轉:讓opencv輸出人臉檢測的得分(置信率)
讓opencv輸出人臉檢測的得分(置信率)
最近專案略多,其中一個需要找出一些和臉比較像但是不是臉的負樣本,想用opencv的人臉檢測器檢測到的錯誤臉作為這樣的負樣本。
但是國內(包括國外)居然幾乎沒有相關的資料如何輸出detectMultiScale()的置信率或者說是人臉得分
所以寫一篇小小的總結供有相關需求的人蔘考。
轉載需註明:http://www.cnblogs.com/sciencefans/
看了下人臉識別函式的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的原始碼:
1 #include <opencv2\opencv.hpp> 2 #include <iostream> 3 #include <vector> 4 #include <fstream> 5 #include <math.h> 6 using namespace std; 7 using namespace cv; 8 const string xmlpath = "lbpcascade_frontalface.xml"; 9 CascadeClassifier face_cc; 10 11 int tic = 0; 12 13 void detect(Mat img){ 14 vector<Rect> faces; 15 vector<int> rejLevel; 16 vector<double> levelW; 17 Mat grayimg; 18 cvtColor(img, grayimg, CV_RGB2GRAY); 19 equalizeHist(grayimg, grayimg); 20 int minl = min(img.rows, img.cols); 21 face_cc.detectMultiScale(grayimg, faces, rejLevel, levelW, 1.1, 3, 0, Size(), Size(), true); 22 //face_cc.detectMultiScale(grayimg, faces, 1.1); 23 for ( int i = 0; i < faces.size(); i++ ) 24 { 25 if ( rejLevel[i] < 00 ) 26 { 27 continue; 28 } 29 stringstream text1, text2; 30 text1 << "rejLevel:" << rejLevel[ i ]; 31 text2 << "levelW:" << levelW[ i ]; 32 string ttt = text1.str(); 33 rectangle(img, faces[ i ], Scalar(255, 255, 0), 2, 8, 0); 34 putText(img, ttt, cvPoint(faces[ i ].x, faces[ i ].y - 3), 1, 1, Scalar(0,255,255)); 35 ttt = text2.str(); 36 putText(img, ttt, cvPoint(faces[ i ].x, faces[ i ].y + 12), 1, 1, Scalar(255, 0, 255)); 37 } 38 imshow("IMG", img); 39 waitKey(0); 40 } 41 42 int main(){ 43 if ( !face_cc.load(xmlpath) ) 44 { 45 cout << "load error!\n"; 46 return -1; 47 } 48 ifstream pathin; 49 pathin.open("imgpath.txt"); 50 string t; 51 while ( pathin >> t && tic < 10000) 52 { 53 Mat img = imread(t); 54 detect(img); 55 } 56 pathin.close(); 57 return 0; 58 }