学习总要从兴趣开始,
自己制作一个利用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();
}