imatcher 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2ad15eab2eb3ec4656cafb23117199966625e18d
4
- data.tar.gz: 3d15c721ce46ed7cbca79a0d9d4e310972ebcfc2
3
+ metadata.gz: cdc4ac5a873087643b65c5d5b196cb389c64bf96
4
+ data.tar.gz: 2c2641e6e1421b5627731cdcc9e912b289539dc2
5
5
  SHA512:
6
- metadata.gz: b098cf87274c56a0089e795e686d6299ea91339d8bff948486ca25ea5a75e993fb1eb50d533416e2eddd18e035d1dc1330eb055e8a23ddb74e49d54c87f6b406
7
- data.tar.gz: 11c76b5365728cfb495a764e15241d1aea897b8d1cf0642a0dceb870479ce2fc4f3bec87efd1c80ce59b12b8fc28d817cfda79013ec384cba7ed76bf7000635b
6
+ metadata.gz: 347587af896ae12f1647c897c2c8749aecc0546f8d50eb8a143a2d4dc7bd1193f24ca85ee204bf31c2064fd5b290f9b84ba8e7d9ca813a3745e45e9b2f95ffd1
7
+ data.tar.gz: fab3b1e8e9501e5cdb5db0c460a8bc414d4d0189af99c38d585759a49d561bac66124a3b08bc3d876942db5c3956dcf80e9f25316cef8c5a8fd60b546818119f
@@ -0,0 +1,42 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'benchmark/ips'
3
+ require 'imatcher'
4
+
5
+ a = Imatcher::Image.from_file(File.expand_path('../../spec/fixtures/a.png', __FILE__))
6
+ b = Imatcher::Image.from_file(File.expand_path('../../spec/fixtures/a.png', __FILE__))
7
+
8
+ rgb = Imatcher::Matcher.new
9
+ grayscale = Imatcher::Matcher.new mode: :grayscale
10
+ delta = Imatcher::Matcher.new mode: :delta
11
+
12
+ Benchmark.ips do |x|
13
+ x.report 'RGB' do
14
+ rgb.compare(a, b)
15
+ end
16
+
17
+ x.report 'Grayscale' do
18
+ grayscale.compare(a, b)
19
+ end
20
+
21
+ x.report 'Delta E' do
22
+ delta.compare(a, b)
23
+ end
24
+
25
+ x.compare!
26
+ end
27
+
28
+ Benchmark.ips do |x|
29
+ x.report 'RGB' do
30
+ rgb.compare(a, b).difference_image
31
+ end
32
+
33
+ x.report 'Grayscale' do
34
+ grayscale.compare(a, b).difference_image
35
+ end
36
+
37
+ x.report 'Delta E' do
38
+ delta.compare(a, b).difference_image
39
+ end
40
+
41
+ x.compare!
42
+ end
@@ -43,5 +43,9 @@ module Imatcher
43
43
  def render_bounds(left, bot, right, top)
44
44
  rect(left, bot, right, top, rgb(255, 0, 0))
45
45
  end
46
+
47
+ def inspect
48
+ "Image:#{object_id}<#{width}x#{height}>"
49
+ end
46
50
  end
47
51
  end
@@ -18,9 +18,9 @@ module Imatcher
18
18
  @mode = Modes.const_get(MODES[mode_type]).new(options)
19
19
  end
20
20
 
21
- def compare(path_1, path_2)
22
- a = Image.from_file(path_1)
23
- b = Image.from_file(path_2)
21
+ def compare(a, b)
22
+ a = Image.from_file(a) unless a.is_a?(Image)
23
+ b = Image.from_file(b) unless b.is_a?(Image)
24
24
  raise SizesMismatchError,
25
25
  "Size mismatch: first image size: " \
26
26
  "#{a.width}x#{a.height}, " \
@@ -3,7 +3,7 @@ module Imatcher
3
3
  class Base # :nodoc:
4
4
  include ColorMethods
5
5
 
6
- attr_reader :result, :threshold
6
+ attr_reader :result, :threshold, :bounds
7
7
 
8
8
  def initialize(threshold: 0.0)
9
9
  @threshold = threshold
@@ -12,6 +12,7 @@ module Imatcher
12
12
 
13
13
  def compare(a, b)
14
14
  result.image = a
15
+ @bounds = [0, 0, result.image.width - 1, result.image.height - 1]
15
16
 
16
17
  b.compare_each_pixel(a) do |b_pixel, a_pixel, x, y|
17
18
  next if pixels_equal?(b_pixel, a_pixel)
@@ -24,28 +25,25 @@ module Imatcher
24
25
 
25
26
  def diff(bg, diff)
26
27
  diff_image = background(bg)
27
- diff_image.render_bounds(*calculate_bounds(diff))
28
28
  diff.each do |pixels_pair|
29
29
  pixels_diff(diff_image, *pixels_pair)
30
30
  end
31
- create_diff_image(bg, diff_image)
31
+ create_diff_image(bg, diff_image).render_bounds(*bounds)
32
32
  end
33
33
 
34
34
  def score
35
35
  @result.diff.length.to_f / @result.image.pixels.length
36
36
  end
37
37
 
38
- # rubocop:disable Metrics/AbcSize
39
- def calculate_bounds(diff)
40
- xmin, xmax, ymin, ymax = result.image.width, 0, result.image.height, 0
41
- diff.each do |pixels_pair|
42
- xmin = pixels_pair[2] if pixels_pair[2] < xmin
43
- xmax = pixels_pair[2] if pixels_pair[2] > xmax
44
- ymin = pixels_pair[3] if pixels_pair[3] < ymin
45
- ymax = pixels_pair[3] if pixels_pair[3] > ymax
46
- end
38
+ def update_result(*_args, x, y)
39
+ update_bounds(x, y)
40
+ end
47
41
 
48
- [xmin - 1, ymin - 1, xmax + 1, ymax + 1]
42
+ def update_bounds(x, y)
43
+ bounds[0] = [x, bounds[0]].max
44
+ bounds[1] = [y, bounds[1]].max
45
+ bounds[2] = [x, bounds[2]].min
46
+ bounds[3] = [y, bounds[3]].min
49
47
  end
50
48
  end
51
49
  end
@@ -4,10 +4,12 @@ module Imatcher
4
4
 
5
5
  # Compare pixels using Delta E distance.
6
6
  class Delta < Base
7
- def initialize(threshold: 0.0)
8
- @threshold = threshold
9
- @result = Result.new(self, threshold)
7
+ attr_reader :tolerance
8
+
9
+ def initialize(options)
10
+ @tolerance = options.delete(:tolerance) || 0.01
10
11
  @delta_score = 0.0
12
+ super(options)
11
13
  end
12
14
 
13
15
  private
@@ -18,8 +20,10 @@ module Imatcher
18
20
 
19
21
  def update_result(a, b, x, y)
20
22
  d = euclid(a, b) / (MAX * Math.sqrt(3))
23
+ return if d <= tolerance
21
24
  @result.diff << [a, b, x, y, d]
22
25
  @delta_score += d
26
+ super
23
27
  end
24
28
 
25
29
  def background(bg)
@@ -24,6 +24,7 @@ module Imatcher
24
24
  end
25
25
 
26
26
  def update_result(a, b, x, y)
27
+ super
27
28
  @result.diff << [a, b, x, y]
28
29
  end
29
30
 
@@ -10,6 +10,7 @@ module Imatcher
10
10
  end
11
11
 
12
12
  def update_result(a, b, x, y)
13
+ super
13
14
  @result.diff << [a, b, x, y]
14
15
  end
15
16
 
@@ -18,7 +19,7 @@ module Imatcher
18
19
  end
19
20
 
20
21
  def create_diff_image(bg, diff_image)
21
- bg.to_grayscale.compose!(diff_image, 0, 0)
22
+ diff_image
22
23
  end
23
24
 
24
25
  def pixels_diff(d, a, b, x, y)
@@ -1,3 +1,3 @@
1
1
  module Imatcher # :nodoc:
2
- VERSION = "0.1.1".freeze
2
+ VERSION = "0.1.2".freeze
3
3
  end
data/spec/fixtures/a.png CHANGED
Binary file
data/spec/fixtures/b.png CHANGED
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -7,9 +7,9 @@ describe Imatcher::Modes::Delta do
7
7
 
8
8
  let(:options) { { mode: :delta } }
9
9
 
10
- context "with similar images" do
11
- it "score around 0.094" do
12
- expect(subject.score).to be_within(0.0005).of(0.094)
10
+ context "with darker image" do
11
+ it "score around 0.075" do
12
+ expect(subject.score).to be_within(0.005).of(0.075)
13
13
  end
14
14
 
15
15
  context "with custom threshold" do
@@ -32,12 +32,20 @@ describe Imatcher::Modes::Delta do
32
32
  context "with different images" do
33
33
  let(:path_2) { image_path "b" }
34
34
 
35
- it "score around 0.0195" do
36
- expect(subject.score).to be_within(0.0005).of(0.0195)
35
+ it "score around 0.0046" do
36
+ expect(subject.score).to be_within(0.0001).of(0.0046)
37
37
  end
38
38
 
39
39
  it "creates correct difference image" do
40
40
  expect(subject.difference_image).to eq(Imatcher::Image.from_file(image_path("delta_diff")))
41
41
  end
42
+
43
+ context "with high tolerance" do
44
+ let(:options) { { mode: :delta, tolerance: 0.1 } }
45
+
46
+ it "score around 0.0038" do
47
+ expect(subject.score).to be_within(0.0001).of(0.0038)
48
+ end
49
+ end
42
50
  end
43
51
  end
@@ -8,16 +8,16 @@ describe Imatcher::Modes::Grayscale do
8
8
  let(:options) { { mode: :grayscale } }
9
9
 
10
10
  context "darker image" do
11
- it "score around 0.7" do
12
- expect(subject.score).to be_within(0.05).of(0.75)
11
+ it "score around 0.95" do
12
+ expect(subject.score).to be_within(0.05).of(0.95)
13
13
  end
14
14
  end
15
15
 
16
16
  context "different images" do
17
17
  let(:path_2) { image_path "b" }
18
18
 
19
- it "score around 0.02" do
20
- expect(subject.score).to be_within(0.0005).of(0.009)
19
+ it "score around 0.005" do
20
+ expect(subject.score).to be_within(0.001).of(0.005)
21
21
  end
22
22
 
23
23
  it "creates correct difference image" do
@@ -37,8 +37,8 @@ describe Imatcher::Modes::Grayscale do
37
37
  context "different image" do
38
38
  let(:path_2) { image_path "b" }
39
39
 
40
- it "score around 0.97" do
41
- expect(subject.score).to be_within(0.005).of(0.97)
40
+ it "score around 0.016" do
41
+ expect(subject.score).to be_within(0.001).of(0.016)
42
42
  end
43
43
  end
44
44
 
@@ -55,16 +55,16 @@ describe Imatcher::Modes::Grayscale do
55
55
  let(:options) { { mode: :grayscale, tolerance: 8 } }
56
56
 
57
57
  context "darker image" do
58
- it "score around 0.9" do
59
- expect(subject.score).to be_within(0.005).of(0.9)
58
+ it "score around 0.96" do
59
+ expect(subject.score).to be_within(0.005).of(0.96)
60
60
  end
61
61
  end
62
62
 
63
63
  context "different image" do
64
64
  let(:path_2) { image_path "b" }
65
65
 
66
- it "score around 0.027" do
67
- expect(subject.score).to be_within(0.0005).of(0.027)
66
+ it "score around 0.006" do
67
+ expect(subject.score).to be_within(0.0005).of(0.006)
68
68
  end
69
69
  end
70
70
  end
@@ -6,7 +6,7 @@ describe Imatcher::Modes::RGB do
6
6
  subject { Imatcher.compare(path_1, path_2, options) }
7
7
  let(:options) { {} }
8
8
 
9
- context "with similar images" do
9
+ context "with darker" do
10
10
  it "score equals to 1" do
11
11
  expect(subject.score).to eq 1
12
12
  end
@@ -15,8 +15,8 @@ describe Imatcher::Modes::RGB do
15
15
  context "with different images" do
16
16
  let(:path_2) { image_path "b" }
17
17
 
18
- it "score around 0.97" do
19
- expect(subject.score).to be_within(0.005).of(0.97)
18
+ it "score around 0.016" do
19
+ expect(subject.score).to be_within(0.001).of(0.016)
20
20
  end
21
21
 
22
22
  it "creates correct difference image" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: imatcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - palkan
@@ -97,6 +97,7 @@ files:
97
97
  - Rakefile
98
98
  - bin/console
99
99
  - bin/setup
100
+ - examples/performance.rb
100
101
  - imatcher.gemspec
101
102
  - lib/imatcher.rb
102
103
  - lib/imatcher/color_methods.rb