您的位置:首页 > 移动开发 > 微信开发

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

2017-06-27 17:09 561 查看
人脸检测之基于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见上一篇博文

 


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

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.   全部代码、工程已上传待审核

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: