OpenCv直方图对比图片的相似性 (c++、qt 、openCv)

  • 1.项目内容
  • 2.直方图判断标准
  • 3.代码
  • 灰度直方图
  • 参考网址


1.项目内容

我最近在负责项目中openCV的部分,此篇文章讲述通过灰度直方图和HSV直方图得到图片相似度(c++)。
在之前团队已经实现了利用face++接口得到人脸相似度比较,但是项目需要快速比较大量人脸,得到相似度,判断是否为一个人,老师希望我们使用openCv本地化获取人脸相似度。
我尝试用openCV获得人脸相似度比,已经实现灰度直方图和HSV直方图比较,设定阈值HISTCMP_CORREL >0.5 && HISTCMP_BHATTACHARYYA<0.5才能划分为一类。
灰度直方图和HSV直方图比较我个人认为不科学,最近在考虑dlib和openCV,使用欧式距离设定阈值判断,思路还不太清晰(我个人认为本地化人脸相似度比较结果不太科学,奈何团队要求),如果大家有什么好的建议,请在下面留言,谢谢!

2.直方图判断标准

做项目时参考的网址

HSV使用色调和饱和度两个通道,而灰色直方图只使用了灰度值。
直方图判断4个标准 :

1.CV_COMP_CORREL 靠近1最好
 2.Chi-Square ( CV_COMP_CHISQR 靠近0最好
 3.Intersection ( CV_COMP_INTERSECT )
 4.Bhattacharyya 距离( CV_COMP_BHATTACHARYYA ) 靠近0最好
 我使用 Chi-Square ( CV_COMP_CHISQR 和Bhattacharyya 距离( CV_COMP_BHATTACHARYYA )联合判断,阈值大家可以自己试,我使用的是HISTCMP_CHISQR <0.5 &&HISTCMP_BHATTACHARYYA<0.5

3.代码

大家配置好openCv和头文件,请自行编译。
我使用的openCv4.1,开发时有部分文件缺失报错,百度缺失文件,在openCv 3.x版本上找到相应文件补全。

#include<opencv2/objdetect/objdetect.hpp>
#include<opencv2/highgui/highgui.hpp> //简单的界面操作
#include<opencv2/imgproc/imgproc.hpp>  //处理图像的功能,如图像过滤和几何变换
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc.hpp>
#include<opencv2/imgcodecs/imgcodecs.hpp>
#include<opencv2/imgproc/types_c.h>
#include<opencv2/objdetect/objdetect_c.h>
#include<opencv2/opencv.hpp>

CompareFaceHSV()得出结果为图片1和自己比较,自己和自己半身图片(hsv_half_down)比较,自己和其他两张图片比较的4个对比标准的结果。
大家可以通过这个来寻找自己的阈值。我使用的是HISTCMP_CHISQR <0.5 && HISTCMP_BHATTACHARYYA<0.5 。
HSV直方图的通道我没有使用亮度,只使用了色调和饱和度。

void CompareFaceHSV(){  //原本的的OpenCvfaceCompareConfidence()用的灰色直方图  HSV肯定准一些
    Mat src_base, hsv_base;
    Mat src_test1, hsv_test1;
    Mat src_test2, hsv_test2;
    Mat hsv_half_down;    // 装载三张背景环境不同的图像
\\大家换成自己图片吧
    src_base = imread( "..\\faceSet\\3.jpg", 1 );
    src_test1 = imread( "..\\faceSet\\5.jpg", 1 );
    src_test2 = imread( "..\\faceSet\\4.jpg", 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 };    // 用到0 1 通道
    Mat hist_base;
    Mat hist_half_down;
    Mat hist_test1;
    Mat hist_test2;    // 计算HSV图像的直方图 1代表输入图像个数
    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() );    //应用不同的直方图对比方法
    // HISTCMP_CORREL 1  HISTCMP_CHISQR 0  HISTCMP_INTERSECT  HISTCMP_BHATTACHARYYA 0
    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" );
        
}

灰度直方图

最后附上openCv灰度直方图比较的代码,肯定没有HSV科学。大家自行寻找阈值。

IplImage* detect( Mat& img){
    Mat gray;
    cvtColor(img, gray, CV_BGR2GRAY );
    equalizeHist( gray, gray );
    IplImage pBinary = IplImage(gray);;
    IplImage *input = cvCloneImage(&pBinary);
    return input;
    //cvResize(img, dst);
}
void CompareHist(IplImage *faceImage1, IplImage *faceImage2){  //只考虑了灰色直方图
    int HistogramBins = 256;
    float HistogramRange1[2]={0,255};
    float *HistogramRange[1]={&HistogramRange1[0]}; 
    CvHistogram *Histogram1 = cvCreateHist(1, &HistogramBins, CV_HIST_ARRAY,HistogramRange);
    CvHistogram *Histogram2 = cvCreateHist(1, &HistogramBins, CV_HIST_ARRAY,HistogramRange);
    cvCalcHist(&faceImage1, Histogram1);  // IplImage** image,
    cvCalcHist(&faceImage2, Histogram2);
    cvNormalizeHist(Histogram1, 1);  //两幅图片大小不同也没关系 bin都是概率
    cvNormalizeHist(Histogram2, 1);
    // CV_COMP_CHISQR,CV_COMP_BHATTACHARYYA这两种都可以用来做直方图的比较,值越小,说明图形越相似 0最好
    printf("CV_COMP_CHISQR : %.4f\n", cvCompareHist(Histogram1, Histogram2, CV_COMP_CHISQR));
    printf("CV_COMP_BHATTACHARYYA : %.4f\n", cvCompareHist(Histogram1,
                                                Histogram2, CV_COMP_BHATTACHARYYA));
    cvReleaseHist(&Histogram1);
    cvReleaseHist(&Histogram2);

}

void OpenCvfaceCompareConfidence(){
      // face_cascade;
    Mat srcImg =imread("..\\faceSet\\3.jpg");  //1 :3通道读取
    Mat targetImg=imread("..\\faceSet\\5.jpg");
    qDebug() << "can read the OpenCvfaceCompareConfidence 2 images";
    if (!targetImg.data || !srcImg.data){
        qDebug() << "Couldn't read the image";
        return ;
    }
    else {

            IplImage* faceImage1=detect(srcImg);  //Mat->IplImag*
            IplImage* faceImage2=detect(targetImg);
            CompareHist(faceImage1, faceImage2);  //IplImag*才能传入
            //       imshow("image1", Mat(faceImage1));
            //       imshow("image2", Mat(faceImage2));

            //阈值还没确定
            cvReleaseImage(&faceImage1);
            cvReleaseImage(&faceImage2);

    }
}