參考:
https://github.com/maccman/dhash
http://blog.iconfinder.com/detecting-duplicate-images-using-python/ 講的很詳細
http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html 各種圖片相似性算法比較
namespace PictureSimilarity { public class ImageDHash { /// <summary> /// 獲取圖片的D-hash值 /// </summary> /// <param name="image"></param> /// <returns></returns> public static ulong GetHash(Image image) { int hashSize = 8; //圖片縮小到9*8的尺寸 var thumbImage = Resize(image, hashSize + 1, hashSize); //獲取灰度圖片,灰度圖片即把rgb轉換成0~255的值 var grayImage = GetGrayScaleVersion(thumbImage); ulong hash = 0; //遍歷9*8像素點,記錄相鄰像素之間的對邊關系,產生8*8=64個對比關系,對應ulong的64位 for (int x = 0; x < hashSize; x++) { for (int y = 0; y < hashSize; y++) { //比較當前像素點與下一個像素點的對比關系,如果當前像素點值較大則為1,否則為0 var largerThanNext = Math.Abs(grayImage.GetPixel(y, x).R) > Math.Abs(grayImage.GetPixel(y + 1, x).R); if (largerThanNext) { var currentIndex = x * hashSize + y; hash |= (1UL << currentIndex); } } } return hash; } /// <summary> /// 計算兩個hash值之間的漢明距離 /// </summary> /// <param name="hash1"></param> /// <param name="hash2"></param> /// <returns></returns> public static double GetSimilarity(ulong hash1, ulong hash2) { return (64 - BitCount(hash1 ^ hash2)) / 64.0; } /// <summary> /// Bitcounts array used for BitCount method (used in Similarity comparisons). /// Don't try to read this or understand it, I certainly don't. Credit goes to /// David Oftedal of the University of Oslo, Norway for this. /// http://folk.uio.no/davidjo/computing.php /// </summary> private static byte[] bitCounts = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,1,2,2,3,2,3,3,4, 2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6, 4,5,5,6,5,6,6,7,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,2,3,3,4,3,4,4,5, 3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 }; /// <summary> /// 計算ulong中位值為1的個數 /// </summary> /// <param name="num"></param> /// <returns></returns> private static uint BitCount(ulong num) { uint count = 0; for (; num > 0; num >>= 8) count += bitCounts[(num & 0xff)]; return count; } /// <summary> /// 修改圖片尺寸 /// </summary> /// <param name="originalImage"></param> /// <param name="newWidth"></param> /// <param name="newHeight"></param> /// <returns></returns> public static Image Resize(Image originalImage, int newWidth, int newHeight) { Image smallVersion = new Bitmap(newWidth, newHeight); using (Graphics g = Graphics.FromImage(smallVersion)) { g.SmoothingMode = SmoothingMode.HighQuality; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.PixelOffsetMode = PixelOffsetMode.HighQuality; g.DrawImage(originalImage, 0, 0, newWidth, newHeight); } return smallVersion; } private static ColorMatrix ColorMatrix = new ColorMatrix( new float[][] { new float[] {.3f, .3f, .3f, 0, 0}, new float[] {.59f, .59f, .59f, 0, 0}, new float[] {.11f, .11f, .11f, 0, 0}, new float[] {0, 0, 0, 1, 0}, new float[] {0, 0, 0, 0, 1} }); /// <summary> /// 獲取灰度圖片 /// </summary> /// <param name="original"></param> /// <returns></returns> public static Bitmap GetGrayScaleVersion(Image original) { //http://www.switchonthecode.com/tutorials/csharp-tutorial-convert-a-color-image-to-grayscale //create a blank bitmap the same size as original Bitmap newBitmap = new Bitmap(original.Width, original.Height); //get a graphics object from the new image using (Graphics g = Graphics.FromImage(newBitmap)) { //create some image attributes ImageAttributes attributes = new ImageAttributes(); //set the color matrix attribute attributes.SetColorMatrix(ColorMatrix); //draw the original image on the new image //using the grayscale color matrix g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height), 0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes); } return newBitmap; } } }