学习总要从兴趣开始,
自己制作一个利用opencv的分类器来检测人脸,再将检测出的人脸用程序扣图出来,创建一个分类器,
实现不同人的人脸识别,标记出他的名字;
程序可以在这里下载:http://download.csdn.net/download/qq_36576377/10213638
程序效果图:
// RlsbDlg.cpp : 实现文件 // #include "stdafx.h" #include "Rlsb.h" #include "RlsbDlg.h" #include "afxdialogex.h" #include <thread> #include "Psapi.h" #include <io.h> #include <iostream> #include <sstream> #include <fstream> #include <string> #include <opencv2\opencv.hpp> #include <opencv\cv.h> #include <opencv\cv.hpp> #include <map> //#pragma comment(lib,"E:\\opencv\\build\\x86\\vc11\\lib\\opencv_core249.lib") using namespace std; using namespace cv; #ifdef _DEBUG #define new DEBUG_NEW #endif BOOL modelsave=FALSE; BOOL loadover=FALSE; map<int,string> maps; BOOL Close=TRUE; char chPath[261]={0};//程序自身路径; VideoCapture cap; Mat img,sbimg; CascadeClassifier face_cascade; string face_cascade_name; int ctimes=0; VideoWriter writecap; Ptr<FaceRecognizer> model = createEigenFaceRecognizer(); void thread01(); void detectface(Mat mat,CString path,int count,BOOL over); void Createtxt(CString path,CString csInt,int inNub); void findfile(string path,std::vector<std::string> &files,vector<int> &xuhao); static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';') { std::ifstream file(filename.c_str(), ifstream::in); if (!file) { string error_message = "No valid input file was given, please check the given filename."; CV_Error(CV_StsBadArg, error_message); } string line, path, classlabel; Mat tempmat; while (getline(file, line)) { stringstream liness(line); getline(liness, path, separator); getline(liness, classlabel); if (!path.empty() && !classlabel.empty()) { tempmat=imread(path,0); equalizeHist(tempmat,tempmat); normalize(tempmat,tempmat,0,tempmat.rows,NORM_MINMAX,-1,Mat()); images.push_back(tempmat); labels.push_back(atoi(classlabel.c_str())); } } }
//---------得到程序自身路径; DWORD idProcess; char path[261]={0}; GetWindowThreadProcessId(AfxGetMainWnd()->m_hWnd, &idProcess); HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, idProcess); if(hProcess) { HMODULE hMod; DWORD cbNeeded; if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) { GetModuleFileNameEx(hProcess, hMod, path, MAX_PATH); string stringpath; stringpath=path; int pos=0; pos=stringpath.rfind("\\",strlen(path)); if(pos!=stringpath.npos) { CString cspos; cspos.Format("%d",pos); strncpy_s(chPath,path,pos); } } } ::MoveWindow(GetDlgItem(IDC_pic)->m_hWnd,0,0,320,240,1);//
//加载opencv自带的分类器; face_cascade_name.assign(chPath).append("\\haarcascade_frontalface_alt.xml"); if(!face_cascade.load(face_cascade_name)) { MessageBox("无法加载分类器"); exit(0); } HWND hWnd; HWND hParent; namedWindow("img", WINDOW_AUTOSIZE); hWnd = (HWND)cvGetWindowHandle("img"); hParent = ::GetParent(hWnd); ::SetParent(hWnd, GetDlgItem(IDC_pic)->m_hWnd); ::ShowWindow(hParent, SW_HIDE); // TODO: 在此添加额外的初始化代码 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE }
//-----采集图片并保存到当前程序目录 void CRlsbDlg::OnBnClickedButton1() { char myname[10]={0}; ::GetDlgItemText(AfxGetMainWnd()->m_hWnd,IDC_name,myname,20); if(strlen(myname)==0) { MessageBox("请输入要模板人的名字"); return; } GetDlgItem(IDC_BUTTON1)->EnableWindow(0); GetDlgItem(IDC_train)->EnableWindow(0); ctimes=0; CString stPath,csInt; stPath.Format("%s",chPath); if(_access(stPath+"\\s01",0)==-1) ::CreateDirectory(stPath+"\\s1", 0); //stPath+="\\"; int i=0; do { ++i; csInt.Format("s%d",i); } while(_access(stPath+"\\"+csInt,0)!=-1); ::CreateDirectory(stPath+"\\"+csInt, 0); CString saveimgPath=stPath+"\\"+csInt; if(cap.isOpened()) cap.release(); cap.open(0); if(!cap.isOpened()) return; CRect rect; Mat outimg; ::GetClientRect((HWND)GetDlgItem(IDC_pic)->m_hWnd,rect); BOOL overCap=TRUE; while(overCap) { cap>>img; if(!img.data) return; outimg=img.clone(); resize(outimg,outimg,Size(rect.Width(),rect.Height())); imshow("img",outimg); detectface(img,saveimgPath,10,TRUE); if(ctimes>15) { overCap=FALSE; cap.release(); } waitKey(30); } Createtxt(stPath,csInt,i); GetDlgItem(IDC_BUTTON1)->EnableWindow(0); GetDlgItem(IDC_train)->EnableWindow(1); GetDlgItem(IDC_reco)->EnableWindow(0); ::SetDlgItemText(AfxGetMainWnd()->m_hWnd,IDC_stat,"信息录入完毕"); // TODO: 在此添加控件通知处理程序代码 }
//创建txt文件 void Createtxt(CString path,CString csInt,int inNub) { ofstream out; std::vector<std::string> files;//通过容器存储 vector<int> xh; int i=0; findfile(path.GetBuffer(0), files,xh); CString csATpath=path+"\\at.txt"; out.open(csATpath); cout.rdbuf(out.rdbuf()); for (int i = 0;i<files.size();i++) cout<<files[i]<<";"<<xh[i]<<endl; out.close(); ofstream out1; CString listpath=path+"\\list.txt"; out1.open(listpath,ios::app); cout.rdbuf(out1.rdbuf()); char myname[10]={0}; ::GetDlgItemText(AfxGetMainWnd()->m_hWnd,IDC_name,myname,20); cout<<inNub<<";"<<myname<<endl; out1.close(); }
//找图形文件 void findfile(string path,std::vector<std::string> &files,vector<int> &xuhao) { string sss; string csInt="s1"; int i=1; struct _finddata_t filefind; intptr_t hfile =0; std::string s; CString paths; sss.assign(path); do { if ((hfile = _findfirst(s.assign(sss).append("/*.jpg").c_str(), &filefind)) != -1) { do { if (filefind.attrib == _A_SUBDIR) { if(strcmp(filefind.name,".")&&strcmp(filefind.name,"..")) findfile(s.assign(sss).append("/").append(filefind.name), files,xuhao); } else { files.push_back(s.assign(sss).append("/").append(filefind.name)); xuhao.push_back(i); } }while(_findnext(hfile, &filefind) == 0); } ++i; stringstream stream; stream.clear(); stream<<"s"; stream << i; stream >> csInt; }while(_access(sss.assign(path).append("\\").append(csInt).c_str(),0)!=-1); _findclose(hfile); } void detectface(Mat mat,CString path,int count,BOOL over) { std::vector<Rect> faces; Mat frame_gray; Mat writeimg; cvtColor( mat, frame_gray, CV_BGR2GRAY ); equalizeHist( frame_gray, frame_gray ); //-- 多尺寸检测人脸 face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) ); for( int i = 0; i < faces.size(); i++ ) { Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 ); ellipse( mat, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 ); cv::Rect rect(center.x-faces[i].width*0.5,center.y-faces[i].height*0.5,faces[i].width,faces[i].height); //rectangle(img,rect,RGB(0,0,255),5,8,0); Mat faceROI = img(faces[i]); if (faceROI.cols > 30) { resize(faceROI, writeimg, Size(92, 112)); string str = format("%s\\%d.jpg",path.GetBuffer(0),ctimes); if(over==TRUE && ctimes>5) imwrite(str, writeimg); else if(over==FALSE) sbimg=writeimg; ctimes++; } } } void CRlsbDlg::OnBnClickedtrain() { GetDlgItem(IDC_BUTTON1)->EnableWindow(0); GetDlgItem(IDC_train)->EnableWindow(0); GetDlgItem(IDC_reco)->EnableWindow(0); string fn_csv=chPath; fn_csv.append("\\at.txt"); // AfxMessageBox(fn_csv.c_str()); // 2个容器来存放图像数据和对应的标签 vector<Mat> images; vector<int> labels; try { read_csv(fn_csv, images, labels); } catch (cv::Exception& e) { cerr << "Error opening file \"" << fn_csv << "\". Reason: " << e.msg << endl; exit(1); } if (images.size() <= 1) { string error_message = "This demo needs at least 2 images to work. Please add more images to your data set!"; CV_Error(CV_StsError, error_message); } // 下面的几行代码仅仅是从你的数据集中移除最后一张图片 //[gm:自然这里需要根据自己的需要修改,他这里简化了很多问题] //Mat testSample = images[images.size() - 1]; //int testLabel = labels[labels.size()-1 ]; images.pop_back(); labels.pop_back(); // 下面几行创建了一个特征脸模型用于人脸识别, // 通过CSV文件读取的图像和标签训练它。 // T这里是一个完整的PCA变换 //如果你只想保留10个主成分,使用如下代码 // cv::createEigenFaceRecognizer(10); // // 如果你还希望使用置信度阈值来初始化,使用以下语句: // cv::createEigenFaceRecognizer(10, 123.0); // // 如果你使用所有特征并且使用一个阈值,使用以下语句: // cv::createEigenFaceRecognizer(0, 123.0); model->train(images, labels); string xmlpath=chPath; xmlpath.append("\\PCAModel.xml"); if(_access(xmlpath.c_str(),0)!=-1) { DeleteFile(xmlpath.c_str()); ::SetDlgItemText(AfxGetMainWnd()->m_hWnd,IDC_stat,"训练完毕;"); } model->save(xmlpath); GetDlgItem(IDC_BUTTON1)->EnableWindow(1); GetDlgItem(IDC_train)->EnableWindow(0); GetDlgItem(IDC_reco)->EnableWindow(1); modelsave=TRUE; /* Ptr<FaceRecognizer> model1 = createFisherFaceRecognizer(); model1->train(images, labels); model1->save("MyFaceFisherModel.xml"); Ptr<FaceRecognizer> model2 = createLBPHFaceRecognizer(); model2->train(images, labels); model2->save("MyFaceLBPHModel.xml"); */ } void CRlsbDlg::OnBnClickedreco() { ::SetDlgItemText(AfxGetMainWnd()->m_hWnd,IDC_stat,"开始识别模式"); thread task(thread01); task.detach(); GetDlgItem(IDC_BUTTON1)->EnableWindow(0); GetDlgItem(IDC_train)->EnableWindow(0); GetDlgItem(IDC_reco)->EnableWindow(0); GetDlgItem(IDC_strop)->EnableWindow(1); maps.clear(); std::ifstream getmap; string listpath=chPath; string line; string lefstring,rightstring; listpath.append("\\list.txt"); getmap.open(listpath); while(getline(getmap,line)) { stringstream liness(line);//这里采用stringstream主要作用是做字符串的分割 getline(liness, lefstring, ';');//读入图片文件路径以分好作为限定符 getline(liness, rightstring);//读入图片标签,默认限定符 maps.insert(map<int, string> :: value_type(atoi(lefstring.c_str()),rightstring)); } map<int,string>::iterator it; ::SetDlgItemText(AfxGetMainWnd()->m_hWnd,IDC_stat,"Map装载完毕"); //::SendMessage((HWND)(::GetDlgItem(AfxGetMainWnd()->m_hWnd,IDC_stat)),WM_SETTEXT,0,(LPARAM)"111"); if(cap.isOpened()) cap.release(); cap.open(0); if(!cap.isOpened()) return; CRect rect; Mat outimg; ::GetClientRect((HWND)GetDlgItem(IDC_pic)->m_hWnd,rect); Close=TRUE; int oldpredict=0,b=0; while(Close) { cap>>img; if(!img.data) return; outimg=img.clone(); resize(outimg,outimg,Size(rect.Width(),rect.Height())); // normalize(img , img , 1.0,cv::NORM_L2); /*Mat img2=img.clone(); Mat img3; cvtColor(img2,img2,CV_RGB2GRAY); imshow("gray",img2); img3=img2.clone(); equalizeHist(img2,img2); imshow("直方图增强",img2); normalize(img2,img2,0,img2.rows,NORM_MINMAX,-1,Mat()); imshow("直方图增强-->归一",img3); equalizeHist(img3,img3); imshow("直方图--归一--直方图",img3);*/ imshow("img",outimg); if(sbimg.data) resize(sbimg,sbimg,Size(1,1)); detectface(img,"111",10,FALSE); if(loadover) if(sbimg.cols>5) { cvtColor(sbimg,sbimg,CV_RGB2GRAY); equalizeHist(sbimg,sbimg); normalize(sbimg,sbimg,0,sbimg.rows,NORM_MINMAX,-1,Mat()); int predictedLabel = model->predict(sbimg); if(oldpredict!=predictedLabel) { b=0; oldpredict=predictedLabel; } else b++; if(b>11) for(it=maps.begin();it!=maps.end();++it) { if(predictedLabel==it->first) { ::SetDlgItemText(AfxGetMainWnd()->m_hWnd,IDC_result,it->second.c_str()); b=0; } } ::SetDlgItemText(AfxGetMainWnd()->m_hWnd,IDC_stat,"识别中"); } waitKey(30); } } void CRlsbDlg::OnBnClickedButton2() { if(cap.isOpened()) cap.release(); GetDlgItem(IDC_BUTTON1)->EnableWindow(1); GetDlgItem(IDC_train)->EnableWindow(0); GetDlgItem(IDC_reco)->EnableWindow(1); // TODO: 在此添加控件通知处理程序代码 } void CRlsbDlg::OnBnClickedstrop() { Close=FALSE; if(cap.isOpened()) cap.release(); GetDlgItem(IDC_BUTTON1)->EnableWindow(1); GetDlgItem(IDC_train)->EnableWindow(0); GetDlgItem(IDC_reco)->EnableWindow(1); ::SetDlgItemText(AfxGetMainWnd()->m_hWnd,IDC_stat,"已停止视频"); } BOOL CRlsbDlg::DestroyWindow() { // TODO: 在此添加专用代码和/或调用基类 if(cap.isOpened()) cap.release(); return CDialogEx::DestroyWindow(); } void CRlsbDlg::OnCancel() { // TODO: 在此添加专用代码和/或调用基类 if(cap.isOpened()) cap.release(); CDialogEx::OnCancel(); } void thread01() { string sbpath; sbpath=chPath; sbpath.append("\\PCAModel.xml"); char *fs=NULL; if(modelsave==FALSE) model->load(sbpath); loadover=TRUE; } void CRlsbDlg::OnBnClickedload() { Close=FALSE; if(cap.isOpened()) cap.release(); GetDlgItem(IDC_BUTTON1)->EnableWindow(1); GetDlgItem(IDC_train)->EnableWindow(0); GetDlgItem(IDC_reco)->EnableWindow(1); ::SetDlgItemText(AfxGetMainWnd()->m_hWnd,IDC_stat,"加载视频"); CString strFile = _T(""); CFileDialog dlgFile(TRUE, NULL, NULL, OFN_HIDEREADONLY, _T("影像文件 (*.avi)|*.avi|Mp4 Files (*.mp4)|*.mp4||"), NULL); if (dlgFile.DoModal()) strFile = dlgFile.GetPathName(); cap.open(strFile.GetBuffer(0)); if(!cap.isOpened()) {MessageBox("没有文件");return;} Close=TRUE; while(Close) { if(cap.read(img)) resize(img,img,Size(320,240)); else { img.create(Size(320,240),CV_8UC1); putText(img,"OVER",Point(img.cols/2,img.rows/2),FONT_HERSHEY_SIMPLEX,1,RGB(255,255,0),3,8); imshow("img",img); break;} imshow("img",img); waitKey(33); } if(cap.isOpened()) cap.release(); } void CRlsbDlg::OnBnClickedsave() { CTime t=CTime::GetCurrentTime(); CString savepath; savepath.Format("%s\\%d-%d-%d.avi",chPath,t.GetHour(),t.GetMinute(),t.GetSecond()); if(!cap.isOpened()) cap.open(0); if(!cap.isOpened()) { MessageBox("摄像头打开失败"); return; } Close=TRUE; int ww = static_cast<int>(cap.get(CV_CAP_PROP_FRAME_WIDTH)); int hh = static_cast<int>(cap.get(CV_CAP_PROP_FRAME_HEIGHT)); double r = cap.get(CV_CAP_PROP_FPS); writecap.open(savepath.GetBuffer(0), CV_FOURCC('M', 'J', 'P', 'G'), 25.0, Size(640, 480)); while(Close) { if(cap.read(img)) { writecap<<img; resize(img,img,Size(320,240)); imshow("img",img); //writecap.write(img); } else break; waitKey(33); } } void CRlsbDlg::OnBnClickedstoprecord() { Close=FALSE; cap.release(); writecap.release(); }