OpenCv直方图对比图片的相似性

转自:http://blog.163.com/woshitony111@126/blog/static/71379539201262202820650/

原理

  • 要比较两个直方图( H_{1} andH_{2} ), 首先必须要选择一个衡量直方图相似度的对比标准 (d(H_{1}, H_{2})) 。

  • OpenCV 函数 compareHist 执行了具体的直方图对比的任务。该函数提供了4种对比标准来计算相似度:

    1. Correlation ( CV_COMP_CORREL )

      d(H_1,H_2) =  \frac{\sum_I (H_1(I) - \bar{H_1}) (H_2(I) - \bar{H_2})}{\sqrt{\sum_I(H_1(I) - \bar{H_1})^2 \sum_I(H_2(I) - \bar{H_2})^2}}

      其中

      \bar{H_k} =  \frac{1}{N} \sum _J H_k(J)

      N 是直方图中bin的数目。

    2. Chi-Square ( CV_COMP_CHISQR )

      d(H_1,H_2) =  \sum _I  \frac{\left(H_1(I)-H_2(I)\right)^2}{H_1(I)+H_2(I)}

    3. Intersection ( CV_COMP_INTERSECT )

      d(H_1,H_2) =  \sum _I  \min (H_1(I), H_2(I))

    4. Bhattacharyya 距离( CV_COMP_BHATTACHARYYA )

      d(H_1,H_2) =  \sqrt{1 - \frac{1}{\sqrt{\bar{H_1} \bar{H_2} N^2}} \sum_I \sqrt{H_1(I) \cdot H_2(I)}}

源码

  • 本程序做什么?

    • 装载一张 基准图像 和 两张 测试图像 进行对比。
    • 产生一张取自 基准图像 下半部的图像。
    • 将图像转换到HSV格式。
    • 计算所有图像的H-S直方图,并归一化以便对比。
    • 基准图像 直方图与 两张测试图像直方图,基准图像半身像直方图,以及基准图像本身的直方图分别作对比。
    • 显示计算所得的直方图相似度数值。
  • 下载代码: 点击 这里

  • 代码一瞥:

#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> #include <stdio.h>  using namespace std; using namespace cv;  /** @函数 main */ int main( int argc, char** argv ) {   Mat src_base, hsv_base;   Mat src_test1, hsv_test1;   Mat src_test2, hsv_test2;   Mat hsv_half_down;    /// 装载三张背景环境不同的图像   if( argc < 4 )     { printf("** Error. Usage: ./compareHist_Demo <image_settings0> <image_setting1> <image_settings2>\n");       return -1;     }    src_base = imread( argv[1], 1 );   src_test1 = imread( argv[2], 1 );   src_test2 = imread( argv[3], 1 );    /// 转换到 HSV   cvtColor( src_base, hsv_base, CV_BGR2HSV );   cvtColor( src_test1, hsv_test1, CV_BGR2HSV );   cvtColor( src_test2, hsv_test2, CV_BGR2HSV );    hsv_half_down = hsv_base( Range( hsv_base.rows/2, hsv_base.rows - 1 ), Range( 0, hsv_base.cols - 1 ) );    /// 对hue通道使用30个bin,对saturatoin通道使用32个bin   int h_bins = 50; int s_bins = 60;   int histSize[] = { h_bins, s_bins };    // hue的取值范围从0到256, saturation取值范围从0到180   float h_ranges[] = { 0, 256 };   float s_ranges[] = { 0, 180 };    const float* ranges[] = { h_ranges, s_ranges };    // 使用第0和第1通道   int channels[] = { 0, 1 };    /// 直方图   MatND hist_base;   MatND hist_half_down;   MatND hist_test1;   MatND hist_test2;    /// 计算HSV图像的直方图   calcHist( &hsv_base, 1, channels, Mat(), hist_base, 2, histSize, ranges, true, false );   normalize( hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat() );    calcHist( &hsv_half_down, 1, channels, Mat(), hist_half_down, 2, histSize, ranges, true, false );   normalize( hist_half_down, hist_half_down, 0, 1, NORM_MINMAX, -1, Mat() );    calcHist( &hsv_test1, 1, channels, Mat(), hist_test1, 2, histSize, ranges, true, false );   normalize( hist_test1, hist_test1, 0, 1, NORM_MINMAX, -1, Mat() );    calcHist( &hsv_test2, 1, channels, Mat(), hist_test2, 2, histSize, ranges, true, false );   normalize( hist_test2, hist_test2, 0, 1, NORM_MINMAX, -1, Mat() );    ///应用不同的直方图对比方法   for( int i = 0; i < 4; i++ )      { int compare_method = i;        double base_base = compareHist( hist_base, hist_base, compare_method );        double base_half = compareHist( hist_base, hist_half_down, compare_method );        double base_test1 = compareHist( hist_base, hist_test1, compare_method );        double base_test2 = compareHist( hist_base, hist_test2, compare_method );         printf( " Method [%d] Perfect, Base-Half, Base-Test(1), Base-Test(2) : %f, %f, %f, %f \n", i, base_base, base_half , base_test1, base_test2 );      }    printf( "Done \n" );    return 0;  } 

解释

  1. 声明储存基准图像和另外两张对比图像的矩阵( RGB 和 HSV )

    Mat src_base, hsv_base; Mat src_test1, hsv_test1; Mat src_test2, hsv_test2; Mat hsv_half_down; 
  2. 装载基准图像(src_base) 和两张测试图像:

    if( argc < 4 )   { printf("** Error. Usage: ./compareHist_Demo <image_settings0> <image_setting1> <image_settings2>\n");     return -1;   }  src_base = imread( argv[1], 1 ); src_test1 = imread( argv[2], 1 ); src_test2 = imread( argv[3], 1 ); 
  3. 将图像转化到HSV格式:

    cvtColor( src_base, hsv_base, CV_BGR2HSV ); cvtColor( src_test1, hsv_test1, CV_BGR2HSV ); cvtColor( src_test2, hsv_test2, CV_BGR2HSV ); 
  4. 同时创建包含基准图像下半部的半身图像(HSV格式):

    hsv_half_down = hsv_base( Range( hsv_base.rows/2, hsv_base.rows - 1 ), Range( 0, hsv_base.cols - 1 ) ); 
  5. 初始化计算直方图需要的实参(bins, 范围,通道 H 和 S ).

    int h_bins = 50; int s_bins = 32; int histSize[] = { h_bins, s_bins };  float h_ranges[] = { 0, 256 }; float s_ranges[] = { 0, 180 };  const float* ranges[] = { h_ranges, s_ranges };  int channels[] = { 0, 1 }; 
  6. 创建储存直方图的 MatND 实例:

    MatND hist_base; MatND hist_half_down; MatND hist_test1; MatND hist_test2; 
  7. 计算基准图像,两张测试图像,半身基准图像的直方图:

    calcHist( &hsv_base, 1, channels, Mat(), hist_base, 2, histSize, ranges, true, false ); normalize( hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat() );  calcHist( &hsv_half_down, 1, channels, Mat(), hist_half_down, 2, histSize, ranges, true, false ); normalize( hist_half_down, hist_half_down, 0, 1, NORM_MINMAX, -1, Mat() );  calcHist( &hsv_test1, 1, channels, Mat(), hist_test1, 2, histSize, ranges, true, false ); normalize( hist_test1, hist_test1, 0, 1, NORM_MINMAX, -1, Mat() );  calcHist( &hsv_test2, 1, channels, Mat(), hist_test2, 2, histSize, ranges, true, false ); normalize( hist_test2, hist_test2, 0, 1, NORM_MINMAX, -1, Mat() ); 
  8. 按顺序使用4种对比标准将基准图像(hist_base)的直方图与其余各直方图进行对比:

    for( int i = 0; i < 4; i++ )    { int compare_method = i;      double base_base = compareHist( hist_base, hist_base, compare_method );      double base_half = compareHist( hist_base, hist_half_down, compare_method );      double base_test1 = compareHist( hist_base, hist_test1, compare_method );      double base_test2 = compareHist( hist_base, hist_test2, compare_method );      printf( " Method [%d] Perfect, Base-Half, Base-Test(1), Base-Test(2) : %f, %f, %f, %f \n", i, base_base, base_half , base_test1, base_test2 );   } 

结果

  1. 使用下列输入图像:

    Base_0

    Test_1

    Test_2

    第一张为基准图像,其余两张为测试图像。同时我们会将基准图像与它自身及其半身图像进行对比。

  2. 我们应该会预料到当将基准图像直方图及其自身进行对比时会产生完美的匹配, 当与来源于同一样的背景环境的半身图对比时应该会有比较高的相似度, 当与来自不同亮度光照条件的其余两张测试图像对比时匹配度应该不是很好:

  3. 下面显示的是结果数值:

对比标准基准 - 基准基准 - 半身基准 - 测试1基准 - 测试2
Correlation1.0000000.9307660.1820730.120447
Chi-square0.0000004.94046621.18453649.273437
Intersection24.39154814.9598093.8890295.775088
Bhattacharyya0.0000000.2226090.6465760.801869

对于 CorrelationIntersection 标准, 值越大相似度越大。因此可以看到对于采用这两个方法的对比,*基准 - 基准* 的对比结果值是最大的, 而基准 - 半身 的匹配则是第二好(跟我们预测的一致)。而另外两种对比标准,则是结果越小相似度越大。 我们可以观察到基准图像直方图与两张测试图像直方图的匹配是最差的,这再一次印证了我们的预测。

 

### 回答1: OpenCVSharp是一个针对OpenCV的C#包装库,提供了图像处理和计算机视觉方面的功能。在OpenCVSharp中实现图像对比需要以下步骤。 首先,我们需要加载要比较的两张图片。使用`Cv2.ImRead()`函数可以加载图像文件,并将其存储在Mat对象中。 接下来,将两张图片转换为灰度图像。我们可以使用`Cv2.CvtColor()`函数将图像从原始的BGR格式转换为灰度格式,以便进行后续的对比操作。 然后,我们可以使用`Cv2.AbsDiff()`函数计算两张灰度图像的差异图像。此函数会计算两个输入图像相应像素点的差异,并将结果存储在新的Mat对象中。 接着,我们可以对差异图像进行阈值处理,以便得到明显的差异区域。可以使用`Cv2.Threshold()`函数将差异图像中低于阈值的像素点设置为0,高于阈值的像素点设置为255。 最后,我们可以通过检测差异图像中的轮廓,并计算轮廓的面积来获取对比结果。使用`Cv2.FindContours()`函数可以检测差异图像中的轮廓。然后,使用`Cv2.ContourArea()`函数可以计算每个轮廓的面积。根据面积大小,我们可以得到对比结果,例如,当面积很大时,说明两幅图像存在较明显的差异;当面积很小或为0时,说明两幅图像非常相似或完全相同。 总结了上述步骤,我们可以在OpenCVSharp中实现图片对比。这个过程可以帮助我们识别两幅图像的异同,对于图像处理和计算机视觉应用非常有用。 ### 回答2: 使用OpenCvSharp进行图片对比可以通过以下步骤实现: 1. 导入OpenCvSharp库。 ```csharp using OpenCvSharp; ``` 2. 加载两张待比较的图片。 ```csharp Mat img1 = new Mat("image1.jpg", ImreadModes.Color); Mat img2 = new Mat("image2.jpg", ImreadModes.Color); ``` 3. 将图片转换为灰度图像。 ```csharp Mat grayImg1 = new Mat(); Cv2.CvtColor(img1, grayImg1, ColorConversionCodes.BGR2GRAY); Mat grayImg2 = new Mat(); Cv2.CvtColor(img2, grayImg2, ColorConversionCodes.BGR2GRAY); ``` 4. 计算两张灰度图像的直方图。 ```csharp Mat histImg1 = new Mat(); Cv2.CalcHist(new Mat[] { grayImg1 }, new int[] { 0 }, new Mat(), histImg1, 1, new int[] { 256 }, new Rangef[] { new Rangef(0, 256) }); Cv2.Normalize(histImg1, histImg1, 0, 255, NormTypes.MinMax); Mat histImg2 = new Mat(); Cv2.CalcHist(new Mat[] { grayImg2 }, new int[] { 0 }, new Mat(), histImg2, 1, new int[] { 256 }, new Rangef[] { new Rangef(0, 256) }); Cv2.Normalize(histImg2, histImg2, 0, 255, NormTypes.MinMax); ``` 5. 计算两张直方图的差异。 ```csharp double compareValue = Cv2.CompareHist(histImg1, histImg2, HistCompMethods.Correl); ``` 6. 根据比较结果判断图像相似度。 ```csharp if (compareValue < 0.9) { Console.WriteLine("图片相似。"); } else { Console.WriteLine("图片相似。"); } ``` 通过以上步骤,我们可以使用OpenCvSharp进行图片对比并判断相似度。根据直方图的相关性计算结果,可以判断两张图片相似程度。如果相似度小于0.9,可以认为图片相似;如果相似度大于等于0.9,可以认为图片相似。 ### 回答3: 要使用OpenCvSharp进行图片对比,可以分为以下几个步骤: 1. 导入OpenCvSharp库 首先,我们需要在项目中导入OpenCvSharp库,以便使用其中的图片处理和对比功能。 2. 读取图片 使用OpenCvSharp提供的函数,可以从文件夹中读取两张待对比的图片,并将其加载到内存中。 3. 图片灰度化 由于我们要进行的是图片对比任务,为了简化计算和提高对比准确性,可以将两张图片转换为灰度图像。可以通过将图像的RGB通道值平均来实现灰度化。 4. 计算图片相似度 一种常用的图片对比方法是计算两张图片的均方误差(MSE)。首先,需要将两张灰度图像转换为二维数组,然后逐像素计算差异,并将差值平方累加。最终得到的累加值越小,表示两张图片相似。 5. 判断图片相似度 根据计算得到的MSE值,可以判断两张图片相似度。可以设置一个阈值,当MSE小于该阈值时,认为两张图片相似;否则,认为两张图片相似。 6. 输出结果 根据对比结果,可以将判断出的相似度信息打印或者输出到文件中,以便后续使用。 总结起来,使用OpenCvSharp进行图片对比的步骤包括导入库、读取图片图片灰度化、计算图片相似度和判断图片相似度等。根据对比结果可以进行后续处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值