Package: imagesearch
imagesearchimagesearchperforms visual comparison operations on images.Thecomparecommand measures visual similiarity between a reference image and a set of other
images. This can be used to search for a similar image that you know among a deep directory
structure of images that you don't want to manually scan.Thedupecommand finds images which have identical visual fingerprints in a search path. This
can be used to identify images which you can delete later.Installationpip install imagesearchSeeimagesearch on PyPI.ExamplesGet help:> imagesearch --help
  ...Commandsimagesearchfunctionality is broken up into subcommands provided on the command line.While the subcommands may have unique arguments, others are common among them:Algorithm selection, which specifies which fingerprint algorithm to use. For help in choosing, see
the section below. For example, to use "average hashing", specify--ahash.If no algorithm is
specified,--dhashis implied.These algorithms can take in additional parameters to tune their performance. See the help
output for what these parameters are. They should be given in a comma-separated list, joining
each parameter name to its value with an equals sign. For example:> imagesearch dupe images/ --whash --algo-params hash_size=8,mode=db4
> imagesearch dupe --help  # for more info and value constraints-f/-formatspecifies the output format of results. This can be eithertextorjson(the
default).jsonshould be used when the results are to be read by another program because
eccentricities in filenames will be properly encoded.(All examples below usetextfor
clarity.)searchCommandA0value indicates the highest level of similarity, or possibly a true match.Compare a reference image to all images in a search path:> imagesearch search needle.jpg haystack\ --format text
  28      haystack\0.jpg
  38      haystack\1.jpg
  12      haystack\2.jpg
  18      haystack\3.jpg
  32      haystack\4.jpg
  29      haystack\5.jpg
  0       haystack\6.jpg
  29      haystack\7.jpg
  5       haystack\8.jpg
  28      haystack\9.jpgIn this example,haystack\6.jpgis most similar.Compare against a single image:> imagesearch search needle.jpg haystack\1.jpg --format text
  38       haystack\1.jpgOnly return images with similarity less than or equal to 10:> imagesearch search needle.jpg haystack\ --threshold 10 --format text
  0       haystack\6.jpg
  5       haystack\8.jpgReturn the first image found under the threshold (0, in this case) and stop searching immediately:> imagesearch search needle.jpg haystack\ -t 0 --stop-on-first-match --format text
  0       haystack\6.jpgSpecify a different algorithm:> imagesearch search needle.jpg haystack\ --colorhash --format text
  ...Get more help:> imagesearch search --help
  ...dupeCommandFind all visually similar images in a search path:> imagesearch dupe images\ --format text
  fff7db9f03030203
          images\file-123.jpg
          images\deep\subdir\foo.jpeg
  fcf8f0fae2c6c400
          images\a\file-987.jpg
          images\subdir\bar.pngEach set of paths that are similar is prefixed with its hash.Get more help:> imagesearch dupe --help
  ...Visual SimiliarityAt its core,imagesearchcreates image fingerprints and compares them to other fingerprints. A
critical feature of these fingerprints is that they can be numerically compared.Images that are
different will have large differences in their fingerprints, and vice versa.Unless you have a good understanding of the algorihms used, values should be treated as opaque and
subjective. It is dependent on the algorithm used to create the fingerprints and your criteria for
what "similar" is.This project uses theimagehashlibrary to produce these fingerprints, and
more information about the techniques can be found there.AlgorithmsAll the fingerprinting algorithms inimagesearchcome fromimagehash. Inimagesearch, you may specify which
algorithm to use by giving an argument in one of the following forms:--ahash: Average hashing (aHash)--phash: 2-axis perceptual hashing (pHash)--phash-simple: 1-axis perceptual hashing (pHash)--dhash: Horizontal difference hashing (dHash)--dhash-vert: Vertical difference hashing (dHash)--whash: Wavelet hashing (wHash), can specify either Haar (mode=haar) or Daubechies
(mode=db4)--colorhash: HSV color hashing (colorhash)CollisionsThese algorithms trade away accuracy for speed and size, usually with acceptable results. Instead of
producing an artifact that exactly identifies an image, there's analysis done on some more abstract
quality of the image, such as it's luminance orsignal frequency. This allows us
to:do less processingget a fingerprint with a small sizeget a fingerprint that exists in a linear space for comparisonHowever, because the exact image analysis is abstract and produces a fixed-size fingerprint, it's
absolutely possible for 2 different images to have the same fingerprint.This is sort of an analog to cryptographic hash collosions, so it's important to understand what
kinds of scenarios may cause this!Seethis section of the imagehash documentationfor examples of different images that
produce the same fingerprint. The source code of that project also references other pages that
explain the workings of the algorithm.TuningIf you notice collisions for images you expect to hash differently, try changing the algorithm
parameters. One easy way to do this is to increase the hash size, done for example by:imagesearch dupe images/ --dhash --algo-params hash_size=16See the subcommand help for more details and any constraints that may be on the value.ContributingFeatures TODOwhitelist file paths by extension (currently tries to open every file in the path, which
hurts for directories with other big files in them. Not sure ifPIL.Image.openis smart enough
to failfast on unknown data.) Something like--ext .jpg --ext .png --ext .jpeg.set whitelist of popular extensions with something like--only-popular-extensions.asyncio for reading? look ataiofileproject and Image.open(BytesIO(...data...)). Would this
even help though? Is there harddisk read parallelism to leverage?algorithm parameter parsing uses it's own little sublanguage (comma-separated key=value pairs).
This could be a first-order argparse task instead. Would have to inspect eachAlgorithmand
auto-generate acceptable arguments.argparse.ArgumentParserhas a niceparse_known_argsmethod that could chomp away at non-algorithm-specific arguments first, and then parse
algorithm-specific ones once the algorithm is known. How would we generate help text for this
though?Bug Fixes/FeaturesSubmit a PR from an appropriately named feature branch off of master.ReleasingBump the version withpoetry run bumpversion [patch|minor|major]. This will update the version
number around the project, commit and tag it.Push the repo. A Github release will be made and published to PyPI.