MFC点击按钮打开文件选择对话框并获取图片

人脸检测之基于Opencv和MFC创作的换脸小程序

1.   背景

Opencv已经接触了有段日子了,无论是Python还是C++,都在控制台内运行,使用Opencv的imshow观察结果。最近在学习MFC,突发奇想地希望把人脸检测和MFC结合起来,制作一个简单地换脸小程序。

2.   设计

采用简单的按钮-事件机制,每个按钮实现不同的功能。程序面板设计如下图:

3.   解决的问题

1.  显示图片的问题

Opencv1的时候,可以支持直接在MFC的Pic control控件内绘图。但是在Opencv2以后,就不再支持了,为了方便,我从网上找到了这段代码直接导入工程使用。

2.  打开图片的问题

我希望程序能够友好一些,所以摒弃了原来在代码内手工编辑图片路径的方式,使用MFC中的CfileDialog类来新建文件选择对话框,从而友好地获取文件路径,方便了操作。

3.  字符串格式转换问题

Cstring转char*,在Unicode编码方式地工程里,只能采用WideCharToMultiByte()函数进行转换。

CStringfileinfo=filepathname;

    intlen=WideCharToMultiByte(CP_ACP,0,fileinfo,-1,NULL,0,NULL,NULL); 

    char*path=newchar[len+1]; 

    WideCharToMultiByte(CP_ACP,0,fileinfo,-1,path,len,NULL,NULL); 

4.  IplImage和Mat的使用问题

IplImage是指针,而Mat是对象,所以这两种类型的赋值要注意,给IplImage类型赋值实际上仍是原来的Image,而新定义一个Mat再给其赋值实际上就是进行了对象之间的拷贝操作。

5.  sprintf_s函数的使用问题

sprintf_s(result,"Havefound %d faces",faces.size());

如果含有中文,那么MessageBox时会出现乱码,这跟编码有关,再Unicode的工程内,尽量使用英文以避免乱码。

6.  Vector<Rect>类型的顶点坐标问题

.tl()是时左上角坐标,类型Point

.br()是右下角坐标,类型也是Point

注意这是个函数调用,不加()的话编译报错

error.x”的左边必须有类/结构/联合”

7.  image的坐标系问题

8.  CascadeClassifier分类器问题

不知道是不是跟版本有关,使用cvCascadeClassifier下的cvHarrDetect程序崩溃,而使用CascadeClassifier下的detectMultiScale则正常运行。

4.   运行效果




5.   代码

1.  CvvImage.cpp和CvvImage.h见上一篇博文

2.  各个按钮响应事件

voidCChangeFaceDlg::OnBnClickedButton1()
{
        // TODO: 在此添加控件通知处理程序代码
        CString filter; 
        filter="(文件类型)(*.*)|*.*||"; 
        CFileDialogdlg(TRUE,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,filter,NULL); 
        if(dlg.DoModal()==IDOK) 
        { 
 
                 filename = dlg.GetFileName();
                 fileext = dlg.GetFileExt();//文件扩展名
                 filepathname =dlg.GetPathName();
                 //MessageBox(str); 
        }
        CString fileinfo = filepathname;
        int len=WideCharToMultiByte(CP_ACP,0,fileinfo,-1,NULL,0,NULL,NULL); 
        char *path =new char[len +1]; 
        WideCharToMultiByte(CP_ACP,0,fileinfo,-1,path,len,NULL,NULL); 
        //MessageBox(fileinfo);
        if(image) cvReleaseImage(&image);
        image = cvLoadImage(path,1); //显示图片
        gray_img = cvLoadImage(path,1);
        delete[] path; 
        DrawPicToHDC(gray_img, IDC_PIC1);
}
 
 
voidCChangeFaceDlg::OnBnClickedButton2()
{
 
        DrawPicToHDC(gray_img, IDC_PIC2);
}
voidCChangeFaceDlg::Facedetect(IplImage *img)
{
        //加载分类器
        CascadeClassifier face_cascade; 
        face_cascade.load("haarcascade_frontalface_alt.xml");
        Mat gray = Mat (img);
 
        face_cascade.detectMultiScale(gray,faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
        char result[200]={0};
        sprintf_s(result,"Have found %dfaces",faces.size());
        CString str(result);
        MessageBox(str);
        //存放两个脸的中心点,仅限两张脸
        for(unsigned int i=0;i <faces.size();i++)
        {
                 rectangle(gray,faces[i],RGB(0,255,0),2);
        }
 
}
 
 
voidCChangeFaceDlg::OnBnClickedButton3()
{
        // TODO: 在此添加控件通知处理程序代码
        gray = Mat(gray_img);
        draw = Mat(image);
        cvtColor(gray,gray,CV_BGR2GRAY);
        //imshow("gray",gray);
        //waitKey(0);
        *gray_img = IplImage(gray);
        Facedetect(gray_img);
}
 
 
voidCChangeFaceDlg::OnBnClickedButton4()
{
        // TODO: 在此添加控件通知处理程序代码
        Point centers[2];
        if(faces.size()==2)
        {
                 int h[2]={0,0};int w[2]={0,0};
                 Mat tmp_img[2];
                 for(unsigned int i=0;i <faces.size();i++)
                 {
                         /*rectangle(draw,faces[i],RGB(0,255,0),2);*/
                         centers[i] =(Point((faces[i].tl().x+faces[i].br().x)/2,(faces[i].tl().y+faces[i].br().y)/2));
                         h[i] =-faces[i].tl().y+faces[i].br().y;
                         w[i] =-faces[i].tl().x+faces[i].br().x;
                         tmp_img[i] =Mat::zeros(h[i],w[i],draw.type());
                 }
                 double x1[2],y1[2];
                 x1[0] = centers[1].x-w[0]/2.0;
                 y1[0] = centers[1].y-h[0]/2.0;
                 x1[1] = centers[0].x-w[1]/2.0;
                 y1[1] = centers[0].y-h[1]/2.0;
 
                 for(int i=0;i<2;i++)
                 {
                         for(intk=0,n=y1[i];k<tmp_img[i].rows;k++,n++)
                         {
                                  for(intl=0,m=x1[i];l<tmp_img[i].cols;l++,m++)
                                  {
                                          for(intc=0;c<3;c++)
                                          {
                                                  tmp_img[i].at<Vec3b>(k,l)[c]= draw.at<Vec3b>(n,m)[c];
                                          }
                                  }
                         }
                 }
                 for(int i=0,j=1;i<2;i++,j--)
                 {
                         for(intk=0,n=y1[i];k<tmp_img[j].rows;k++,n++)
                         {
                                  for(intl=0,m=x1[i];l<tmp_img[j].cols;l++,m++)
                                  {
                                          for(intc=0;c<3;c++)
                                          {
                                                  draw.at<Vec3b>(n,m)[c]= tmp_img[j].at<Vec3b>(k,l)[c];
                                          }
                                  }
                         }
                 }
                 /*imshow("one",tmp_img[0]);
                 imshow("two",tmp_img[1]);
                 waitKey(0);*/
                 *image = IplImage(draw);
                 DrawPicToHDC(image, IDC_PIC2);
        }else
        {
                 MessageBox(L"请保证检测到了两张脸");
        }
}


6.   全部代码、工程已上传待审核

猜你喜欢

转载自blog.csdn.net/gao_summer_cola/article/details/73805085