加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

图像相似性检测入门

发布时间: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;
}


?


就写这么多吧~

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读