歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

讓OpenCV輸出人臉檢測的得分代碼(置信率)

最近項目略多,其中一個需要找出一些和臉比較像但是不是臉的負樣本,想用OpenCV的人臉檢測器檢測到的錯誤臉作為這樣的負樣本。

但是國內(包括國外)居然幾乎沒有相關的資料如何輸出detectMultiScale()的置信率或者說是人臉得分

所以寫一篇小小的總結供有相關需求的人參考。

看了下人臉識別函數的OpenCV的源碼

\sources\modules\objdetect\src\cascadedetect.cpp

 

中detectMultiScale有兩個重載,第二個重載在opencv的開發文檔裡居然只字未提:

void CascadeClassifier::detectMultiScale( const Mat& image, vector<Rect>& objects,
                                          vector<int>& rejectLevels,
                                          vector<double>& levelWeights,
                                          double scaleFactor, int minNeighbors,
                                          int flags, Size minObjectSize, Size maxObjectSize,
                                          bool outputRejectLevels )

發現他有個rejectLevels和levelWeight這兩個引用參數,看名字感覺是一種得分輸出。

google了一下發現國外問的人不少但是基本沒啥解釋(或者是我沒認真找?)

然後看了下它調用的cvHaarDetectObjectsForROC()的源碼實現,大概懂了這倆vectors是在干什麼的。

先上結論:確實和人臉得分有關。

首先應該明白一點detectMultiScale()這個方法是一個級聯分類器,使用了boosting的方法。所以輸入圖像要經過層層(級級)選拔,留到最後的才是真漢子(正樣本)

rejectLevels就是代表在第幾層被out的。如果是最後一層(在lbpcascade_frontalface.xml中是20,具體要看xml中的敘述)被out,則說明很可能是正樣本。

為啥說很可能呢?

因為還有個參數:levelWeight。即使是在最後一層被out的,levelWeight很小甚至是負數,也可以看成是負樣本。

實際上很多負樣本正是在最後一層被out的。

見下圖:

我這裡只截取了level在20才out的框。輸出了他們的levelWeight。是臉的地方最大是4.23多,其他的就很小。不用過多解釋了吧~

所以這個函數的原理是這樣的(個人理解,有錯誤請指教):

首先一個level一個level地測試樣本,然後每一個level給一個對應的得分,也就是levelWeight,如果這個weight低於或者高於對應level的threshold,則被拋棄。

堅持到最後一個level並且在最後一個level仍然滿足threshold的框就是正確的臉(正樣本)。

所以,人臉的分應該是這樣:level越大,分數越高,在相同的level,levelWeight越大分數越高。

但是實際上真正的人臉都是能堅持到level20(最後一個level)的,所以只比對最後一個level的所有大於1的框的levelWeight進行比對就可以知道臉的得分啦~

這裡給出所有level被gg的框的圖:

最後給出灰常短小精悍的demo的源代碼:

#include <opencv2\opencv.hpp>
#include <iostream>
#include <vector>
#include <fstream>
#include <math.h>
using namespace std;
using namespace cv;
const string xmlpath = "lbpcascade_frontalface.xml";
CascadeClassifier face_cc;

int tic = 0;

void detect(Mat img){
    vector<Rect> faces;
    vector<int> rejLevel;
    vector<double> levelW;
    Mat grayimg;
    cvtColor(img, grayimg, CV_RGB2GRAY);
    equalizeHist(grayimg, grayimg);
    int minl = min(img.rows, img.cols);
    face_cc.detectMultiScale(grayimg, faces, rejLevel, levelW, 1.1, 3, 0, Size(), Size(), true);
    //face_cc.detectMultiScale(grayimg, faces, 1.1);
    for ( int i = 0; i < faces.size(); i++ )
    {
        if ( rejLevel[i] < 00 )
        {
            continue;
        }
        stringstream text1, text2;
        text1 << "rejLevel:" << rejLevel[ i ];
        text2 << "levelW:" << levelW[ i ];
        string ttt = text1.str();
        rectangle(img, faces[ i ], Scalar(255, 255, 0), 2, 8, 0);
        putText(img, ttt, cvPoint(faces[ i ].x, faces[ i ].y - 3), 1, 1, Scalar(0,255,255));
        ttt = text2.str();
        putText(img, ttt, cvPoint(faces[ i ].x, faces[ i ].y + 12), 1, 1, Scalar(255, 0, 255));
    }
    imshow("IMG", img);
    waitKey(0);
}

int main(){
    if ( !face_cc.load(xmlpath) )
    {
        cout << "load error!\n";
        return -1;
    }
    ifstream pathin;
    pathin.open("imgpath.txt");
    string t;
    while ( pathin >> t && tic < 10000)
    {
        Mat img = imread(t);
        detect(img);
    }
    pathin.close();
    return 0;
}

--------------------------------------分割線 --------------------------------------

Ubuntu Linux下安裝OpenCV2.4.1所需包 http://www.linuxidc.com/Linux/2012-08/68184.htm

Ubuntu 12.04 安裝 OpenCV2.4.2 http://www.linuxidc.com/Linux/2012-09/70158.htm

CentOS下OpenCV無法讀取視頻文件 http://www.linuxidc.com/Linux/2011-07/39295.htm

Ubuntu 12.04下安裝OpenCV 2.4.5總結 http://www.linuxidc.com/Linux/2013-06/86704.htm

Ubuntu 10.04中安裝OpenCv2.1九步曲 http://www.linuxidc.com/Linux/2010-09/28678.htm

基於QT和OpenCV的人臉識別系統 http://www.linuxidc.com/Linux/2011-11/47806.htm

[翻譯]Ubuntu 14.04, 13.10 下安裝 OpenCV 2.4.9  http://www.linuxidc.com/Linux/2014-12/110045.htm

--------------------------------------分割線 --------------------------------------

OpenCV的詳細介紹:請點這裡
OpenCV的下載地址:請點這裡

Copyright © Linux教程網 All Rights Reserved