图像相似性检测入门
发布时间:2020-12-14 02:54:21 所属栏目:大数据 来源:网络整理
导读:前文提到,本爷接到一个小任务,是要做图像相似性检测。 现在图像处理发展迅猛异常,检测相似性,方法不胜枚举。。然而。。简单易懂容易实现的方法,就只有几个了。。 首先最广泛应用的是直方图相似度检测。这个方法大多数openCV的教材都有,思路大概就是 数
前文提到,本爷接到一个小任务,是要做图像相似性检测。
现在图像处理发展迅猛异常,检测相似性,方法不胜枚举。。然而。。简单易懂容易实现的方法,就只有几个了。。
首先最广泛应用的是直方图相似度检测。这个方法大多数openCV的教材都有,思路大概就是 数一数 各种颜色有多少个像素点,统计起来,记录成为直方图,然后比较两个图的直方图有什么差别。
给出一个函数来看看吧
{ Mat src1,src2; //灰度直方图 Mat hist1,hist2; //rgb直方图 Mat hist1_r,hist1_g,hist1_b; Mat hist2_r,hist2_g,hist2_b; //记录结果 double result1,result2,result3,result4; //bin数目,取值范围 int binNumber = 16; float range[] = {0,255}; const float *ranges[] = {range}; const int channels = 0; /// 装载图像 src1 = imread("/图片的路径。。/1.png"); src2 = imread("/图片的路径。。/2.png"); //分割图像的矩阵,成为RGB三个通道,分别存于vector1和vector2中 vector<<span class="s1">Mat> vec1; split(src1,vec1); vector<<span class="s1">Mat> vec2; split(src2,vec2); calcHist(&src1,1,&channels,Mat(),hist1,&binNumber,ranges,true,false); calcHist(&vec1[0],hist1_r,false); calcHist(&vec1[1],false); calcHist(&vec1[2],hist1_b,false); calcHist(&src2,hist2,false); calcHist(&vec2[0],hist2_r,false); calcHist(&vec2[1],false); calcHist(&vec2[2],hist2_b,false); //归一化 normalize(hist1,hist1); normalize(hist1_r,hist1_r); normalize(hist1_g,hist1_g); normalize(hist1_b,hist1_b); normalize(hist2,hist2); normalize(hist2_r,hist2_r); normalize(hist2_g,hist2_g); normalize(hist2_b,hist2_b); //相关系数:(绝对值)=1完全相同,>0.8高度相关,<0.3低度相关,其他为中度相关 //巴氏:完全匹配为0,完全不匹配为1 result1 = compareHist(hist1,CV_COMP_BHATTACHARYYA); result2 = compareHist(hist1_r,CV_COMP_BHATTACHARYYA); result3 = compareHist(hist1_g,CV_COMP_BHATTACHARYYA); result4 = compareHist(hist1_b,CV_COMP_BHATTACHARYYA); //通过弹出窗口显示 NSString *str= [NSString stringWithFormat:@"相似度: %f (%f %f %f) !",result1,result4]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"(巴氏距离,越小越好)!" message:str delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil]; [alert show]; } 另外一种方法叫hash。。。其实我忘记叫什么了。。。 思路是缩小图片至某个size,然后统一成为灰度图,再计算一下所有点的灰度值的平均,然后大于平均的点记录为1,小得记录为0..这时候,图片就变成了一个size * size(比如8*8),装满了0和1的矩阵。这个矩阵,听说是叫做图片的指纹(fingerprint,外国人起的名字,,,)然后比较一下两个指纹区别多大,就可以知道两个图片区别多大。一般用汉明距离来计算相似度,比如A指纹的左上角是0,而B指纹的左上角是1,那么汉明距离就+1,以此类推循环一遍。 另外有更高级的pHash方法,在缩小矩阵,转化灰度之后,做一个离散余弦变换(不懂。。我猜大概就是。。把图片中高频的成分(变化大的地方,比如黑白交接的地方)往右下角挪动,把低频成分(变化小的地方)往左上角挪动)。然后取出低频的成分,计算两图的距离 同样奉上一段代码
- (void)DoSomething { Mat src1,src2; src1 = imread("/图片的路径/1.png"); src2 = imread("/图片的路径/2.png"); string str1 = avgHashValue(src1); string str2 = avgHashValue(src2); printf("结果:%dn",HamingDistance(str1,str2)); } //均值Hash算法 string avgHashValue(Mat &src) { string rst(64,' '); Mat img,dst; if(src.channels()==3){ cvtColor(src,src,CV_BGR2GRAY); img=Mat_<<span class="s1">double>(src); } else img=Mat_<<span class="s1">double>(src); //第一步,缩小尺寸。将图片缩小到8x8的尺寸,总共64个像素,去除图片的细节 resize(img,img,cv::Size(8,8)); // 第二步,简化色彩(Color Reduce)。将缩小后的图片,转为64级灰度。 uchar *pData; for(int i=0;irows;i++) { pData = img.ptr<<span class="s4">uchar>(i); for(int j=0;jcols;j++) { pData[j]=pData[j]/4; } } // 第三步,计算平均值。计算所有64个像素的灰度平均值。 int average = mean(img).val[0]; //第四步,比较像素的灰度。将每个像素的灰度,与平均值进行比较。大于或等于平均值记为1,小于平均值记为0 Mat mask= (img>=(uchar)average); // 第五步,计算哈希值。 int index = 0; for(int i=0;irows;i++) { pData = mask.ptr<<span class="s4">uchar>(i); for(int j=0;jcols;j++) { if(pData[j]==0) rst[index++]='0'; else rst[index++]='1'; } } return rst; } //pHash算法 string pHashValue(Mat &src) { string rst(64,dst; double dIdex[64]; double avg = 0.0; int k = 0; if(src.channels()==3){ cvtColor(src,CV_BGR2GRAY); img=Mat_<<span class="s1">double>(src); } else img=Mat_<<span class="s1">double>(src); //第一步,缩小尺寸。将图片缩小到8x8的尺寸,总共64个像素,8)); //第二部:离散余弦变换,dct系数求取 dct(img,dst); //第三步,求取DCT系数均值(左上角8*8区块的DCT系数) for (int i = 0; i < 8; ++i) { for (int j = 0; j < 8; ++j) { dIdex[k] = dst.at<<span class="s1">double>(i,j); avg += dst.at<<span class="s1">double>(i,j)/64; ++k; } } // 第四步,计算哈希值。 for (int i =0;i<64;++i) { if (dIdex[i]>=avg) { rst[i]='1'; } else { rst[i]='0'; } } return rst; } //汉明距离计算 int HamingDistance(string &str1,string &str2) { if((str1.size()!=256)||(str2.size()!=256)) return -1; int difference = 0; for(int i=0;i<256;i++) { if(str1[i]!=str2[i]) difference++; } return difference; } ? 就写这么多吧~ (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |