平均哈希算法
實現步驟
1.縮小尺寸:將圖像縮小到8*8的尺寸,總共64個像素(去除圖像細節,只保留結構和明暗結構等基本信息)
2.簡化色彩:將縮小的圖像轉換為64灰度。(所有像素點只有64種顏色)
3.計算平均值:計算64個像素的灰度平均值。
4.比較灰度:將64個像素的灰度值和平均值進行比較,大於等於記為1,小於記為0.
5.計算哈希值:將上一步的比較結果,組合在一起,就構成了一個64位的整數,這就是這張圖像的指紋。組合的次序並不重要,只要保證所有圖像都采用同樣次序就行了;
6.得到指紋以后,就可以對比不同的圖像,看看64位中有多少位是不一樣的。在理論上,這等同於”漢明距離”(Hamming distance,在信息論中,
兩個等長字符串之間的漢明距離是兩個字符串對應位置的不同字符的個數)。如果不相同的數據位數不超過5,就說明兩張圖像很相似;如果大於10,就說明這是兩張不同的圖像。
//平均哈希算法 unsafe public int aHash(Mat matSrc1, Mat matSrc2) { //Mat matSrc1 = new Mat(imagesrc); //Mat matSrc2 = new Mat(imagesrc2); Mat matDst1 = new Mat(); Mat matDst2 = new Mat(); Cv2.Resize(matSrc1, matDst1, new OpenCvSharp.Size(32, 32), 0, 0, InterpolationFlags.Linear); Cv2.Resize(matSrc2, matDst2, new OpenCvSharp.Size(32, 32), 0, 0, InterpolationFlags.Linear); Cv2.CvtColor(matDst1, matDst1, ColorConversionCodes.BGR2GRAY); Cv2.CvtColor(matDst2, matDst2, ColorConversionCodes.BGR2GRAY); ////顯示圖片 //Cv2.ImShow("aa", matDst1); //Cv2.ImShow("bb", matDst2); int iAvg1 = 0; int iAvg2 = 0; int[] arr1 = new int[1024]; int[] arr2 = new int[1024]; for (int i = 0; i < 32; i++) { byte* data1 = (byte*)matDst1.Ptr(i); byte* data2 = (byte*)matDst2.Ptr(i); int tmp = i * 8; for (int j = 0; j < 32; j++) { int tmp1 = tmp + j; arr1[tmp1] = data1[j] / 4 * 4; arr2[tmp1] = data2[j] / 4 * 4; iAvg1 += arr1[tmp1]; iAvg2 += arr2[tmp1]; } } iAvg1 /= 1024; iAvg2 /= 1024; for (int i = 0; i < 1024; i++) { arr1[i] = (arr1[i] >= iAvg1) ? 1 : 0; arr2[i] = (arr2[i] >= iAvg2) ? 1 : 0; } int iDiffNum = 0; for (int i = 0; i < 1024; i++) { if (arr1[i] != arr2[i]) iDiffNum++; } return iDiffNum; }
感知哈希算法
平均哈希算法過於嚴格,不夠精確,更適合搜索縮略圖,為了獲得更精確的結果可以選擇感知哈希算法,它采用的是DCT(離散余弦變換)來降低頻率的方法
一般步驟
- 縮小圖片:32 * 32是一個較好的大小,這樣方便DCT計算
- 轉化為灰度圖
- 計算DCT:利用Opencv中提供的dct()方法,注意輸入的圖像必須是32位浮點型
- 縮小DCT:DCT計算后的矩陣是32 * 32,保留左上角的8 * 8,這些代表的圖片的最低頻率
- 計算平均值:計算縮小DCT后的所有像素點的平均值
- 大於平均值記錄為1,反之記錄為0
- 得到信息指紋
//感知哈希算法 unsafe public int phash(Mat matSrc1, Mat matSrc2) { //Mat matSrc1 = new Mat(imagesrc); //Mat matSrc2 = new Mat(imagesrc2); Mat matDst1 = new Mat(); Mat matDst2 = new Mat(); Cv2.Resize(matSrc1, matDst1, new OpenCvSharp.Size(32, 32), 0, 0, InterpolationFlags.Cubic); Cv2.Resize(matSrc2, matDst2, new OpenCvSharp.Size(32, 32), 0, 0, InterpolationFlags.Cubic); Cv2.CvtColor(matDst1, matDst1, ColorConversionCodes.BGR2GRAY); Cv2.CvtColor(matDst2, matDst2, ColorConversionCodes.BGR2GRAY); matDst1.ConvertTo(matDst1, MatType.CV_32F); matDst2.ConvertTo(matDst2, MatType.CV_32F); Cv2.Dct(matDst1, matDst1); Cv2.Dct(matDst2, matDst2); int iAvg1 = 0; int iAvg2 = 0; int[] arr1 = new int[1024]; int[] arr2 = new int[1024]; for (int i = 0; i < 32; i++) { byte* data1 = (byte*)matDst1.Ptr(i); byte* data2 = (byte*)matDst2.Ptr(i); int tmp = i * 32; for (int j = 0; j < 32; j++) { int tmp1 = tmp + j; arr1[tmp1] = data1[j]; arr2[tmp1] = data2[j]; iAvg1 += arr1[tmp1]; iAvg2 += arr2[tmp1]; } } iAvg1 /= 1024; iAvg2 /= 1024; for (int i = 0; i < 1024; i++) { arr1[i] = (arr1[i] >= iAvg1) ? 1 : 0; arr2[i] = (arr2[i] >= iAvg2) ? 1 : 0; } int iDiffNum = 0; for (int i = 0; i < 1024; i++) { if (arr1[i] != arr2[i]) iDiffNum++; } return iDiffNum; }
色差均值哈希算法
一般步驟
- 縮小圖片:32 * 32是一個較好的大小,這樣方便DCT計算
- 計算DCT:利用Opencv中提供的dct()方法,注意輸入的圖像必須是32位浮點型
- 縮小DCT:DCT計算后的矩陣是32 * 32,保留左上角的8 * 8,這些代表的圖片的最低頻率
- 計算平均值:計算縮小DCT后兩張對比圖片的所有像素點只差的絕對值
unsafe public int aHashs(Mat matSrc1, Mat matSrc2) { //Mat matSrc1 = new Mat(imagesrc); //Mat matSrc2 = new Mat(imagesrc2); Mat matDst1 = new Mat(); Mat matDst2 = new Mat(); Cv2.Resize(matSrc1, matDst1, new OpenCvSharp.Size(32, 32), 0, 0, InterpolationFlags.Linear); Cv2.Resize(matSrc2, matDst2, new OpenCvSharp.Size(32, 32), 0, 0, InterpolationFlags.Linear); Cv2.CvtColor(matDst1, matDst1, ColorConversionCodes.BGR2GRAY); Cv2.CvtColor(matDst2, matDst2, ColorConversionCodes.BGR2GRAY); ////顯示圖片 //Cv2.ImShow("aa", matDst1); //Cv2.ImShow("bb", matDst2); int iAvg = 0; int[] arr1 = new int[1024]; int[] arr2 = new int[1024]; for (int i = 0; i < 32; i++) { byte* data1 = (byte*)matDst1.Ptr(i); byte* data2 = (byte*)matDst2.Ptr(i); int tmp = i * 32; for (int j = 0; j < 32; j++) { int tmp1 = tmp + j; arr1[tmp1] = data1[j]; arr2[tmp1] = data2[j]; iAvg += System.Math.Abs(arr1[tmp1] - arr2[tmp1]); } } iAvg /= 1024; return iAvg; }