定义一个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;
}