dhash-vips 0.0.0.2 → 0.0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 91c7be59e88216898e8a6dfa9cb3eeccf88cd9d6
4
- data.tar.gz: 76e55f4d301b274ee37a95c236ebe7d884164490
3
+ metadata.gz: 07665dfb99e7720dd2406286235a1a6623576830
4
+ data.tar.gz: 6ecf29f185c958959d556b3ceb12b1da15db69e4
5
5
  SHA512:
6
- metadata.gz: 9d6d563744fe3b72502b5827ef072af1b816866e30374b1ff18e312157cc646776c352560e4c3c7ec52b436d5833f3731455d5429b9d0051d0491943b718f860
7
- data.tar.gz: 92054de250d05c1a93ffb178c85ccc8ac2132e110869789d2097fe8c8f03c1f4f0c280a1b3b941fa72e10f333d7adac389d10b96deb967387cd0501e01d69fff
6
+ metadata.gz: b48e8ad679501b2ea2b6c7d7e579f9ff7a1c1bd04c7a2f2d12e6b2f249d0ce96cabe959767b28146a96c9cb1cb3e71f187199a9250485dd1ec645495860a0206
7
+ data.tar.gz: 6e3b6b9cca29187047f34a12543862494cfb557a009efa83fd8fac0592a76c446e425d03163a2ab1e9eb6f9a00bd500961181964b541b77f197b3d1c20c59eb2
data/Rakefile CHANGED
@@ -1,8 +1,47 @@
1
+ STDOUT.sync = true
2
+
1
3
  require "bundler/gem_tasks"
2
4
 
3
5
  task :default => %w{ spec }
4
6
 
5
7
  require "rspec/core/rake_task"
6
- RSpec::Core::RakeTask.new(:spec) do |t|
8
+ RSpec::Core::RakeTask.new :spec do |t|
7
9
  t.verbose = false
8
10
  end
11
+
12
+ visualize_hash = lambda do |hash|
13
+ puts hash.to_s(2).rjust(64, ?0).gsub(/(?<=.)/, '\0 ').scan(/.{16}/)
14
+ end
15
+
16
+ task :compare_pixelation do |_, args|
17
+ require_relative "lib/dhash-vips"
18
+ require "dhash"
19
+
20
+ ARGV.drop(1).each do |arg|
21
+ FileUtils.mkdir_p "compare_pixelation/#{File.dirname arg}"
22
+
23
+ puts filename = "compare_pixelation/#{arg}.dhash-vips.png"
24
+ DHashVips::DHash.pixelate(arg, 8).
25
+ colourspace(:srgb). # otherwise we may get `Vips::Error` `RGB color space not permitted on grayscale PNG` when the image was already bw
26
+ write_to_file filename
27
+ visualize_hash.call DHashVips::DHash.calculate arg
28
+
29
+ puts filename = "compare_pixelation/#{arg}.dhash.png"
30
+ Magick::Image.read(arg).first.quantize(256, Magick::Rec601LumaColorspace, Magick::NoDitherMethod, 8).resize!(9, 8).
31
+ write filename
32
+ visualize_hash.call Dhash.calculate arg
33
+ end
34
+ end
35
+
36
+ task :compare_kernels do |_, args|
37
+ require_relative "lib/dhash-vips"
38
+ require "dhash"
39
+
40
+ %i{ nearest linear cubic lanczos2 lanczos3 }.each do |kernel|
41
+ hashes = ARGV.drop(1).map do |arg|
42
+ puts arg
43
+ DHashVips::DHash.calculate(arg, 8, kernel).tap &visualize_hash
44
+ end
45
+ puts "kernel: #{kernel}, distance: #{DHashVips::DHash.hamming *hashes}"
46
+ end
47
+ end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "dhash-vips"
3
- spec.version = (require_relative "lib/dhash-vips/version"; DhashVips::VERSION)
3
+ spec.version = (require_relative "lib/dhash-vips/version"; DHashVips::VERSION)
4
4
  spec.author = "Victor Maslov"
5
5
  spec.email = "nakilon@gmail.com"
6
6
  spec.summary = "dHash powered by Vips"
@@ -1,29 +1,73 @@
1
1
  require_relative "dhash-vips/version"
2
2
  require "vips"
3
3
 
4
- module DhashVips
5
- extend self
4
+ module DHashVips
5
+ module DHash
6
+
7
+ extend self
8
+
9
+ def hamming a, b
10
+ (a ^ b).to_s(2).count "1"
11
+ end
12
+
13
+ def pixelate file, hash_size, kernel = nil
14
+ image = Vips::Image.new_from_file file
15
+ if kernel
16
+ image.resize((hash_size + 1).fdiv(image.width), vscale: hash_size.fdiv(image.height), kernel: kernel).colourspace("b-w")
17
+ else
18
+ image.resize((hash_size + 1).fdiv(image.width), vscale: hash_size.fdiv(image.height) ).colourspace("b-w")
19
+ end
20
+ end
21
+
22
+ def calculate file, hash_size = 8, kernel = nil
23
+ image = pixelate file, hash_size, kernel
24
+
25
+ image.cast("int").conv([1, -1]).crop(1, 0, 8, 8).>(0)./(255).cast("uchar").to_a.join.to_i(2)
26
+ end
6
27
 
7
- def hamming a, b
8
- (a ^ b).to_s(2).count "1"
9
28
  end
10
29
 
11
- def calculate file, hash_size = 8
12
- image = Vips::Image.new_from_file file
13
- image = image.resize((hash_size + 1).fdiv(image.width), vscale: hash_size.fdiv(image.height)).colourspace "b-w"
30
+ module IDHash
31
+ extend self
14
32
 
15
- difference = 0
33
+ def hamming a, b
34
+ ad = a >> 64
35
+ ai = a - (ad << 64)
36
+ bd = b >> 64
37
+ bi = b - (bd << 64)
38
+ ((ai | bi) & (ad ^ bd)).to_s(2).count "1"
39
+ end
16
40
 
17
- hash_size.times do |row|
18
- hash_size.times do |col|
19
- pixel_left = image.getpoint(col, row).first
20
- pixel_right = image.getpoint(col + 1, row).first
21
- difference <<= 1
22
- difference += 1 if pixel_left > pixel_right
23
- end
41
+ def median array
42
+ h = array.size / 2
43
+ return array[h] if array[h] != array[h - 1]
44
+ right = array.dup
45
+ left = right.shift h
46
+ right.shift if right.size > left.size
47
+ return right.first if left.last != right.first
48
+ return right.uniq[1] if left.count(left.last) > right.count(right.first)
49
+ left.last
50
+ end
51
+ fail unless 2 == median([1, 2, 2, 2, 2, 2, 3])
52
+ fail unless 3 == median([1, 2, 2, 2, 2, 3, 3])
53
+ fail unless 3 == median([1, 1, 2, 2, 3, 3, 3])
54
+ fail unless 2 == median([1, 1, 1, 2, 3, 3, 3])
55
+ fail unless 2 == median([1, 1, 2, 2, 2, 2, 3])
56
+ fail unless 2 == median([1, 2, 2, 2, 2, 3])
57
+ fail unless 3 == median([1, 2, 2, 3, 3, 3])
58
+ fail unless 1 == median([1, 1, 1])
59
+ fail unless 1 == median([1, 1])
60
+
61
+ def calculate file, hash_size = 8
62
+ image = Vips::Image.new_from_file file
63
+ image = image.resize((hash_size + 1).fdiv(image.width), vscale: hash_size.fdiv(image.height)).colourspace("b-w")
64
+
65
+ conv = image.cast("int").conv([1, -1]).crop(1, 0, 8, 8)
66
+ d = conv.>(0)./(255).cast("uchar").to_a.join.to_i(2)
67
+ i = conv.abs.>=(median conv.abs.to_a.flatten.sort)./(255).cast("uchar").to_a.join.to_i(2)
68
+ (d << 64) + i
24
69
  end
25
70
 
26
- difference
27
71
  end
28
72
 
29
73
  end
@@ -1,3 +1,3 @@
1
- module DhashVips
2
- VERSION = "0.0.0.2"
1
+ module DHashVips
2
+ VERSION = "0.0.1.0"
3
3
  end
@@ -1,8 +1,25 @@
1
1
  require "dhash-vips"
2
2
 
3
- describe DhashVips do
3
+ [
4
+ [DHashVips::DHash, 18, 22],
5
+ # [[0, 17, 29, 27, 22, 29],
6
+ # [17, 0, 30, 26, 33, 36],
7
+ # [29, 30, 0, 18, 39, 30],
8
+ # [27, 26, 18, 0, 35, 30],
9
+ # [22, 33, 39, 35, 0, 17],
10
+ # [29, 36, 30, 30, 17, 0]]
11
+ [DHashVips::IDHash, 10, 15],
12
+ # [[0, 5, 21, 23, 18, 23],
13
+ # [5, 0, 15, 16, 17, 28],
14
+ # [21, 15, 0, 10, 31, 25],
15
+ # [23, 16, 10, 0, 26, 28],
16
+ # [18, 17, 31, 26, 0, 8],
17
+ # [23, 28, 25, 28, 8, 0]]
18
+ ].each do |lib, max_similar, min_not_similar|
19
+
20
+ describe lib do
4
21
 
5
- require "tmpdir"
22
+ # require "tmpdir"
6
23
  require "fileutils"
7
24
  require "open-uri"
8
25
  require "digest"
@@ -17,10 +34,14 @@ describe DhashVips do
17
34
  df0a3b93e9412536ee8a11255f974141.jpg
18
35
  679634ff89a31279a39f03e278bc9a01.jpg
19
36
  } # these images a consecutive pairs of slightly (but enough for nice asserts) silimar images
37
+ bw1, bw2 = %w{
38
+ 71662d4d4029a3b41d47d5baf681ab9a.jpg
39
+ ad8a37f872956666c3077a3e9e737984.jpg
40
+ } # these is the same photo but of different size and bw
20
41
 
21
42
  example.metadata[:extra_failure_lines] = []
22
- FileUtils.mkdir_p dir = Dir.tmpdir + "/dhash-vips-spec"
23
- images.each do |image|
43
+ FileUtils.mkdir_p dir = "images"
44
+ *images, bw1, bw2 = [*images, bw1, bw2].map do |image|
24
45
  "#{dir}/#{image}".tap do |filename|
25
46
  unless File.exist?(filename) && Digest::MD5.file(filename) == File.basename(filename, ".jpg")
26
47
  example.metadata[:extra_failure_lines] << "copying image from web to #{filename}"
@@ -33,28 +54,32 @@ describe DhashVips do
33
54
  end
34
55
  end
35
56
 
36
- hashes = images.map &DhashVips.method(:calculate)
37
- table = MLL::table[DhashVips.method(:hamming), [hashes], [hashes]]
57
+ hashes = images.map &described_class.method(:calculate)
58
+ table = MLL::table[described_class.method(:hamming), [hashes], [hashes]]
59
+
38
60
  # require "pp"
39
61
  # pp table
40
- # [[0, 17, 29, 27, 22, 29],
41
- # [17, 0, 30, 26, 33, 36],
42
- # [29, 30, 0, 18, 39, 30],
43
- # [27, 26, 18, 0, 35, 30],
44
- # [22, 33, 39, 35, 0, 17],
45
- # [29, 36, 30, 30, 17, 0]]
62
+ # abort
46
63
 
47
- hashes.size.times.to_a.combination(2) do |i, j|
48
- case
49
- when i == j
50
- expect(table[i][j]).to eq 0
51
- when (j - i).abs == 1 && (i + j - 1) % 4 == 0
52
- expect(table[i][j]).to be > 0
53
- expect(table[i][j]).to be < 19
54
- else
55
- expect(table[i][j]).to be > 21
64
+ aggregate_failures do
65
+ hashes.size.times.to_a.repeated_combination(2) do |i, j|
66
+ case
67
+ when i == j
68
+ expect(table[i][j]).to eq 0
69
+ when (j - i).abs == 1 && (i + j - 1) % 4 == 0
70
+ expect(table[i][j]).to be > 0
71
+ expect(table[i][j]).to be <= max_similar
72
+ else
73
+ expect(table[i][j]).to be >= min_not_similar
74
+ end
56
75
  end
76
+
77
+ hashes = [bw1, bw2].map &described_class.method(:calculate)
78
+ expect(described_class.hamming(*hashes)).to eq 0
57
79
  end
80
+
58
81
  end
59
82
 
60
83
  end
84
+
85
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dhash-vips
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0.2
4
+ version: 0.0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Maslov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-21 00:00:00.000000000 Z
11
+ date: 2017-09-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: vips
@@ -91,13 +91,10 @@ files:
91
91
  - LICENSE.txt
92
92
  - README.md
93
93
  - Rakefile
94
- - dhash.gemspec
94
+ - dhash-vips.gemspec
95
95
  - lib/dhash-vips.rb
96
96
  - lib/dhash-vips/version.rb
97
97
  - spec/_spec.rb
98
- - spec/images/face-high.jpg
99
- - spec/images/face-low.jpg
100
- - spec/images/face-with-nose.jpg
101
98
  homepage: https://github.com/nakilon/dhash-vips
102
99
  licenses:
103
100
  - MIT
Binary file
Binary file