程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++開發人臉性別識別教程(10)——添加圖片的人臉檢測程序

C++開發人臉性別識別教程(10)——添加圖片的人臉檢測程序

編輯:C++入門知識

C++開發人臉性別識別教程(10)——添加圖片的人臉檢測程序


  如今我們的MFC框架已經初具規模,能夠讀取並顯示文件夾下的圖片,在這篇博文中我們將向其中添加人臉檢測的程序。

  一、人臉檢測算法

  這裡我們使用OpenCv封裝的Adaboost方法來進行人臉檢測,
  

       二、初始化

  1、添加初始化按鈕

  在進行人臉檢測之前需要初始化一些相關變量,例如開辟內存,加載檢測器等等。首先,我們為MFC框架添加一個初始化按鈕,並將ID更改為IDC_BUTTON_INITIAL:

\

  雙擊這個按鈕,添加事件響應函數:

\

  2、初始化變量

  從之前的博客中可知,OpenCv在進行人臉檢測時需要用到兩個靜態變量:static CvMemStorage* storage和static CvHaarClassifierCascade* cascade,這裡我們將其作為成員變量添加到CGenderRecognitionMFCDlg類中,這裡由於static CvMemStorage*和static CvHaarClassifierCascade*這兩個類型名在MFC類向導中是無法被識別的,因此需要手動添加至CGenderRecognitionMFCDlg類的構造函數中:

\

  接下裡對這兩個驚天變量進行初始化。C++明確規定靜態成員變量要在類外進行初始化,而不能在類內聲明時或者構造函數內進行初始化,原因就是靜態變量時屬於類本身的,而非類對象的屬性,和全局變量類似,因此我們將這兩個靜態變量的初始化操作放在GenderRecognitionMFCDlg.cpp文件(從解決方案資源管理器窗口中查找cpp文件)的開頭位置:

// 用於應用程序“關於”菜單項的 CAboutDlg 對話框
CvMemStorage* CGenderRecognitionMFCDlg::storage = NULL;
CvHaarClassifierCascade* CGenderRecognitionMFCDlg::cascade = NULL;

  然後在“初始化”按鈕的響應函數OnBnClickedButtonInitial()中加載對應的人臉檢測器:

void CGenderRecognitionMFCDlg::OnBnClickedButtonInitial()
{
    cascade = cvLoadHaarClassifierCascade("D:\\opencv\\sources\\data\\haarcascades
\\haarcascade_frontalface_alt_tree.xml",cvSize(30,30));
    storage = cvCreateMemStorage(0);
    // TODO: 在此添加控件通知處理程序代碼
}

  初始化完成。

  三、編寫人臉檢測函數  

  這裡將人臉檢測的操作封裝成一個函數detect_and_draw(),作為成員函數添加到CGenderRecognitionMFCDlg類中:

\

  在類視圖中找到detect_and_draw()函數,完善其人臉檢測代碼,由於之前已經詳細介紹過人臉檢測的相關操作,這裡直接給出代碼:

void CGenderRecognitionMFCDlg::detect_and_draw(IplImage* img)
{
    /**********初始化**********/
    double scale   = 1.2; 
    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));                       //初始檢測窗口大小

    /**********繪制檢測結果**********/
    if(objects->total > 0)                    //如果人臉檢測成功
    {
        for (int i = 0; i < (objects ? objects->total : 0); i++)
        {
            CvRect* rect = (CvRect*)cvGetSeqElem(objects,i);
            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); 
}

  注意這裡相對於之前的程序,添加了一項直方圖均衡化的操作,以提高人臉檢測的成功率:

\

  四、調用人臉檢測函數

  理論上在顯示圖像之前應該自動調用人臉檢測操作,因此在GetNextBigImg()函數中調用人臉檢測函數:

\

  由於在detect_and_draw()函數中已經封裝了picture顯示的程序,所以可以將GetNextBigImg()函數中原有的picture控件顯示程序去掉。

  大功告成,順利完成人臉檢測:

\

  三、總結

  這裡我們初步完成了MFC中的人臉檢測功能,但這裡存在兩個嚴重的BUG,一是如果用戶未單擊“初始化”按鈕,直接打開圖片,程序會因缺少必要的初始化步驟而直接崩潰;二是如上圖所見,OpenCv在進行人臉檢測時可能會錯誤檢測出多個矩形,其中只有一個矩形包含人臉,其余的都是干擾,需要進行處理,我們將在下一篇博客中介紹如何解決這兩個BUG。

  同時在此需要強調一下兩個問題:

  1、靜態成員變量的初始化:c++中可以對類中私有成員中的靜態變量初始化嗎?

  2、字符串的連接:C++字符換行

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved