Opencv摄像头实时人脸识别
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Opencv摄像头实时人脸识别
Introduction
网上存在很多人脸识别的文章,这篇文章是我的一个作业,重在通过摄像头实时采集人脸信息,进行人脸检测和人脸识别,并将识别结果显示在左上角。
利用OpenCV 实现一个实时的人脸识别系统,人脸库采用ORL FaceDatabase (网上下载) ,另外在数据库中增加了作业中自带的20张照片和自己利用摄像头采集到的10张照片,系统利用摄像头实时的采集到场景图像,从中检测出人脸用方框标出,并利用提供的数据库进行人脸识别,并在图像左上角显示相匹配的数据库图片。
Method
算法流程分两步,分别是人脸检测和人脸识别。
人脸检测使用的是ViolaJones 人脸检测方法,利用样本的Haar-like 特征进行分类器训练,得到级联boosted 分类器,加载训练好的人脸分类器,利用分类器在视频帧中查找人脸区域;人脸识别利用了局部二进制模式直方图。
Haar-like 特征
Haar-like 特征如下图所示
图1 Haar-like 特征
LBPH
人脸识别常用的方法有三种,Eigenfaces、Fisherfaces 和LBPH;对于高维的图像空间,我们首先应该进行降维操作。
LBP 不把图像看做高维的矢量,而是通过物体的局部特征来描述。
将每个像素和其相邻像素对比形成局部的结构,把该像素看做中心,并以该值对邻接像素做阈值处理,如果临界像素的亮度大于该像素则为1 否则为0,这样每个像素点都可以用一个二进制数来表示,比如一个使用3*3 临界点的LBP 操作如下图所示:
图2 LBP
Implementation识别训练
利用准备好的数据库进行识别训练:首先我们利用Opencv 安装文件中的python脚本create_csv.py建立CSV文件,文件中每条记录如:orl/s13/2.pgm;12,分号之前是图片所存路径,而分号之后是图片的标签号,每一组图片对应着唯一的标签号;之后利用代码中的train_data和read_csv函数对数据集进行训练。
使用到的OpenCV 类和函数有:FaceRecognizer,createLBPHFaceRecognizer
人脸检测
运用Opencv安装文件中的haarcascade_frontalface_alt.xml文
件,使用分类器在视频帧中查找人脸区域,并用绿色方框标出。
用到的OpenCV 类和函数有:
CascadeClassifier,detectMultiScale。
人脸识别
读取训练好的yaml文件,对每个监测到的区域的图像分类,并在视频帧人脸区域上方显示分类结果(分类结果显示为标签和可信度),在左上角显示缩略图。
用到的OpenCV 函数主要有:predict.
Code
1 /*头文件:*/
2 #include "opencv2/core/core.hpp"
3 #include "opencv2/contrib/contrib.hpp"
4 #include "opencv2/highgui/highgui.hpp"
5 #include "opencv2/imgproc/imgproc.hpp"
6 #include "opencv2/objdetect/objdetect.hpp"
7
8 #include <iostream>
9 #include <fstream>
10 #include <sstream>
11 #include <string.h>
12
13 char *FACES_TXT_PATH = "face.txt";
14 char *HARR_XML_PATH =
"haarcascade_frontalface_alt.xml";
15 char *FACES_MODEL = "face.yaml";
16 char *POTRAITS ="potraits.jpg";
17 int DEVICE_ID = 0;
18
19 /*主文件*/
20 #include "config.h"
21
22 using namespace cv;
23 using namespace std;
24 int FACE_WIDHT=92;
25 int FACE_HEIGHT=112;
26 int POTRITE_WIDTH = 100;
27 int POTRITE_HEIGHT = 100;
28
29 static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';') {
30 std::ifstream file(filename.c_str(), ifstream::in);
31 if (!file) {
32 string error_message = "找不到文件,请核对路径";
33 CV_Error(CV_StsBadArg, error_message);
34 }
35 string line, path, classlabel;
36 while (getline(file, line)) {
37 stringstream liness(line);
38 getline(liness, path, separator);
39 getline(liness, classlabel);
40 if(!path.empty()
&& !classlabel.empty()) {
41 images.push_back(imread(path, 0));
42 labels.push_back(atoi(classlabel.c_str()));
43 }
44 }
45
46 }
47
48 /*利用csv文件读取数据集并训练对应模型*/
49 void train_data(String fn_csv)
50 {
51 vector<Mat> images;
52 vector<int> labels;
53 //获取数据集,如果出错抛出异常
54 try {
55 read_csv(fn_csv, images, labels);
56 }
57 catch (cv::Exception& e) {
58 cerr << "打开文件失败\"" << fn_csv << "\". 原因:" << e.msg << endl;
59 exit(1);
60 }
61
62 // 如果训练集数量不够退出
63 if(images.size() <= 1) {
64 string error_message = "训练集图片少于2";
65 CV_Error(CV_StsError, error_message);
66 }
67
68 //训练模型
69 Ptr<FaceRecognizer> model = createLBPHFaceRecognizer();
70 model->train(images, labels);
71 model->save(FACES_MODEL);
72 }
73
74 void show_portrait(Mat &potrait, Mat &frame) {
75 int channels = potrait.channels();
76 int nRows = potrait.rows;
77 int nCols = potrait.cols*channels;
78
79 uchar *p_p, *p_f;
80 for(auto i=0; i<nRows; i++) {
81 p_p = potrait.ptr<uchar>(i);
82 p_f = frame.ptr<uchar>(i);
83 for(auto j=0; j<nCols; j++) {
84 p_f[j*3] = p_p[j];
85 p_f[j*3+1] = p_p[j+1];
86 p_f[j*3+2] = p_p[j+2];
87 }
88 }
89
90 }
91
92 void makePotraitImages(vector<Mat> potraits) {
93 int rows = potraits.size()/6;
94 if(potraits.size()-rows *6>0)rows++;
95 rows *= POTRITE_HEIGHT;
96 int cols = 6*POTRITE_HEIGHT;
97 Mat potrait_s = Mat(rows,cols,CV_8UC3);
98 rows = POTRITE_HEIGHT;
99 cols = POTRITE_WIDTH;
100 uchar *p_ps, *p_p;
101 for(auto i=0; i<potraits.size(); i++) {
102 for(auto j=0; j<rows; j++) {
103 p_ps =
potrait_s.ptr<uchar>(i/6*POTRITE_HEIGHT+j)+3*(i%6) *POTRITE_WIDTH;
104 p_p = potraits[i].ptr<uchar>(j);
105 for(auto k=0; k<cols; k++) {
106 p_ps[k*3] = p_p[k];
107 p_ps[k*3+1] = p_p[k+1];
108 p_ps[k*3+2] = p_p[k+2];
109 }
110 }
111 }
112 imwrite(POTRAITS, potrait_s);
113 }
114
115 void loadPortraits(const string& filename,
vector<Mat>& images, char separator = ';') {
116 string fn_csv = string(FACES_TXT_PATH);
117 std::ifstream file(fn_csv.c_str(), ifstream::in);
118 if (!file) {
119 string error_message = "找不到文件,请核对路径.";
120 CV_Error(CV_StsBadArg, error_message); 121 }
122 string line, path, classlabel;
123 int label(0);
124 while (getline(file, line)) {
125 stringstream liness(line);
126 getline(liness, path, separator);
127 getline(liness, classlabel);
128 if(!path.empty()
&& !classlabel.empty()) {
129 if(atoi(classlabel.c_str()) != label) {
130 Mat potrait = imread(path, 0);
131 resize(potrait,
potrait,Size(POTRITE_WIDTH, POTRITE_HEIGHT));
132 images.push_back(potrait);
133 label = atoi(classlabel.c_str());
134 }
135 }
136 }
137 }
138
139 int main(int argc, const char *argv[]) {
140 // 保存图像和对应标签的向量,要求同一个人的图像必须对应相同的标签
141 string fn_csv = string(FACES_TXT_PATH);
142 string fn_haar = string(HARR_XML_PATH);
143
144 Ptr<FaceRecognizer> model = createLBPHFaceRecognizer();
145 FileStorage model_file(FACES_MODEL, FileStorage::READ);
146 if(!model_file.isOpened()){
147 cout<<"无法找到模型,训练中..."<<endl;
148 train_data(fn_csv);//训练数据集,1表示EigenFace 2表示FisherFace 3表示LBPHFace
149 }
150 model->load(model_file);
151 model_file.release();
152 vector<Mat> potraits;
153 loadPortraits(FACES_MODEL,potraits);
154 makePotraitImages(potraits);
155 CascadeClassifier haar_cascade;
156 haar_cascade.load(fn_haar);
157
158 VideoCapture cap(DEVICE_ID);
159 if(!cap.isOpened()) {
160 cerr << "设备" << DEVICE_ID << "无法打开" << endl;
161 return -1;
162 }
163
164 Mat frame;
165 for(;;) {
166 cap >> frame;
167 if(!frame.data)continue;
168 // 拷贝现有frame
169 Mat original = frame.clone();
170 // 灰度化
171 Mat gray;
172 cvtColor(original, gray, CV_BGR2GRAY); 173 // 识别frame中的人脸
174 vector< Rect_<int> > faces; 175 haar_cascade.detectMultiScale(gray, faces); 176
177 if(faces.size() != 0)
178 {
179 int max_area_rect=0;
180 for(int i = 0; i < 1; i++) {
181 if(faces[i].area() >
faces[max_area_rect].area()){
182 max_area_rect = i;
183 }
184
185 }
186
187 // 顺序处理
188 Rect face_i = faces[max_area_rect]; 189
190 Mat face = gray(face_i);
191 rectangle(original, face_i, CV_RGB(0, 255,0), 1);
192 int pridicted_label = -1;
193 double predicted_confidence = 0.0;
194 model->predict(face, pridicted_label, predicted_confidence);
195 string result_text = format("Prediction = %d confidence=%f", pridicted_label, predicted_confidence);
196 int text_x = std::max(face_i.tl().x - 10, 0); 197 int text_y = std::max(face_i.tl().y - 10, 0); 198 putText(original,result_text, Point(text_x, text_y),FONT_HERSHEY_PLAIN, 1.0, CV_RGB(0,255,0), 2.0);
199 if(pridicted_label >0)
200 show_portrait(potraits[pridicted_label], original);
201 }
202 // 显示结果:
203 imshow("face_recognizer", original);
204
205 char key = (char) waitKey(20);
206 if(key == 32)
207 exit(0);; 208 }
209 return 0;
210 }
Experiment
图3 结果展示
图4 人脸库拼图。