C# OpenCVsharp圖片相識度
阿新 • • 發佈:2022-03-30
平均雜湊演算法
實現步驟
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[64]; int[] arr2 = new int[64]; for (int i = 0; i < 8; i++) { byte* data1 = (byte*)matDst1.Ptr(i); byte* data2 = (byte*)matDst2.Ptr(i); int tmp = i * 8; for (int j = 0; j < 8; j++) { int tmp1 = tmp + j; arr1[tmp1] = data1[j] / 4 * 4; arr2[tmp1] = data2[j] / 4 * 4; iAvg1 += arr1[tmp1]; iAvg2 += arr2[tmp1]; } } iAvg1 /= 64; iAvg2 /= 64; for (int i = 0; i < 64; i++) { arr1[i] = (arr1[i] >= iAvg1) ? 1 : 0; arr2[i] = (arr2[i] >= iAvg2) ? 1 : 0; } int iDiffNum = 0; for (int i = 0; i < 64; 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[64]; int[] arr2 = new int[64]; for (int i = 0; i < 8; i++) { byte* data1 = (byte*)matDst1.Ptr(i); byte* data2 = (byte*)matDst2.Ptr(i); int tmp = i * 8; for (int j = 0; j < 8; j++) { int tmp1 = tmp + j; arr1[tmp1] = data1[j]; arr2[tmp1] = data2[j]; iAvg1 += arr1[tmp1]; iAvg2 += arr2[tmp1]; } } iAvg1 /= 64; iAvg2 /= 64; for (int i = 0; i < 64; i++) { arr1[i] = (arr1[i] >= iAvg1) ? 1 : 0; arr2[i] = (arr2[i] >= iAvg2) ? 1 : 0; } int iDiffNum = 0; for (int i = 0; i < 64; i++) { if (arr1[i] != arr2[i]) iDiffNum++; } return iDiffNum; }