class Dhashy
@author Matthias Winkelmann <m@matthi.coffee> The *difference hash* is a compact representation of an image (i. e. photo) that works well for fuzzy finding of pairs of images that are substantially euqal.
Constants
- VERSION
Attributes
size[R]
Public Class Methods
new(jpg, size=128)
click to toggle source
# File lib/dhashy.rb, line 12 def initialize(jpg, size=128) self.size = size return from_array(jpg) if jpg.is_a? Array jpg = MiniMagick::Image.open(jpg.to_s) if jpg.is_a? Pathname jpg.combine_options do |j| j.resize "#{@dimension + 1}x#{@dimension + 1}!" end @pixels = jpg.get_pixels.map {|row| row.map {|p| ((p[0].to_f * 299) + (p[1] * 587) + (p[2] * 114)).to_f / 1000.0 }} @h = from_array(@pixels) end
Public Instance Methods
-(other)
click to toggle source
(Hamming-) Distance, or visual difference
@param [DHashy] another hash @return [Integer] The Hamming distance (also Manhattan-distance),
i. e. the number of different bits
# File lib/dhashy.rb, line 49 def -(other) [0,1].map { |matrix| (0...@dimension).map {|x| (0...@dimension).map {|y| (@h[matrix][x][y] == other[matrix][x][y]) ? 0 : 1 }.sum}.sum}.sum end
==(other, cutoff=@size / 64)
click to toggle source
Visual Equality
@oaram [DHashy] another hash @param [cutoff] number of bits allowed to differ.
Default: @size / 64 (i. e. 2 bits for default size)
@return [Boolean]
# File lib/dhashy.rb, line 63 def ==(other, cutoff=@size / 64) self - other < 5 end
[](index)
click to toggle source
# File lib/dhashy.rb, line 53 def[](index) @h[index] end
dimension(size)
click to toggle source
Our budget is spent on two square matrices:
one with the differences from row to row the second with differences from column to column
# File lib/dhashy.rb, line 28 def dimension(size) Math.sqrt(size / 2).to_i end
display(values = nil)
click to toggle source
# File lib/dhashy.rb, line 67 def display(values = nil) values = @h unless values [1,0].map do |matrix| (0...@dimension).map do |x| (0...@dimension).map do |y| values[matrix][x][y] ? '*' : '.' end.join(" ") end.join("\n") end.join("\n\n") + "\n" end
matrix()
click to toggle source
return [String] The concatenated row- and
column-wise matrices, compatible to the python implementation
@see github.com/Jetsetter/dhash
# File lib/dhashy.rb, line 82 def matrix [0,1].map do |matrix| (0...@dimension).map do |x| (0...@dimension).map do |y| @h[matrix][x][y] ? '1' : '0' end.join end.join("\n") end.join("\n") end
size=(newsize)
click to toggle source
# File lib/dhashy.rb, line 32 def size=(newsize) fail(ArgumentError, "size must be integer, got %s: %s" % [newsize, newsize.class]) unless newsize.is_a?(Numeric) fail(ArgumentError, "size must be integer, got %s: %s" % [newsize, newsize.class]) unless newsize.integer? fail(ArgumentError, "size must be >= 4") unless newsize >= 4 if self.dimension(newsize) != Math.sqrt(newsize / 2.0) fail(ArgumentError, "sqrt(size / 2) must be integer, is sqrt(%s / 2) / 2 = %s" % [newsize, self.dimension(newsize)]) end @size = newsize @dimension = self.dimension(@size) end
to_i()
click to toggle source
return [Integer] The integer of bit length
<size> representing the hash
# File lib/dhashy.rb, line 104 def to_i [0,1].map do |matrix| (0...@dimension).map do |x| (0...@dimension).map do |y| @h[x][y] * 2**(x*y) end end end .sum end
to_s()
click to toggle source
# File lib/dhashy.rb, line 92 def to_s [0,1].map do |matrix| (0...@dimension).map do |x| (0...@dimension).map do |y| @h[matrix][x][y] ? 1 : 0 end.join end.join end.join end
Private Instance Methods
from_array(gray)
click to toggle source
# File lib/dhashy.rb, line 116 def from_array(gray) [:rows, :cols].map do |direction| (0...@dimension).map do |y| (0...@dimension).map do |x| if direction == :rows gray[x][y] <= gray[x+1][y] else gray[x][y] <= gray[x][y+1] end end end end end