C# OpenCVsharp图片相识度
平均哈希算法
实现步骤
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; }