Home

Awesome

priHash

C# Implementation of pHash (http://phash.org). Based on phash-0.9.4 for Windows.

NuGet packages

The Shipwreck.Phash accepts only IByteImage interface. The package does not contain any method to load an image. So additional packages provide extension methods to instantiate ByteImage

There are some more packages for uncommon usage.

Compatibility Notice

Following methods contains breaking changes at versions below. Hashes computed by older versions cannot be compared with the new one:

Hashing an image (Bitmap)

var bitmap = (Bitmap)Image.FromFile(fullPathToImage);
var hash = ImagePhash.ComputeDigest(bitmap.ToLuminanceImage());

Hashing an image (BitmapSource)

var bitmapSource = BitmapFrame.Create(stream);
var hash = ImagePhash.ComputeDigest(bitmapSource.ToLuminanceImage());

Image similarity score

var score = ImagePhash.GetCrossCorrelation(hash1, hash2);

Multithreaded hashing of all images in a folder

Example below required .NET 4.7+ since the function returns a tuple of results.

public static (ConcurrentDictionary<string, Digest> filePathsToHashes, ConcurrentDictionary<Digest, HashSet<string>> hashesToFiles) GetHashes(string dirPath, string searchPattern)
{
    var filePathsToHashes = new ConcurrentDictionary<string, Digest>();
    var hashesToFiles = new ConcurrentDictionary<Digest, HashSet<string>>();

    var files = Directory.GetFiles(dirPath, searchPattern);

    Parallel.ForEach(files, (currentFile) =>
    {
        var bitmap = (Bitmap)Image.FromFile(currentFile);
        var hash = ImagePhash.ComputeDigest(bitmap);
        filePathsToHashes[currentFile] = hash;

        HashSet<string> currentFilesForHash;

        lock (hashesToFiles)
        {
            if (!hashesToFiles.TryGetValue(hash, out currentFilesForHash))
            {
                currentFilesForHash = new HashSet<string>();
                hashesToFiles[hash] = currentFilesForHash;
            }
        }

        lock (currentFilesForHash)
        {
            currentFilesForHash.Add(currentFile);
        }
    });

    return (filePathsToHashes, hashesToFiles);
}

Then you can call it like this:

(ConcurrentDictionary<string, Digest> gilePathsToHashes, ConcurrentDictionary<Digest, HashSet<string>> hashesToFiles) =
    GetHashes(
        dirPath: @"C:\some\path\",
        searchPattern: "*.jpg");

TestApp

Download Image sets from http://phash.org/download/ and extract into the /data/compr, /data/blur, /data/rotd, /data/misc directories. Or you can create test Image sets by yourself.

License

GNU General Public License version 3 or later http://www.gnu.org/licenses/