我是靠谱客的博主 腼腆眼睛,最近开发中收集的这篇文章主要介绍基于openCV的视频人脸识别——<<演员的诞生>>视频人脸识别,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1.准备训练数据

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



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



    

#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制作标签(注意修改文件中的目录路径)

#!/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<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的视频人脸识别——<<演员的诞生>>视频人脸识别所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(76)

评论列表共有 0 条评论

立即
投稿
返回
顶部