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 +4 -4
- data/Rakefile +40 -1
- data/{dhash.gemspec → dhash-vips.gemspec} +1 -1
- data/lib/dhash-vips.rb +60 -16
- data/lib/dhash-vips/version.rb +2 -2
- data/spec/_spec.rb +46 -21
- metadata +3 -6
- data/spec/images/face-high.jpg +0 -0
- data/spec/images/face-low.jpg +0 -0
- data/spec/images/face-with-nose.jpg +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07665dfb99e7720dd2406286235a1a6623576830
|
4
|
+
data.tar.gz: 6ecf29f185c958959d556b3ceb12b1da15db69e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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";
|
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"
|
data/lib/dhash-vips.rb
CHANGED
@@ -1,29 +1,73 @@
|
|
1
1
|
require_relative "dhash-vips/version"
|
2
2
|
require "vips"
|
3
3
|
|
4
|
-
module
|
5
|
-
|
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
|
-
|
12
|
-
|
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
|
-
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
data/lib/dhash-vips/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module
|
2
|
-
VERSION = "0.0.0
|
1
|
+
module DHashVips
|
2
|
+
VERSION = "0.0.1.0"
|
3
3
|
end
|
data/spec/_spec.rb
CHANGED
@@ -1,8 +1,25 @@
|
|
1
1
|
require "dhash-vips"
|
2
2
|
|
3
|
-
|
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 =
|
23
|
-
images.
|
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 &
|
37
|
-
table = MLL::table[
|
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
|
-
#
|
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
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
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-
|
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
|
data/spec/images/face-high.jpg
DELETED
Binary file
|
data/spec/images/face-low.jpg
DELETED
Binary file
|
Binary file
|