dhash-vips 0.0.0.2 → 0.0.1.0

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: 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