Face detection based on Opencv and MFC-based face-changing applet
1. Background
Opencv has been in contact for a while, whether it is Python or C++, it runs in the console, and uses Opencv's imshow to observe the results. I'm learning MFC recently, and I want to combine face detection and MFC to make a simple face-changing applet.
2. Design
Using a simple button-event mechanism, each button implements a different function. The design of the program panel is as follows:
3. Problems solved
1. The problem of displaying pictures
When Opencv1 is used, it can support drawing directly in the Pic control control of MFC. But after Opencv2, it is no longer supported. For convenience, I found this code from the Internet and directly imported it into the project.
2. The problem of opening the picture
I hope the program can be more friendly, so I abandoned the original way of manually editing the image path in the code, and used the CfileDialog class in MFC to create a new file selection dialog, so as to obtain the file path friendly and easy to operate.
3. String format conversion problem
Cstring to char* can only be converted by the WideCharToMultiByte() function in a Unicode encoding project.
CStringfileinfo=filepathname;
intlen=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);
4. The use of IplImage and Mat
IplImage is a pointer, and Mat is an object, so the assignment of these two types should be noted that the assignment to the IplImage type is actually still the original Image, and defining a new Mat and then assigning it is actually a copy between objects. operate.
5. The use of the sprintf_s function
sprintf_s(result,"Havefound %d faces",faces.size());
If it contains Chinese, there will be garbled characters in the MessageBox, which is related to the encoding. In the Unicode project, try to use English to avoid garbled characters.
6. Vertex coordinate problem of Vector<Rect> type
.tl() is the upper left corner coordinate, type Point
.br() is the coordinate of the lower right corner, and the type is also Point
Note that this is a function call, if you don't add (), you will get an error when compiling
such as error " .x " must have class / struct / union on the left side"
7. Image coordinate system problem
8. CascadeClassifier problem
I don't know if it is related to the version. The cvHarrDetect program under cvCascadeClassifier crashes, but the detectMultiScale under CascadeClassifier runs normally.
4. Operation effect
5. Code
1. See the previous blog post for CvvImage.cpp and CvvImage.h
2. Each button responds to events
voidCChangeFaceDlg::OnBnClickedButton1() { // TODO: Add control notification handler code here CString filter; filter="(file type)(*.*)|*.*||"; CFileDialogdlg(TRUE,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,filter,NULL); if(dlg.DoModal()==IDOK) { filename = dlg.GetFileName(); fileext = dlg.GetFileExt();//File extension 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); //Display image gray_img = cvLoadImage(path,1); delete[] path; DrawPicToHDC(gray_img, IDC_PIC1); } voidCChangeFaceDlg::OnBnClickedButton2() { DrawPicToHDC(gray_img, IDC_PIC2); } voidCChangeFaceDlg::Facedetect(IplImage *img) { // load the classifier 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); //Store the center point of the two faces, only two faces for(unsigned int i=0;i <faces.size();i++) { rectangle(gray,faces[i],RGB(0,255,0),2); } } voidCChangeFaceDlg::OnBnClickedButton3() { // TODO: Add control notification handler code here 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: Add control notification handler code here 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"Please make sure two faces are detected"); } }
6. All codes and projects have been uploaded for review