本文主要是介绍基于openCV的视频人脸识别 《演员的诞生》,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1.准备训练数据
网络上下载(训练数据量大时,通过爬虫获取)目标的图片:
运用以下代码将原图中的 人脸头像识别、提取、调整大小(这里是150*200),并分别保存。
运行环境:win7 64+VS2013+openCV3.1。
(PS:抱怨下vs和opencv的版本密切相关,注意安装配置)
- #include <opencv2\opencv.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 cascade\n"); return -1; };
- if (!eyes_cascade.load(eyes_cascade_name)){ printf("--(!)Error loading eyes cascade\n"); 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制作标签(注意修改文件中的目录路径)
- #!/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)
- //#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. 预测数据
加载上述训练好的训练模型,并进行估值
- #include<opencv2\opencv.hpp>
- #include<iostream>
- #include <opencv2\opencv.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的视频人脸识别 《演员的诞生》的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!