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

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

1.項目內容

我最近在負責項目中openCV的部分,此篇文章講述通過灰度直方圖和HSV直方圖得到圖片相似度(c++)。
在之前團隊已經實現了利用face++接口得到人臉相似度比較,但是項目需要快速比較大量人臉,得到相似度,判斷是否爲一個人,老師希望我們使用openCv本地化獲取人臉相似度。
我嘗試用openCV獲得人臉相似度比,已經實現灰度直方圖和HSV直方圖比較,設定閾值HISTCMP_CORREL >0.5 && HISTCMP_BHATTACHARYYA<0.5才能劃分爲一類。
灰度直方圖和HSV直方圖比較我個人認爲不科學,最近在考慮dlib和openCV,使用歐式距離設定閾值判斷,思路還不太清晰(我個人認爲本地化人臉相似度比較結果不太科學,奈何團隊要求),如果大家有什麼好的建議,請在下面留言,謝謝!

2.直方圖判斷標準

做項目時參考的網址
https://blog.csdn.net/liurong_cn/article/details/8752427
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);

    }
}

參考網址

  1. 直方圖判斷4個標準 https://blog.csdn.net/liurong_cn/article/details/8752427
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章