程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++開發人臉性別識別教程(18)——輔助功能之文件名批量修改、方法驗證

C++開發人臉性別識別教程(18)——輔助功能之文件名批量修改、方法驗證

編輯:關於C++

  時光推移了30多天,這個人臉性別識別的小項目也接近尾聲了,預計再通過三篇博文的篇幅來完成這個項目的收尾工作。在這篇博文中我們再為程序添加另外兩個小的輔助功能:文件名批量修改、方法驗證。

  一 文件名批量修改

  批量修改文件名是一件很基礎也很常用的小操作,核心操作就是圖像文件的批量讀取、批量改名、批量保存。基本思想就是把文件讀出來,然後在保存回去(注意不要和別的文件發生覆蓋),從這個角度來講文件名批量修改與上一篇博客C++開發人臉性別識別教程(17)——輔助功能之人臉批量分割中的人臉批量分割簡直如出一轍,這裡就不再贅述,大家請自行添加控件按鈕、編寫相關函數吧:

\

  二 方法驗證

  這個小功能是當初為了測試四種分類方法(PCA、Fisher、LBP、HOG+SVM)的分類性能而額外添加的一段代碼,目的很簡單,就是想看看四種方法分類時哪個方法更准確一點。

  2.1 添加控件

  首先,添加一個按鈕控件,命名為“方法驗證”,ID不用變:

\

  然後在添加兩個編輯框控件,用來顯示各個方法的分類正確率,ID分別更改為IDC_Effect_Man和IDC_Effect_Wom:

\

  2.2 批量讀取測試樣本

  雙擊“方法驗證”按鈕,添加對應的事件處理函數OnBnClickedButton3(),首先,讀取測試樣本所在的文件夾:

    CString str;                            //存儲圖像路徑
    BROWSEINFO bi;                          //用來存儲用戶選中的目錄信息
    TCHAR name[MAX_PATH];                   //存儲路徑
    char imageFullName[500];                //存儲單個圖像文件的全路徑
    name[0]='d';

    ZeroMemory(&bi,sizeof(BROWSEINFO));     //清空目錄對應的內存
    bi.hwndOwner=GetSafeHwnd();             //得到窗口句柄
    bi.pszDisplayName=name;

    BIF_BROWSEINCLUDEFILES;
    bi.lpszTitle=_T("Select folder");       //對話框標題
    bi.ulFlags=0x80;//設置對話框形式
    LPITEMIDLIST idl=SHBrowseForFolder(&bi);//返回所選中文件夾的ID
    if(idl==NULL)
        return;
    SHGetPathFromIDList(idl,str.GetBuffer(MAX_PATH));//將文件信息格式化存儲到對應緩沖區中
    str.ReleaseBuffer();                    //與GerBuffer配合使用,清空內存
    m_Path=str;                             //將路徑存儲在m_path中
    if(str.GetAt(str.GetLength()-1)!='\\')
        m_Path+="\\";
    UpdateData(FALSE);

    // free memory used     
    IMalloc * imalloc = 0;
    if (SUCCEEDED(SHGetMalloc(&imalloc)))
    {
        imalloc->Free (idl);
        imalloc->Release();
    }
    m_ImageDir=(LPSTR)(LPCTSTR)m_Path;

    m_pDir = opendir(m_ImageDir);           //獲取該路徑下的第一個文件
    for (int i = 0; i < 2; i ++)            //過濾目錄 ..   和  .
    {
        m_pEnt = readdir(m_pDir);
    

  這裡圖像的批量讀取采用SHBrowseForFolder方法,在之前的博文中詳細介紹過,網上也有很多資料,這裡不再贅述。

  2.3 相關變量初始化

  由於要計算正確率,因此需要使用到一些局部臨時變量,這裡先對其進行初始化,至於每個變量的具體用途,在接下來的代碼中會幫助大家理解:

    float sum_num_man = 0;
    float sum_num_women = 0;
    float current_num_man = 0;
    float current_num_women = 0;

  2.4 方法測試

  接下來開始循環讀取測試文件夾下的測試樣本,進行性別識別、累加計數、計算正確率,先給出代碼:

    /**********方法測試**********/
    while (m_pDir && (m_pEnt = readdir(m_pDir)) != NULL) 
    {
        //首先判斷當前文件是否為圖像文件
        char* pJpg = strstr(m_pEnt->d_name,".jpg");
        char* pBmp = strstr(m_pEnt->d_name,".bmp");
        char* pPng = strstr(m_pEnt->d_name,".png");
        char* pJPG = strstr(m_pEnt->d_name,".JPG");

        if(pJpg==NULL && pBmp==NULL && pPng==NULL && pJPG==NULL)
        {
            break;
        }

        //拼出文件的全路徑
        sprintf(imageFullName,"%s%s",m_ImageDir,m_pEnt->d_name);

        IplImage* src;
        CvvImage srcCvvImg;

        //加載圖像
        src = cvLoadImage(imageFullName);
        detect_and_draw(src);
        //根據標簽來判斷當前圖片是男性還是女性
        char* pMan = strstr(m_pEnt->d_name,"man");
        char* pWomen = strstr(m_pEnt->d_name,"women");
        if (pMan != NULL)//如果當前圖片為男性
        {
            sum_num_man = sum_num_man + 1;
        }
        if (pWomen != NULL)//如果當前圖片為女性
        {
            sum_num_women = sum_num_women + 1;
        }
        if (m_genderLabel == 1)//如果當前圖片計算機檢測為男性
        {
            current_num_man = current_num_man + 1;
        }
        if (m_genderLabel == 2)//如果當前圖片計算機檢測為女性
        {
            current_num_women = current_num_women + 1;
        }
        cvReleaseImage(&src);
    }

  這裡主要有一下幾個問題需要強調:

  (1)測試樣本集的制作。在制作測試樣本集的時候,就用到了圖像批量改名的手段,男性測試樣本的名稱用“man”來標記,女性測試樣本的名稱用“women”來進行標記,效果如下:

\

\

  (2)正確率計算方法。在這裡計算識別率的方法非常簡單,首先通過strstr()函數判斷當前測試樣本的名稱中是含有“man”還是含有“women”,若含有“man”字符串,則說明當前測試樣本為男性測試樣本,計數器sum_num_man加一,同理若測試樣本為女性樣本時則女性計數器sum_num_women加一。 然後在根據性別識別結果(標簽m_genderLabel)來對當前的識別情況進行計數。

  2.5、計算識別率並顯示

  遍歷完成後,開始計算識別率並將其顯示在編輯框中,代碼如下:

    /**********計算識別結果並顯示**********/
    char ch[10];
    if (sum_num_man > sum_num_women)//如果當前測試集為男性
    {
        float result1;
        result1 = current_num_man / sum_num_man;
        int res1; 
        res1 = result1 * 100;
        itoa(res1,ch,10);
        GetDlgItem(IDC_Effect_Man)->SetWindowTextA(ch);
    }
    else
    {
        float result2; 
        result2 = current_num_women / sum_num_women;
        int res2;
        res2 = result2 * 100;
        itoa(res2,ch,10);
        GetDlgItem(IDC_Effect_Wom)->SetWindowTextA(ch);
    }

  OK,此時F5調試運行程序,選擇分類方法,初始化,選擇測試樣本文件夾,程序開始自動進行方法驗證,得出識別率。

  三 注意事項

  1、批量讀取文件的重要性

  從這兩篇博文中可以說明文件遍歷的重要性,C++乃至OpenCv都有相關的圖像遍歷方法,這裡給出的SHBrowseForFolder方法只是其中之一,其中OpenCv也提供了Directory類,大家可以多參考網上資料。

  2、存在人臉檢測失敗的可能性

  這裡有一個隱含的問題需要注意,在進行人臉檢測時是存在檢測失敗的風險的,如果檢測失敗,雖然程序不會報錯,但會導致識別率的誤降低(具體原因大家自己思考哈),解決方案有三種,一是提前進行一遍人臉檢測,將檢測失敗的圖像剔除出去;二是設置人臉檢測標志位,當人臉檢測失敗時不進行樣本數目的累加;三是直接使用已經分割好的人臉做仿真,繞過人臉檢測這一步,具體采用哪種方法改進大家自行決定吧。

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