基于Opencv的人脸识别

文章目录

  • 前言
  • 一、对象检测初始化
  • 二、获取样本
  • 三、读取样本
  • 四、训练数据
  • 五、识别人脸
  • 六、完整代码


前言

人脸识别算法用的是Eigenface算法。 Eigenface算法原理:计算平均脸->计算协方差矩阵->计算特征值->计算特征矩阵->得到特征脸->将图片与特征脸对比识别人脸。

一、对象检测初始化

定义一个CascadeClassifier对像来检测人脸,先使用load方法初始化,初始化时要用到haar的特征人脸识别分类器。

string haar_face_datapath = "C:/opencv/build/etc/haarcascades/haarcascade_frontalface_alt_tree.xml";//检测人脸
CascadeClassifier faceDetector;//CascadeClassifier对象检测
faceDetector.load(haar_face_datapath);//初始化

二、获取样本

先使用VideoCapture捕捉摄像头中的人脸,将从摄像头中得到的源图像存储到Mat格式的变量中,然后使用detectMultiScale进行多尺度目标检测,将源图像中的人脸识别出来,并用Rect类型的vector存储检测出来的人脸的矩形轮廓。
将检测出来的人脸使用resize函数,按照矩形轮廓截取,并使用imwrite保存下来。
接下来是训练和识别人脸,我将上一步检测出来的人脸,全部按照路径加人物编号的方式存储到了一个csv文件中,方便读取。

VideoCapture capture(0);//0表示打开摄像头,如果是路径表示读取视频
if (!capture.isOpened())
{
	cout << "could not open camera" << endl;
	return -1;
}
Mat frame;
vector<Rect> faces;//Rect矩形坐标
int count = 0;//计算人脸数
while (capture.read(frame))//read按帧读取图像,保存到frame中
{
	flip(frame, frame, 1);//flip用于反转图像,参数一:原始图像,参数二:变换后的图像,参数三:反转模式,1表示水平翻转
	//detectMultiScale进行多尺度目标检测,frame摄像头得出来的源图像,faces检测出的物体的边缘
	faceDetector.detectMultiScale(frame, faces, 1.1,1,0,Size(100,120),Size(380,400));
	for (int i = 0; i < faces.size(); i++)
	{
		if (count % 10 == 0)
		{
			Mat dst;
			resize(frame(faces[i]), dst, Size(100, 100));//调整图片大小。frame(faces[i])重载"()"操作符函数
			imwrite(format("C:/Users/18218/source/repos/facerecog_01/outimage/face_%d.jpg",count),dst);
		}
		rectangle(frame, faces[i], Scalar(0, 0, 255), 2, 8, 0);//画红色矩形框
	}
	imshow("camera-demo", frame);
	char c = waitKey(10);//waitKey(10)表示延时10ms切换到下一帧图像
	if (c == 27)//esc键对应的ASCLL码是27
		break;
	count++;
}
capture.release();

三、读取样本

定义一个ifstream类型的变量将csv中的人脸数据,getline逐行全部读取出来,并将图片存储到vector类型的images变量中,将编号存储到vector类型的labels变量中,编号用来区分不同的人,编号相同,说明是同一个人脸。

string filename = string("C:/Users/18218/source/repos/facerecog_01/outimage/image.csv");
ifstream file(filename.c_str(), ifstream::in);
if (!file)
{
	printf("could not load file\n");
	return -1;
}
string line, path, classlabel;
vector<Mat> images;
vector<int> labels;
char separator = ';';
while (getline(file, line))//逐行读取csv文件
{
	stringstream liness(line);//stringstream流的输入输出操作
	getline(liness, path, separator);
	getline(liness, classlabel);
	if (!path.empty() && !classlabel.empty())
	{
		//printf("path:%s\n", path.c_str());
		images.push_back(imread(path, 0));//将图片装到images容器中
		labels.push_back(atoi(classlabel.c_str()));//atoi将字符串转化为整形,c_str将string类转化为char*类
	}
}

if (images.size() < 1 || labels.size() < 1)
{
	printf("invalid image path\n");
	return -1;
}

Mat testSample = images[images.size() - 1];//最后一张图
int testLabel = labels[labels.size() - 1];
images.pop_back();
images.pop_back();

四、训练数据

定义一个Ptr类型的model指针变量用于训练数据,这里用到了EigenFace特征脸算法。先使用model->train(images, labels)训练数据,然后是model的predict方法用来识别任意一张人脸,看其返回的人脸编号是否是正确的,验证数据训练结果。

Ptr<BasicFaceRecognizer> model = EigenFaceRecognizer::create();
model->train(images, labels);

五、识别人脸

接下来就是用摄像头实时识别人脸。首先还是要先检测人脸再识别人脸,所以还是要先用到CascadeClassifier对象检测和haar。获取摄像头中的画面,然后detectMultiScale进行多尺度目标检测,将检测出来的人脸用predict方法预测其编号,看是哪张人脸。然后根据不同编号用putText函数输出该人脸姓名。

VideoCapture capture(0);//0表示打开摄像头,如果是路径表示读取视频
if (!capture.isOpened())
{
	cout << "could not open camera" << endl;
	return -1;
}
Mat frame;
namedWindow("face-recognition", CV_WINDOW_AUTOSIZE);
vector<Rect> faces;
Mat dst;
while (capture.read(frame))
{
	flip(frame, frame, 1);//flip用于反转图像,参数一:原始图像,参数二:变换后的图像,参数三:反转模式,1表示水平翻转
	faceDetector.detectMultiScale(frame, faces, 1.1, 1, 0, Size(80, 100), Size(380, 400));
	for (int i = 0; i < faces.size(); i++)
	{
		Mat roi = frame(faces[i]);
		cvtColor(roi, dst, COLOR_BGR2GRAY);//传进去的是灰度图像,所以要处理下
		resize(dst, testSample, testSample.size());//将从摄像头中获取的人脸图像大小调整为样本大小,并存储到testSample
		int label = model->predict(testSample);
		rectangle(frame, faces[i], Scalar(255, 0, 0), 2, 8, 0);
		//1是image.csv中每行最后一个数,代表是目标人脸			
		putText(frame, format("I'm %s", (label == 1 ? "张三" : "Unkonw")), faces[i].tl(), FONT_HERSHEY_PLAIN, 1.0, Scalar(0, 0, 255), 2, 8);	
	}
	imshow("face-recognition", frame);
	char c = waitKey(10);//waitKey(10)表示延时10ms切换到下一帧图像
	if (c == 27)//esc键对应的ASCLL码是27
		break;
}

六、完整代码

#include "pch.h"
#include<opencv2/opencv.hpp>
#include<opencv2/face.hpp>
#include<iostream>

using namespace cv;
using namespace cv::face;
using namespace std;

string harr_face_datapath= "C:/opencv/build/etc/haarcascades/haarcascade_frontalface_alt_tree.xml";//检测人脸
int main(int argc, char** argv)
{
	string filename = string("C:/Users/18218/source/repos/facerecog_01/outimage/image.csv");
	ifstream file(filename.c_str(), ifstream::in);
	if (!file)
	{
		printf("could not load file\n");
		return -1;
	}
	string line, path, classlabel;
	vector<Mat> images;
	vector<int> labels;
	char separator = ';';
	while (getline(file, line))//逐行读取csv文件
	{
		stringstream liness(line);//stringstream流的输入输出操作
		getline(liness, path, separator);
		getline(liness, classlabel);
		if (!path.empty() && !classlabel.empty())
		{
			//printf("path:%s\n", path.c_str());
			images.push_back(imread(path, 0));//将图片装到images容器中
			labels.push_back(atoi(classlabel.c_str()));//atoi将字符串转化为整形,c_str将string类转化为char*类
		}
	}

	if (images.size() < 1 || labels.size() < 1)
	{
		printf("invalid image path\n");
		return -1;
	}
	Mat testSample = images[images.size() - 1];//最后一张图
	int testLabel = labels[labels.size() - 1];
	images.pop_back();
	images.pop_back();

	//训练数据
	//Ptr model = createEigenFaceRecognizer();
	Ptr<BasicFaceRecognizer> model = EigenFaceRecognizer::create();
	model->train(images, labels);

	CascadeClassifier faceDetector;//CascadeClassifier对象检测
	faceDetector.load(harr_face_datapath);//初始化

	VideoCapture capture(0);//0表示打开摄像头,如果是路径表示读取视频
	if (!capture.isOpened())
	{
		cout << "could not open camera" << endl;
		return -1;
	}
	Mat frame;
	namedWindow("face-recognition", CV_WINDOW_AUTOSIZE);
	vector<Rect> faces;
	Mat dst;
	while (capture.read(frame))
	{
		flip(frame, frame, 1);//flip用于反转图像,参数一:原始图像,参数二:变换后的图像,参数三:反转模式,1表示水平翻转
		faceDetector.detectMultiScale(frame, faces, 1.1, 1, 0, Size(80, 100), Size(380, 400));
		for (int i = 0; i < faces.size(); i++)
		{
			Mat roi = frame(faces[i]);
			cvtColor(roi, dst, COLOR_BGR2GRAY);//传进去的是灰度图像,所以要处理下
			resize(dst, testSample, testSample.size());//将从摄像头中获取的人脸图像大小调整为样本大小,并存储到testSample
			int label = model->predict(testSample);
			rectangle(frame, faces[i], Scalar(255, 0, 0), 2, 8, 0);
			//1是image.csv中每行最后一个数,代表是目标人脸			
			putText(frame, format("I'm %s", (label == 1 ? "张三" : "Unkonw")), faces[i].tl(), FONT_HERSHEY_PLAIN, 1.0, Scalar(0, 0, 255), 2, 8);	
		}
		imshow("face-recognition", frame);
		char c = waitKey(10);//waitKey(10)表示延时10ms切换到下一帧图像
		if (c == 27)//esc键对应的ASCLL码是27
			break;
	}

	waitKey(0);
	return 0;
}

你可能感兴趣的:(opencv,人脸识别)