C++开发人脸性别识别教程(18)——辅助功能之文件名批量修改、方法验证

  时光推移了30多天,这个人脸性别识别的小项目也接近尾声了,预计再通过三篇博文的篇幅来完成这个项目的收尾工作。在这篇博文中我们再为程序添加另外两个小的辅助功能:文件名批量修改、方法验证。

  一 文件名批量修改

  批量修改文件名是一件很基础也很常用的小操作,核心操作就是图像文件的批量读取、批量改名、批量保存。基本思想就是把文件读出来,然后在保存回去(注意不要和别的文件发生覆盖),从这个角度来讲文件名批量修改与上一篇博客C++开发人脸性别识别教程(17)——辅助功能之人脸批量分割中的人脸批量分割简直如出一辙,这里就不再赘述,大家请自行添加控件按钮、编写相关函数吧:

C++开发人脸性别识别教程(18)——辅助功能之文件名批量修改、方法验证_第1张图片

  二 方法验证

  这个小功能是当初为了测试四种分类方法(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、存在人脸检测失败的可能性

  这里有一个隐含的问题需要注意,在进行人脸检测时是存在检测失败的风险的,如果检测失败,虽然程序不会报错,但会导致识别率的误降低(具体原因大家自己思考哈),解决方案有三种,一是提前进行一遍人脸检测,将检测失败的图像剔除出去;二是设置人脸检测标志位,当人脸检测失败时不进行样本数目的累加;三是直接使用已经分割好的人脸做仿真,绕过人脸检测这一步,具体采用哪种方法改进大家自行决定吧。

你可能感兴趣的:(mfc,opencv,性别识别)