最近項目略多,其中一個需要找出一些和臉比較像但是不是臉的負樣本,想用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
}
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

