人脸检测之基于Opencv和MFC创作的换脸小程序
2017-06-27 17:09
561 查看
人脸检测之基于Opencv和MFC创作的换脸小程序
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);
如果含有中文,那么MessageBox时会出现乱码,这跟编码有关,再Unicode的工程内,尽量使用英文以避免乱码。
.br()是右下角坐标,类型也是Point
注意这是个函数调用,不加()的话编译报错
如error“.x”的左边必须有类/结构/联合”
{
// 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"请保证检测到了两张脸");
}
}
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. 全部代码、工程已上传待审核
相关文章推荐
- SmileyFace——基于OpenCV的人脸人眼检测、面部识别程序
- 基于opencv和QT的人脸(人眼)检测程序
- 基于opencv的人脸检测程序
- 基于OPenCV和MFC的读图程序
- 在fedora15的环境下编译与安装opencv,并测试人脸检测程序
- 基于OpenCV读取摄像头进行人脸检测和人脸识别
- opencv参考手册里面有个 [人脸检测] 的程序
- OpenCV 实践程序12——用分类器对视频进行人脸检测
- 基于OPenCV和MFC的读图程序
- 如何使基于OpenCV库的人脸检测系统在其它机器上运行
- 基于OpenCV的读取摄像头实现单个人脸验证MFC程序
- 基于opencv的人脸检测的web应用
- 基于QT和OpenCV的人脸检测识别系统(2)
- OpenCV学习笔记(25)基于MFC和OpenCV的摄像机定标与立体匹配测试程序(20140505更新)
- 基于OpenCV读取摄像头进行人脸检测和人脸识别
- 基于OpenCV+MFC的AVI视频文件读取及运动检测
- (学习笔记二)——基于opencv人脸检测原理及实现
- 【MFC基础入门】基于Adaboost算法的车牌检测在OpenCV上的研究与实现
- 基于opencv人脸检测原理及实现
- OpenCV 实践程序14——图片中人脸检测