在這篇博客需要解決之前遺留的兩個BUG,一是用戶在不初始化條件下運行程序,二是人臉檢測的誤差結果。
一、添加初始化警告
目前我們在“初始化”按鈕對應的響應函數中封裝了人臉分類器加載、開辟內存等操作:

因此,如果用戶在未單擊“初始化”按鈕的情況下進行圖片讀入,人臉檢測,程序就會因為缺少人臉檢測器而崩潰,因此我們向CGenderRecognitionMFCDlg類中添加一個布爾類型的標志位用于指示當前用戶是否完成了初始化操作:

并在CGenderRecognitionMFCDlg類的構造函數中將其初始化為false(正常情況下VS會自動完整這個操作):

接下來,在“初始化”按鈕對應的響應函數中,將這個標志位置為true,代表初始化已經完成:

接下來在“打開文件夾”按鈕對應的響應函數的開頭,添加標志位判斷代碼:

此時,如果用戶在未初始化時點擊了“圖像文件夾”按鈕,程序會彈出對話框,提示用戶先進行初始化操作:

二、人臉檢測優化
在之前的程序中,人臉檢測所返回的矩形不止一個,也就意味著存在檢測誤差。這里我們添加人臉檢測的結果篩選代碼,即根據檢測結果矩形的面積進行篩選,只保留最大面積的矩形作為人臉檢測的結果。這里需要對成員函數detect_and_draw()進行一些修改。
1、計算矩形面積
在人臉檢測完成后,輪詢檢測結果序列,計算矩形面積,并保留面積最大的矩形標號:
~~~
/**********對檢測出的人臉區域面積做比較,選取其中的最大矩形**********/
int maxface_label = 0; //最大面積人臉標簽
Mat max_face = Mat::zeros(objects->elem_size,1,CV_32FC1); //候選矩形面積
for(int i = 0;i< objects->total;i++)
{
CvRect* r = (CvRect*)cvGetSeqElem(objects,i);
max_face.at<float>(i,0) = (float)(r->height * r->width);
if(i > 0&&max_face.at<float>(i,0) > max_face.at<float>(i - 1,0))
{
maxface_label = i;
}
}
~~~
然后更改結果顯示部分的代碼,只繪制最大面積的矩形:
~~~
/**********繪制檢測結果**********/
if(objects->total > 0) //如果人臉檢測成功
{
CvRect* rect = (CvRect*)cvGetSeqElem(objects,maxface_label);
cvRectangle(img,cvPoint(rect->x,rect->y),
cvPoint(rect->x + rect->width,rect->y + rect->height),cvScalar(0.0,255));
}
~~~
大功告成。這里由于對detect_and_draw()函數做了較大修改,因此在此給出修改后detect_and_draw()函數的完整代碼:
~~~
void CGenderRecognitionMFCDlg::detect_and_draw(IplImage* img)
{
/**********初始化**********/
IplImage* gray = cvCreateImage(cvSize(img->width,img->height),8,1);
/**********灰度化**********/
if (img->nChannels = 3)
{
cvCvtColor(img,gray, CV_BGR2GRAY);//將圖像灰度化存放在gray中
}
else
{
gray = img;
}
/**********直方圖均衡**********/
cvEqualizeHist(gray,gray);
/**********人臉檢測**********/
cvClearMemStorage(storage);
CvSeq* objects = cvHaarDetectObjects(gray,//待檢測圖像
cascade, //分類器標識
storage, //存儲檢測到的候選矩形
1.3, //相鄰兩次檢測中窗口擴大的比例
3, //認為是人臉的最小矩形數(閾值)
0, //CV_HAAR_DO_CANNY_PRUNING
cvSize(30,30)); //初始檢測窗口大小
/**********對檢測出的人臉區域面積做比較,選取其中的最大矩形**********/
int maxface_label = 0; //最大面積人臉標簽
Mat max_face = Mat::zeros(objects->elem_size,1,CV_32FC1); //候選矩形面積
for(int i = 0;i< objects->total;i++)
{
CvRect* r = (CvRect*)cvGetSeqElem(objects,i);
max_face.at<float>(i,0) = (float)(r->height * r->width);
if(i > 0&&max_face.at<float>(i,0) > max_face.at<float>(i - 1,0))
{
maxface_label = i;
}
}
/**********繪制檢測結果**********/
if(objects->total > 0) //如果人臉檢測成功
{
CvRect* rect = (CvRect*)cvGetSeqElem(objects,maxface_label);
cvRectangle(img,cvPoint(rect->x,rect->y),
cvPoint(rect->x + rect->width,rect->y + rect->height),cvScalar(0.0,255));
}
/**********在圖像控件上顯示圖像**********/
CvvImage cvvImage;
cvvImage.CopyOf(img);
cvvImage.DrawToHDC(m_pPicCtlHdc,m_PicCtlRect);
cvReleaseImage(&gray);
}
~~~
?
?
?