C 开采人脸性别识别教程(15)——搭建MFC框架运

作者:ca88编程

C 开垦人脸性别识别教程(10)——增添图片的人脸检验程序

  近些日子我们的MFC框架已经初具规模,能够读取并呈现文件夹下的图样,在这篇博文中大家将向当中加多人脸检测的主次。

  一、人脸检验算法

  这里我们运用OpenCv封装的艾达boost方法来进行人脸检查实验,   

       二、初始化

  1、加多初阶化开关

  在进展人脸检验此前必要开始化一些皮之不存毛将焉附变量,比方开垦内部存款和储蓄器,加载检测器等等。首先,大家为MFC框架增多贰个初叶化开关,并将ID更换为IDC_BUTTON_INITIAL:

ca88编程 1

  双击那个按键,增加事变响应函数:

ca88编程 2

  2、开端化变量

  从在此之前的博客中可见,OpenCv在开展人脸检验时索要用到四个静态变量:static CvMemStorage* storage和static CvHaarClassifierCascade* cascade,这里大家将其当作成员变量增添到CGenderRecognitionMFCDlg类中,这里由于static CvMemStorage*和static CvHaarClassifierCascade*那四个项目名在MFC类向导中是无计可施被识别的,因而必要手动增添至CGenderRecognitionMFCDlg类的构造函数中:

ca88编程 3

  接下里对那多少个惊天变量实行初叶化。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类中:

ca88编程 4

  在类视图中找到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); 
}

  注意这里绝对于事先的前后相继,增加了一项直方图均衡化的操作,以升高人脸检查评定的成功率:

ca88编程 5

  四、调用人脸检验函数

  理论上在展现图像在此以前应当自行调用人脸检测操作,因而在GetNextBigImg()函数中调用人脸检查测量试验函数:

ca88编程 6

  由于在detect_and_draw()函数中早已封装了picture展现的主次,所以能够将GetNextBigImg()函数中本来的picture控件展现程序去掉。

  旗开得胜,顺遂完毕年人脸检查实验:

ca88编程 7

  三、总结

  这里大家早先成功了MFC中的人脸检查测验成效,但此间存在多个沉痛的BUG,一是只要顾客未单击“开始化”开关,直接张开图片,程序会因贫乏须要的伊始化步骤而平昔崩溃;二是如上航海用教室所见,OpenCv在扩充人脸检测时可能会错误检查测量试验出七个矩形,在那之中唯有三个矩形包蕴人脸,别的的都是扰攘,要求打开管理,我们就要下一篇博客中介绍怎么着消除那五个BUG。

  同期在此需求重申一下多个难题:

  1、静态成员变量的伊始化:c 中得以对类中个人成员中的静态变量开头化吗?

  2、字符串的连天:C 字符换行

 

这段日子大家的MFC框架已经初具规模,能够读取并展现文件夹下的图片,在那篇博...

  双击那些button。参加事件响应函数:

C 开拓人脸性别识别教程(12)——增多性别识别功用

  经过此前几篇博客的助教,大家已经成功搭建了MFC应用框架,并贯彻了骨干的图像呈现和人脸检查实验程序,在那篇博文中我们要向里面增添性别识别代码。

  关于性别鉴定识别,在此之前曾经非常拿出两篇博客的篇幅来打开教学,这里不再赘言,具体参见:C 开荒人脸性别识别教程(5)——通过FaceRecognizer类实现性别鉴定区别和C 开荒人脸性别识别教程(6)——通过SVM完成性别鉴定识别。

  一、分类器演练

  在拓宽人脸性别识别在此之前必要陶冶性别鉴其余分类器,而分类器的教练进度是对峙耗费时间的(大致五分钟),由此这里大家应用离线磨炼在线识别的形式,即提前将分类器陶冶好,作为程序的多寡进行保存,程序运营进程中平昔加载已经磨练好的分类器举办性别分类,那样速度就能够大大升高。

  在上边提供的两篇博客中都详细介绍了性别鉴定识别分类器的磨练方法,这里一同必要磨练各样分类器,分别是PCA、Fisher、LBP、SVM:

ca88编程 8

  二、增添下拉列表控件

  1、绘制控件

  由于此处有八种性别鉴其他不二诀窍,由此在程序运营时,供给顾客钦定一种性别鉴其余方式,这里提供四个下拉摘取列表(Combo Box)控件来供客户选拔。首先从工具箱中当选该控件,在MFC主窗口的确切岗位打开绘图,并将ID更动为IDC_COMBO_FUNCTION:

ca88编程 9

  2、钦命选项值

  接下去须求在CGenderRecognitionMFCDlg类的OnInitDialog()开头化函数中为下拉列表设置ID标号以及相应的突显文本:

    /*********初始化Combo Box控件**********/
    ((CComboBox*)GetDlgItem(IDC_COMBO_FUNCTION))->AddString("PCA变换");
    ((CComboBox*)GetDlgItem(IDC_COMBO_FUNCTION))->AddString("Fisher变换");
    ((CComboBox*)GetDlgItem(IDC_COMBO_FUNCTION))->AddString("LBP变换");
    ((CComboBox*)GetDlgItem(IDC_COMBO_FUNCTION))->AddString("支持向量机");
    ((CComboBox*)GetDlgItem(IDC_COMBO_FUNCTION))->SetCurSel(1);      //设置当前默认显示选项

  注意这里Combo 博克斯控件的次第选项的标号是暗中同意从“0”最初张开注脚的,即这里“0”代表“PCA转换”,“1”代表“Fisher调换”,“2”代表“LBP转换”,“3”代表“协助向量机”,私下认可呈现”Fisher转变“:

ca88编程 10

  这里有八个小细节供给留意:

  (1)须要提前线指挥部定Combo Box的下拉限定,那样本事确定保障在单击下拉开关时间调节件能够将具有选项整体来得出来:

ca88编程 11

  (2)Combo Box控件的”sort“属性,应该置为”false“:

ca88编程 12

  三、增添性别识别算法

  绘制完ComboBox控件之后,初步向里面填入性别鉴定识别算法。

  1、全局变量证明

  在头里性别识别的博客中牵线得很掌握,在动用OpenCv封装的分类器以前,须求申明多少个静态的沙盘变量,大家这里将其声明为全局变量,放在GenderRecognitionMFCDlg.cpp文件的初叶部分:

/************初始化性别分类器************/
static Ptr model_PCA = createEigenFaceRecognizer();    //PCA分类器
static Ptr model_Fisher = createFisherFaceRecognizer();//Fisher分类器
static Ptr model_LBP = createLBPHFaceRecognizer();     //LBP分类器
static CvSVM svm;                                                      //支持向量机分类器

  2、在”开首化“按键中加载分类器

  这里将分类器的加载操作安排在”开头化“开关对应的事件响应函数OnBnClickedButtonInitial()中,即客商单击”最初化“按钮之后,程序会基于当下顾客挑选的艺术来加载钦命的分类器。由于供给遵照客户日前在下拉列表中的选用景况来拓宽分类器的加载,由此要求下获得客户的选取的标记,然后通过switch语句完毕有选用的加载,代码如下:

    /**********根据用户的选择来加载分类器**********/
    int index = 0;
    index = ((CComboBox*)GetDlgItem(IDC_COMBO_FUNCTION))->GetCurSel();
    switch (index)
    {
    case 0:
        model_PCA->load("E:\性别识别数据库—CAS-PEAL\面部训练样本\PCA_Model.xml");
        break;
    case 1:
        model_Fisher->load("E:\性别识别数据库—CAS-PEAL\面部训练样本\Fisher_Model.xml");
        break;
    case 2:
        model_LBP->load("E:\性别识别数据库—CAS-PEAL\面部训练样本\LBP_Model.xml");
        break;
    case 3:
        svm.load("E:\性别识别数据库—CAS-PEAL\面部训练样本\SVM_SEX_Model.txt");
        break;
    default:
        break;
    }

  加载成功后,给出提醒:

MessageBox("初始化完成");

  这里给出起头化函数的完好代码:

void CGenderRecognitionMFCDlg::OnBnClickedButtonInitial()
{
    m_boolInitOK = true;
    cascade = cvLoadHaarClassifierCascade("D:\opencv\sources\data\haarcascades
\haarcascade_frontalface_alt_tree.xml",cvSize(30,30));
    storage = cvCreateMemStorage(0);

    /**********根据用户的选择来加载分类器**********/
    int index = 0;
    index = ((CComboBox*)GetDlgItem(IDC_COMBO_FUNCTION))->GetCurSel();
    switch (index)
    {
    case 0:
        model_PCA->load("E:\性别识别数据库—CAS-PEAL\面部训练样本\PCA_Model.xml");
        break;
    case 1:
        model_Fisher->load("E:\性别识别数据库—CAS-PEAL\面部训练样本\Fisher_Model.xml");
        break;
    case 2:
        model_LBP->load("E:\性别识别数据库—CAS-PEAL\面部训练样本\LBP_Model.xml");
        break;
    case 3:
        svm.load("E:\性别识别数据库—CAS-PEAL\面部训练样本\SVM_SEX_Model.txt");
        break;
    default:
        break;
    }
    MessageBox("初始化完成");
    // TODO: 在此添加控件通知处理程序代码
}

  3、编写性别识别函数

  将性别鉴定识别编写为贰个名称为GenderRecognition(IplImage* img)的函数,将其视作成员函数添加到CGenderRecognitionMFCDlg类中:

ca88编程 13

  然后再向CGenderRecognitionMFCDlg类中增加一个int类型的竹签,用来保存对当前图片的猜测结果(“1”代表男人,“2”代表女子):

ca88编程 14

  接下去初始编写性别识别函数,与后边加载分类器的流水生产线类似,这里同样须求判断客商所选用的艺术的标号,然后调用对应的分类器对输入图片举办预测,可是这里供给先将输入的IplImage类型变量转换为Mat类型变量,代码如下:

    Mat image(img);
    Mat trainImg;
    resize(image,image,Size(92,112));

    /***********根据当前用户选择的方法来使用对应的分类器进行分类**********/
    int index = 0;
    index     = ((CComboBox*)GetDlgItem(IDC_COMBO_FUNCTION))->GetCurSel();
    switch (index)
    {
    case 0:
        {
            m_genderLabel = model_PCA->predict(image);
            break;
        }
    case 1:
        {
            m_genderLabel = model_Fisher->predict(image);
            break;
        }
    case 2:
        {
            m_genderLabel = model_LBP->predict(image);
            break;
        }
    case 3:
        {
            resize(image, trainImg, cv::Size(64,64), 0, 0, INTER_CUBIC);
            HOGDescriptor *hog=new HOGDescriptor(cvSize(64,64),cvSize(16,16),cvSize(8,8),cvSize(8,8), 9);  
            vectordescriptors; 
            hog->compute(trainImg, descriptors,Size(1,1), Size(0,0)); 
            Mat SVMtrainMat =  Mat::zeros(1,descriptors.size(),CV_32FC1);    
            int n=0;    
            for(vector::iterator iter=descriptors.begin();iter!=descriptors.end();iter  )    
            {    
                SVMtrainMat.at(0,n) = *iter;    
                n  ;    
            }  
            m_genderLabel = svm.predict(SVMtrainMat);
            break;
        }
    default:
        {
            break;
        }
    }

  这里供给小心的一些就是在选取SVM进行性别鉴定区别时,一样须要先提取测验样本的HOG特征,参数设置要与事先磨炼时的HOG参数设置一样,具体参见:C 开辟人脸性别识别教程(6)——通过SVM实现性别鉴定分别。同一时间要将测量试验样本先归一化到和练习样本相同的尺寸,这里为92*112。

  4、展现识别结果

  我们统一希图通过一个编写制定框控件(艾德it Control)来显示当前图片的性别鉴定分别结果,即m_genderRecognition为“1”时显得“美男子”,为“2”时显示“美丽的女人”。首先在主分界面上绘制那个控件,并将其ID内定为IDC_EDIT_RecognitionResult。

  然后大家在GenderRecognition()函数中加多结果彰显代码:

    /**********显示识别结果**********/
    if (1 == m_genderLabel)
    {
        GetDlgItem(IDC_EDIT_RESULT)->SetWindowText("帅哥");
    }
    else if(2 == m_genderLabel)
    {
        GetDlgItem(IDC_EDIT_RESULT)->SetWindowText("美女");
    }

  此时性别鉴定分别函数编写成功,这里给出该函数的整体代码:

void CGenderRecognitionMFCDlg::GenderRecognition(IplImage* img)
{
    Mat image(img);
    Mat trainImg;
    resize(image,image,Size(92,112));

    /***********根据当前用户选择的方法来使用对应的分类器进行分类**********/
    int index = 0;
    index     = ((CComboBox*)GetDlgItem(IDC_COMBO_FUNCTION))->GetCurSel();
    switch (index)
    {
    case 0:
        {
            m_genderLabel = model_PCA->predict(image);
            break;
        }
    case 1:
        {
            m_genderLabel = model_Fisher->predict(image);
            break;
        }
    case 2:
        {
            m_genderLabel = model_LBP->predict(image);
            break;
        }
    case 3:
        {
            resize(image, trainImg, cv::Size(64,64), 0, 0, INTER_CUBIC);
            HOGDescriptor *hog=new HOGDescriptor(cvSize(64,64),cvSize(16,16),cvSize(8,8),cvSize(8,8), 9);  
            vectordescriptors; 
            hog->compute(trainImg, descriptors,Size(1,1), Size(0,0)); 
            Mat SVMtrainMat =  Mat::zeros(1,descriptors.size(),CV_32FC1);    
            int n=0;    
            for(vector::iterator iter=descriptors.begin();iter!=descriptors.end();iter  )    
            {    
                SVMtrainMat.at(0,n) = *iter;    
                n  ;    
            }  
            m_genderLabel = svm.predict(SVMtrainMat);
            break;
        }
    default:
        {
            break;
        }
    }

    /**********显示识别结果**********/
    if (1 == m_genderLabel)
    {
        GetDlgItem(IDC_EDIT_RESULT)->SetWindowText("帅哥");
    }
    else if(2 == m_genderLabel)
    {
        GetDlgItem(IDC_EDIT_RESULT)->SetWindowText("美女");
    }
}

  四、调用性别识别函数

  编写完性别识别函数之后,大家就可以筹算调用这么些函数来开展性别鉴定分别了,由于程序的设计是先实行人脸检查测量检验,然后开展性别鉴定识别,因而大家计划在人脸检查评定函数detect_and_draw()中调用那本性别鉴定区别函数。

  1、人脸区域分割

  明显,在展开人脸检查评定之后,我们必要将检查测验到的人脸区域分割出来,再送入GenderRecognition()性别鉴定分别函数中进行分辨,由此大家要求向detect_and_draw()函数中增多人脸区域分割的代码。

  首先,深入分析一下detect_and_draw(IplImage* img)函数中存活变量的意义:

  IplImage*img:为输入的本来图像,必要在那么些本来图像上海展览中心开人脸区域分割;

  IplImage*gray:为灰度化的图像,但gray经过了直方图均衡化的操作,导致其遗失了九华山真面指标性别新闻,由此不可能用其展开性别鉴定识别,那也就表示我们需求再行对原本图像img实行灰度化操作,然后举行私分;

  CvRect* rect:保存了人脸检查实验的结果,供给基于那一个矩形的职分和 尺寸来开展人脸区域分割。

  OK,经过以上解析,大家付出人脸区域分割的代码:

    /**********分割人脸区域**********/
    cvSetImageROI(img,*rect);                //设置图像人脸部分ROI区域
    IplImage* faceImage = cvCreateImage(cvSize(rect->width,rect->width),IPL_DEPTH_8U,1);
    if (img->nChannels = 3)
    {
        cvCvtColor(img,faceImage, CV_BGR2GRAY);//将图像灰度化存放在gray中 
    }
    else
    {
        faceImage = img;
    }
    cvResetImageROI(img);

    /**********性别识别**********/
    GenderRecognition(faceImage);
    cvReleaseImage(&faceImage);

  这里在拓宽区域分割时使用了设置ROI区域的格局,那是OpenCv1.x中的方法,在2.x中的Mat类型中封装了更精简的法子,详见OpenCV中ROI 总括。

  考虑到在拓宽人脸检查实验时会出现检查评定失利的情况,假如大家在人脸检查评定失利的状态下仍坚定不移启用人脸分割及性别鉴定区别程序,程序就能够因为各类变量的未定义而夭折,由此大家这里选用将这段人脸分割、性别鉴其他代码放在if语句中,保障其唯有在人脸检查测量检验成功的动静下才施行,为了有助于我们清理逻辑,这里给出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(i,0) = (float)(r->height * r->width);
        if(i > 0&&max_face.at(i,0) > max_face.at(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));

      /**********分割人脸区域**********/
      cvSetImageROI(img,*rect);                  //设置图像人脸部分ROI区域
      IplImage* faceImage = cvCreateImage(cvSize(rect->width,rect->width),IPL_DEPTH_8U,1);
      if (img->nChannels = 3)
      {
          cvCvtColor(img,faceImage, CV_BGR2GRAY);//将图像灰度化存放在gray中 
      }
      else
      {
          faceImage = img;
      }
      cvResetImageROI(img);

      /**********性别识别**********/
      GenderRecognition(faceImage);
      cvReleaseImage(&faceImage);
    }

    /**********在图像控件上显示图像**********/
    CvvImage cvvImage;
    cvvImage.CopyOf(img);
    cvvImage.DrawToHDC(m_pPicCtlHdc,m_PicCtlRect);
    cvReleaseImage(&gray); 
}

  OK,大功告成:

ca88编程 15

  四、总结

  经过那篇博客之后,能够说小编们的性别鉴定识别MFC程序已经基本成型,具有了图片读取与呈现,人脸检查评定、性别鉴定区别等基本成效,在接下去的博文中大家将介绍怎样举办拍照头录制流的人脸性别识别。不过这里有多少个难点亟需重新重申一下。

  1、分类器类别

  之前大家说程序中用到了三种性别鉴定分别分类器:PCA、Fisher、LBP、SVM。其实这种说法是不下马看花的,这里只是有多种API函数,而从分类器层面旅长独有二种分类器。前边八个真相上都以用的K近邻分类器,只是提取了三种不一致的表征而已。

  2、MFC教程

  在那些程序的付出进程中用到了相当多MFC的有关文化,假使我们希望系统摸底MFC开采的连带注意事项及本事的话,推荐咱们参谋孙鑫先生的MFC录制教程。这一个录制教程相比长,大家有选用性的读书就可以。

  3、增多伊始化实现的指示对话框

  这里我们向“开始化”按键的响应函数中加多了开端化完毕的唤醒对话框,原因是加载分类器的进度供给大概5秒左右的小时,增加一个做到提示对话框会使得程序显得更有提醒性,更协和。

  4、resource.h文件的功能

  resource.h保存了眼前能源(各个空间,图片,字符串)的ID号,须求时大家能够从这些文件中寻觅:

ca88编程 16

 

  5、全局变量

  程序中不引进应用静态的全局变量,会下跌程序的安全性。

经过从前几篇博客的讲课,我们已经成功搭建了MFC应用框架,并贯彻了主导的图像显...

C 开荒人脸性别识别教程(15)——搭建MFC框架运营录像头

  在事先的博文中早已成功了针对图片的人脸性别识别功用,在那篇小说中大家初始引进摄像头设备,为顺序增添第三个职能:录制人脸性别识别。

  一、增多控件

  这里供给新增加多个与摄像人脸性别识别相关的功能控件,一个是“展开摄像”按键(ID为IDC_OpenVideo),二个是“暂停按键”开关。为了方便回退主窗口中的开关控件的数据,这里再度使用一种复用战略,就要摄像识别情势中的“暂停”作用与从前图片文件夹识别格局中的“下一张”功效合併,通过四个开关来支配:

ca88编程 17

  二、CVideoInfo类

ca88编程,  2.1 增多摄像流类

  接下去供给敞开摄像摄像头,将录像头获取的图像实时的来得在主程序的picture控件中。有关OpenCv中的录制头操作本人在C 开拓人脸性别识别教程(4)——OpenCv的人脸检验函数那篇博文中张开了较为详细的牵线。这里大家对摄像头的拉开进行一下小小的包装,就要其宣称为三个类CVideoInfo,那样做的来由首倘诺为着能够方便中期的管理,大家将录像头输出的摄像流、帧图像、帧图像的尺码(宽度和可观)都封装在同三个指标中,方便读取,也便于获取图像的连带属性。

  在VS中切换成类视图窗口,右击工程名,增加类:

ca88编程 18

  钦赐加多类的类型为“C 类”:

ca88编程 19  输入类名CVideoInfo,对应的.h文件和.cpp文件名称系统会自动生成,无一而再,访谈属性暗中认可使用public,单击完结:

ca88编程 20

  此时在类视图下能够见见工程中多了三个名叫CVideoInfo的类:

ca88编程 21

  2.2 编辑CVideoInfo类

  接下去为CVideoInfo加多相应的代码。切换来技术方案能源管理器窗口,会发觉此时工程目录下会多出五个文本,VideoInfo.h和VideoInfo.cpp:

ca88编程 22

  首先编辑类对应的头文件VideoInfo.h,发掘VS已经在头文件中提供了主导的类注脚,并交付了缺省的构造函数和析构函数,大家在这里只需向里面增添若干分子变量就能够,这里大家添加几个成员变量:CvCapture*格式的录像流变量,IplImage*格式的帧图像变量,以及多少个整型变量用以代表帧图像的增进率和惊人:

    CvCapture* m_pCapture;     //用于存储摄像头输入的视频流
    IplImage* m_pFrameImage;   //存储图片

    int m_FrameWidth;          //图片宽度
    int m_FrameHeight;         //图片高度

  最后VideoInfo.h文件中的类声西晋码如下:

#pragma once
#include "opencv2/opencv.hpp"

class CVideoInfo
{
public:

    CvCapture* m_pCapture;     //用于存储摄像头输入的视频流
    IplImage* m_pFrameImage;   //存储图片

    int m_FrameWidth;          //图片宽度
    int m_FrameHeight;         //图片高度

public:
    CVideoInfo(void);          //缺省构造函数
public:
    ~CVideoInfo(void);         //缺省析构函数
};

  至于VideoInfo.cpp,由于VideoInfo类这几天只是肩负图像的存放和显示,未有别的附加的功能,因而在此间只须求做到构造函数对成员变量的伊始化,而析构函数选取系统提供的缺省函数就能够,VideoInfo.cpp文件的代码如下:

#include "StdAfx.h"
#include "VideoInfo.h"

CVideoInfo::CVideoInfo(void)  //缺省构造函数
{
    m_pCapture = NULL;
    m_pFrameImage = NULL; 
}

CVideoInfo::~CVideoInfo(void)//缺省析构函数
{
}

  完结了类的概念之后,须要向CGenderRecognitionMFCDlg类中增多一个VideoInfo*花样的变量m_pVideoInfo用来保存当前的摄像流新闻,当然使用全局变量也足以落成那些职能,可是会是代码变得更目迷五色,不推荐。

ca88编程 23

  在充足变量以前要求先在CGenderRecognitionMFCDlg.h中包蕴一下VideoInfo.h头文件,使得VideoInfo类可知:

ca88编程 24

  接下去就足以标准开始开启摄像头了。

  三、开启摄像头

  双击“张开录制”开关,增加对应的事件管理函数:

ca88编程 25

  首先,推断程序是不是开展了分类器加载开头化:

    if (m_boolInitOK == FALSE)
    {
        MessageBox("请先进行初始化");
        return;
    }

  然后使用cvCreateCameraCapture函数开启摄像头,并将录制流赋值给m_pVideoInfo:

m_pVideoInfo->m_pCapture = cvCreateCameraCapture(0);//创建一个Capture(摄像头)

  注意此时运维程序的话在那句代码会报错,原因是m_pVideoInfo那几个成员变量尚未被分配内部存款和储蓄器空间,由此供给在程序最早运转时手动通过new操作符对其张开内部存款和储蓄器空间的分配,这里将内部存款和储蓄器分配的说话放置在OnInitDialog()那些成员函数中:

    /*********为m_pVideoInfo变量分配内存空间**********/
    m_pVideoInfo = new CVideoInfo;

  四、展现图像

  在录像头捕捉到图像之后,接下去供给将帧图像实时的显得在picture分界面中,达成这一个意义的点子有为数相当多,这里运用电磁照料计时器的主意。即设置三个计时器,每隔一按期间就接触,在相应的回调函数中成就帧图像的显得工作。因而在OnBnClickedButton1Video()函数中供给对停车计时器进行初阶化,单击“张开录像”按键后,就从头接触沙漏,轮询播放摄像头画面:

SetTimer(1,1,NULL);//触发一个计数器,在响应函数中完成图像显示

  有关MFC中电磁料理计时器的施用我们参见网络资料,这里就不再赘述。

  接下去增加机械漏刻新闻响应函数,在类视图中右键单击CGenderRecognitionMFCDlg类,选用属性,弹出属性对话框,在音讯栏中找到WM_TIMESportage,单击左边的下拉箭头,增多音信响应函数OnTimer:

ca88编程 26

  在OnTimer()函数体中造成帧图像的绘图,这里一向付出代码:

void CGenderRecognitionMFCDlg::OnTimer(UINT_PTR nIDEvent)
{
    m_pVideoInfo->m_pFrameImage = cvQueryFrame(m_pVideoInfo->m_pCapture);//得到视频流中的下一帧

    CvvImage cvvImage;
    cvvImage.CopyOf(m_pVideoInfo->m_pFrameImage);
    cvvImage.DrawToHDC(m_pPicCtlHdc,m_PicCtlRect);
    CDialogEx::OnTimer(nIDEvent);
}

  此时运作程序,程序平常化试行,能够在picture分界面上实时的来得录像头采撷的图像,在下一篇博客上校介绍怎样向个中增加性别识其他步骤。

ca88编程 27

  五、注意事项

  1、CVideoInfo类的包装难题

  说实话这里将摄像头输入的摄像流封装为CVideoInfo类的行事措施显示略微大惊小怪,就像一贯在类中增多贰个CvCapture*品种的分子变量就可以不负职责职务,但随着程序的改进,大家只怕要求获得更上一层楼多的录制帧图像的属性值(如尺寸,通道数等等),以至供给在读取帧图像从前对原图像做一些少不了的、固化的开头化操作,如若大家将摄像流封装成CVideoInfo类,就能够方便的以分子函数的花样提交这几个操作、属性值,制止了在前后相继的大框架下增多,也制止了对一一属性值的一再读取。

  2、类成员访问属性难题

  C 中对类成员变量的探访属性推荐设置为private,对成员函数的拜会属性推荐设置为public,並且推荐通过分子函数来访谈成员变量,而非直接读取。

  3、计时器难点

  关于VC中反应计时器的用French Open上有数不清详尽的印证,例如VC放大计时器的用法:SetTimer和Ontimer,这里将时间距离设置为1纳秒,即每一皮秒就刷新一帧,大家能够品味改动别的的时日距离,观看效果。

  4、OnInitDialog函数难点

  OnInitDialog()函数在对话框生成的时候调用,因而在依据对话框的次序中,这么些函数用来进行顺序须求的初叶化操作,近年来结束在我们的工程中这几个函数承担了初始化Combo Box控件、初步化Combo Box控件、为m_pVideoInfo变量分配内部存款和储蓄器空间的天职,随着程序的编撰,还应该有更加多的开头化操作被投入到这么些函数体中。

  5、致歉

  那篇博客是本身在寒假从此写的,中间有二个多月的时日没写过代码,所以思路有一点点零乱,汇报的不是很清晰,大家见谅。

在此前的博文中早已完毕了针对图片的人脸性别识别效能,在那篇小说中大家开...

  旗开得胜。顺遂告竣人脸检測:

  一、人脸检測算法

  从此前的博客中可见。OpenCv在打开人脸检測时须求用到三个静态变量:static CvMemStorage* storage和static CvHaarClassifierCascade* cascade。这里大家将其视作成员变量参预到CGenderRecognitionMFCDlg类中。这里因为static CvMemStorage*和static CvHaarClassifierCascade*这八个类型名在MFC类向导中是敬敏不谢被识其他,由此必需手动插手至CGenderRecognitionMFCDlg类的构造函数中:

  2、字符串的连年:C 字符换行 .

  这里大家起首实现了MFC中的人脸检測成效。但此处存在七个严重的BUG,一是假使客户未单击“起头化”button,直接展开图片,程序会因贫乏需要的初叶化步骤而一向崩溃;二是如上海体育场面所见,OpenCv在开展人脸检測时大概会错误检測出几个矩形。在那之中仅只有三个矩形蕴涵人脸,别的的都是滋扰,须求扩充拍卖,大家就要下一篇博客中牵线怎么着消除这五个BUG。

  然后在“最初化”button的响应函数OnBnClickedButtonInitial()中载入相应的人脸检測器:

  三、编写人脸检測函数  

ca88编程 28

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
CvMemStorage* CGenderRecognitionMFCDlg::storage = NULL;
CvHaarClassifierCascade* CGenderRecognitionMFCDlg::cascade = NULL;

本文由ca88发布,转载请注明来源

关键词: ca88网址 yzc888亚洲城 亚洲城官网