dhashy is a ruby gem implementing the difference hash algorithm for perceptual image matching. Apple has not publicly confirmed that they use dhasy for any specific project.
dhashy encodes changes in average brightness along a path of segments of the image in a binary vector. The sum of differences between a pair of such vectors is a measure of the images' difference. Length of the vector is configurable, allowing for any appropriate compromise in a trade-off of runtime and storage space vs. accuracy.
dhashy works extremely well for common whole-image changes, such as changes in contrast, brightness, tone, or color mapping (including conversion to grayscale and b&w). It is entirely oblivious towards re-encoding. Effectiveness against rotation, warping and distortion is somewhat lower but still very good for any change that would, for typical photos, be a noticeable flaw.
dhashy does not work against mirroring. To detect pairs of mirror images, you have to mirror the image yourself and check again.
dhashy is sensitive to cropping. This can be ameliorated for your use case by switching to the longest common substring of the vectors, at the cost of an increased rate of false positives.
dhashy does not work well with illustrative images such as screenshots (including images of text), logos, charts, line drawings, or 🏳️🌈patterns🏁. Because it works within the brightness domain (sum of red + green + blue), all solid-color images resolve to the same vector. while small random variations in photos of solid-colored surfaces will produce results quickly approaching randomness.
dhashy runs in O(n)
with respect to image size (h x l
) to produce the vector. It uses imagemagick for the most involved operation, which is rescaling the image and could easily be adapted to use some alternative library. Comparison against a library of known vector is not included. This is a nearest neighbor problem and you should consult your database's documentation to learn how to failed to find anything better than naive comparison with a quadratic runtime.
Add this line to your application's Gemfile:
gem 'dhashy'
And then execute:
$ bundle
Or install it yourself as:
$ gem install dhashy
first_image = MiniMagick::Image.open("test/test.jpg")
other_image = MiniMagick::Image.open("test/8x8.jpg")
first_hash = Dhashy.new(first_image)
other_hash = Dhashy.new(other_image)
puts first_hash.display
=>
00100100
00010010
00001001
00010100
00010010
00001010
00101101
01010010
puts first_hash - other_hash
=> 0
other_image.draw "circle 50%,50% 25%,25%"
other_hash = Dhashy.new(other_image)
puts other_hash.display
00010100
10011001
10001100
10010100
00010010
00001010
00101100
01110010
puts first_hash - other_hash
=> 12
After checking out the repository, run bin/setup
to install dependencies. Then, run rake test
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/MatthiasWinkelmann/dhashy. Contributors are expected to adhere to the Contributor Covenant code of conduct. While this project with exactly zero community activity probably doesn't need it,it's a good idea in general. Contributors are also bound by our strict no-fascist policy. Not because they are evil, but because they tend to use tabs instead of spaces. (this project uses three-space-indenting, as God intended)
The gem is available as open source under the terms of the MIT License, because there is no HARVARD License.