1.准备训练数据
网络上下载(训练数据量大时,通过爬虫获取)目标的图片:

运用以下代码将原图中的
人脸头像识别、提取、调整大小(这里是150*200),并分别保存。
运行环境:win7 64+VS2013+openCV3.1。
(PS:抱怨下vs和opencv的版本密切相关,注意安装配置)


复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86#include <opencv2opencv.hpp> #include <iostream> #include <stdio.h> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/opencv.hpp> #include <opencv2/imgproc/types_c.h> #include <opencv2/videoio/videoio_c.h> #include <opencv2/highgui/highgui_c.h> using namespace std; using namespace cv; /** Function Headers */ void detectAndDisplay(Mat frame); /** Global variables */ String face_cascade_name = "F:\Downloads\opencv_build\install\etc\haarcascades\haarcascade_frontalface_default.xml"; String eyes_cascade_name = "F:\Downloads\opencv_build\install\etc\haarcascades\haarcascade_eye_tree_eyeglasses.xml"; CascadeClassifier face_cascade; //定义人脸分类器 CascadeClassifier eyes_cascade; //定义人眼分类器 String window_name = "Capture - Face detection"; /** @function main */ int main(void) { //-- 1. Load the cascades if (!face_cascade.load(face_cascade_name)){ printf("--(!)Error loading face cascaden"); return -1; }; if (!eyes_cascade.load(eyes_cascade_name)){ printf("--(!)Error loading eyes cascaden"); return -1; }; //-- 2. 遍历原图像文件夹 vector<String> files; glob("D:\training\liudh_before\*.jpg", files, true); //-- 3. 识别、提取,并保存头像至新文件夹。图片均调整为150x200像素 for (int i = 0; i < files.size(); i++) { //Image processing Mat img = imread(files[i]); //读取文件 cout << files[i] << 'n'; detectAndDisplay(img); //提取头像 waitKey(1000); } } /** @function detectAndDisplay */ void detectAndDisplay(Mat frame) { static int count = 0; std::vector<Rect> faces; Mat frame_gray; Mat MyFace; cvtColor(frame, frame_gray, COLOR_BGR2GRAY); //equalizeHist(frame_gray, frame_gray); //imshow("2", frame_gray); //-- Detect faces face_cascade.detectMultiScale(frame_gray, faces, 1.1); for (size_t i = 0; i < faces.size(); i++) //人脸数目 { Mat faceROI = frame_gray(faces[i]); rectangle(frame, faces[i], Scalar(255, 0, 0), 2, 8, 0); if (faceROI.cols > 80){ resize(faceROI, MyFace, Size(150, 200)); string str = format("D:\training\liudh\MyFcae%d.jpg", count); cout << " 保存图片" << count<<endl; imwrite(str, MyFace); imshow("ii", MyFace); } count++; } //-- Show what you got namedWindow(window_name, 2); imshow(window_name, frame); }
2.制作标签文件CSV
进入命令行,输入命令 di /b/s *.pgm *jpg >at.txt

会在训练数据文件夹下生成一个at.txt文件,但这文件内只有数据,没有标签。(笨办法是将数据拷贝到execl表格中生成标签)
最终生成文件内容如下所示:

也可以通过create_csv.py制作标签(注意修改文件中的目录路径)
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53#!/usr/bin/env python import sys import os.path # This is a tiny script to help you creating a CSV file from a face # database with a similar hierarchie: # # philipp@mango:~/facerec/data/at$ tree # . # |-- README # |-- s1 # | |-- 1.pgm # | |-- ... # | |-- 10.pgm # |-- s2 # | |-- 1.pgm # | |-- ... # | |-- 10.pgm # ... # |-- s40 # | |-- 1.pgm # | |-- ... # | |-- 10.pgm # if __name__ == "__main__": #if len(sys.argv) != 2: # print "usage: create_csv <base_path>" # sys.exit(1) #BASE_PATH=sys.argv[1] BASE_PATH="D:/att_faces" SEPARATOR=";" fh = open("D:/att_faces/at.txt",'w') label = 1 for dirname, dirnames, filenames in os.walk(BASE_PATH): for subdirname in dirnames: subject_path = os.path.join(dirname, subdirname) for filename in os.listdir(subject_path): abs_path = "%s/%s" % (subject_path, filename) #print "%s%s%d" % (abs_path, SEPARATOR, label) fh.write(abs_path) fh.write(SEPARATOR) fh.write(str(label)) fh.write("n") label = label + 1 fh.close()
3. 训练模型
EigenFace和FisherFace的训练图像和测试图像都必须是灰度图,而且是经过归一化裁剪过的。
1.运用alt.txt文件,加载训练数据;提取数据和标签
2.根据FaceRecognizer三种训练模型进行训练;
3.保存训练数据及模型(xml)
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148//#include "stdafx.h" #include <opencv2/opencv.hpp> #include <iostream> #include <fstream> #include <sstream> #include <math.h> #include <opencv2/face.hpp> #include <opencv2/face/facerec.hpp> #include <iostream> #include <stdio.h> #include "opencv2/core.hpp" #include "opencv2/core/utility.hpp" #include "opencv2/core/ocl.hpp" #include "opencv2/imgcodecs.hpp" #include "opencv2/highgui.hpp" #include "opencv2/features2d.hpp" #include "opencv2/calib3d.hpp" #include "opencv2/imgproc.hpp" #include"opencv2/flann.hpp" #include"opencv2/xfeatures2d.hpp" #include"opencv2/ml.hpp" #include"opencv2/face.hpp" #include"opencv2/face/facerec.hpp" #include"opencv2/objdetect.hpp" using namespace cv; using namespace std; using namespace face; static Mat norm_0_255(InputArray _src) { Mat src = _src.getMat(); // 创建和返回一个归一化后的图像矩阵: Mat dst; switch (src.channels()) { case1: cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC1); break; case3: cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC3); break; default: src.copyTo(dst); break; } return dst; } //使用CSV文件去读图像和标签,主要使用stringstream和getline方法 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; while (getline(file, line)) { stringstream liness(line); getline(liness, path, separator); getline(liness, classlabel); if (!path.empty() && !classlabel.empty()) { images.push_back(imread(path, 0)); labels.push_back(atoi(classlabel.c_str())); } } } int main() { //读取你的CSV文件路径. //string fn_csv = string(argv[1]); string fn_csv = "D:\training\at.txt"; // 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); Ptr <FaceRecognizer> model = createEigenFaceRecognizer(10); model->train(images, labels); model->save("MyFacePCAModel.xml"); Ptr <FaceRecognizer> model1 = createFisherFaceRecognizer(10); model1->train(images, labels); model1->save("MyFaceFisherModel.xml"); Ptr <FaceRecognizer> model2 = createLBPHFaceRecognizer(10); model2->train(images, labels); model2->save("MyFaceLBPHModel.xml"); // 下面对测试图像进行预测,predictedLabel是预测标签结果 int predictedLabel = model->predict(testSample); int predictedLabel1 = model1->predict(testSample); int predictedLabel2 = model2->predict(testSample); // 还有一种调用方式,可以获取结果同时得到阈值: // int predictedLabel = -1; // double confidence = 0.0; // model->predict(testSample, predictedLabel, confidence); string result_message = format("Predicted class = %d / Actual class = %d.", predictedLabel, testLabel); string result_message1 = format("Predicted class = %d / Actual class = %d.", predictedLabel1, testLabel); string result_message2 = format("Predicted class = %d / Actual class = %d.", predictedLabel2, testLabel); cout << result_message << endl; cout << result_message1 << endl; cout << result_message2 << endl; while (1); //waitkey只对imshow有效 //if (waitKey(10) == 17) return 0;; // //return 0; }
4. 预测数据
加载上述训练好的训练模型,并进行估值
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127#include<opencv2opencv.hpp> #include<iostream> #include <opencv2opencv.hpp> #include <iostream> #include <stdio.h> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/opencv.hpp> #include <opencv2/imgproc/types_c.h> #include <opencv2/videoio/videoio_c.h> #include <opencv2/highgui/highgui_c.h> #include <opencv2/face.hpp> #include <opencv2/face/facerec.hpp> using namespace std; using namespace cv; using namespace face; int main() { VideoCapture cap("D:\pics\wjd.avi"); //打开默认摄像头 if (!cap.isOpened()) { return -1; } Mat frame; Mat edges; Mat gray; CascadeClassifier cascade; bool stop = false; //训练好的文件名称,放置在可执行文件同目录下 cascade.load("D:\training\training_data\haarcascade_frontalface_default.xml"); Ptr<FaceRecognizer> modelPCA = createEigenFaceRecognizer(); modelPCA->load("D:\training\training_data\MyFacePCAModel.xml"); while (!stop) { cap >> frame; //frame = imread("D:\pics\test3.jpg"); if (frame.empty()) break; //建立用于存放人脸的向量容器 vector<Rect> faces(0); cvtColor(frame, gray, CV_BGR2GRAY); //改变图像大小,使用双线性差值 //resize(gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR); //变换后的图像进行直方图均值化处理 equalizeHist(gray, gray); cascade.detectMultiScale(gray, faces, 1.1); //, 2, 0 //|CV_HAAR_FIND_BIGGEST_OBJECT //|CV_HAAR_DO_ROUGH_SEARCH //| CV_HAAR_SCALE_IMAGE, //Size(30, 30)); Mat face; Point text_lb; for (size_t i = 0; i < faces.size(); i++) { if (faces[i].height > 0 && faces[i].width > 0) { face = gray(faces[i]); text_lb = Point(faces[i].x, faces[i].y); rectangle(frame, faces[i], Scalar(255, 0, 0), 1, 8, 0); } } imshow("face1", frame); Mat face_test; int predictPCA = 0; if (face.rows >= 80) { resize(face, face_test, Size(150, 200)); } //Mat face_test_gray; //cvtColor(face_test, face_test_gray, CV_BGR2GRAY); if (!face_test.empty()) { //测试图像应该是灰度图 predictPCA = modelPCA->predict(face_test); } cout << predictPCA << endl; if (predictPCA == 1) { string name = "liangcw"; putText(frame, name, text_lb, FONT_HERSHEY_PLAIN, 1, Scalar(0, 0, 255)); } else if (predictPCA == 2) { string name = "liudh"; putText(frame, name, text_lb, FONT_HERSHEY_PLAIN, 1, Scalar(0, 0, 255)); } else if (predictPCA == 3) { string name = "zyw"; putText(frame, name, text_lb, FONT_HERSHEY_PLAIN, 1, Scalar(0, 0, 255)); } else if (predictPCA == 4) { string name = "zzy"; putText(frame, name, text_lb, FONT_HERSHEY_PLAIN, 1, Scalar(0, 0, 255)); } imshow("face2", frame); //waitKey(0); if (waitKey(10) >= 0) stop = true; } return 0; }
5. 测试结果
优酷下载了《演员的诞生》某片段,转成avi格式,能识别出视频中的周一围、章子怡等

6. 结论
基于openCV人脸识别的相关结构体(CascaderClassify、FacerRecognizer),训练数据越大识别效果才越好
人脸检测相关模型,如正脸、侧脸、眼睛、鼻子都是分开的,有没有联合一起的??
最后
以上就是腼腆眼睛最近收集整理的关于基于openCV的视频人脸识别——<<演员的诞生>>视频人脸识别的全部内容,更多相关基于openCV内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复