【Opencv人脸识别学习记录】
环境:
- opencv3.0.0
- vs2012
- opencv_contrib3.0.0 —— — 编译和配置点此
- ORL人脸数据库,下载地址:点此进入下载
【注意事项】
!!!自己测试的图片一定要和ORL人脸数据图片的尺寸和颜色通道一模一样!!!!!!
【工程下载】完成工程下载地址,包含数据集以及测试图片等:
https://download.csdn.net/download/qq153471503/10370732
1、制作csv文件
一个面孔对应一个标签,在程序中一个个读取图片和标签,那么效率很低,所以将图片路径和标签制作成一个文件,在程序中直接读取文件中的路径和标签,就能将面孔和标签对应起来。
下面一段python代码就是生成这个csv文件,使用方法:
python [这个python文件名] [参数一:ORL文件目录] [参数二:输出的csv文件]
例如我在当前工程目录下打开命令行,键入:
python create_csv.py ./faces_data/ ./at.txt
效果:这个文件就是at.txt
# -*- coding: UTF-8 -*-
import os
import os.path
import sys
if __name__ == "__main__":
if len(sys.argv) != 3:
print
print("Input error. conmond format: \n \
python %s [images path] [output file] \n \
For example: python %s ./faces_data ./at.txt ")%(sys.argv[0], sys.argv[0])
sys.exit(0)
BASE_PATH = sys.argv[1]
SEPARATOR = ";"
fh = open(sys.argv[2], "w")
label = 0
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()
2、人脸检测代码
#if 1
CascadeClassifier face_cascade; //载入分类器
//加载分类训练器,OpenCv官方文档提供的xml文档,可以直接调用
//xml文档路径 opencv\sources\data\haarcascades
cout << "loading haarcascade_frontalface_alt.xml..." << endl;
if (!face_cascade.load("haarcascade_frontalface_alt.xml"))
{
cout << "load haarcascade_frontalface_alt failed!" << endl;
exit(-1);
}
cout << "OK" << endl;
Mat matTestImg = imread("test.png"); // 输入测试图像
resize(matTestImg, matTestImg, matTestImg.size());
Mat showImg;
matTestImg.copyTo(showImg);
vector<Rect> face_rect;
vector<Mat> res = FaceDetectMultiScale(face_cascade, matTestImg, face_rect); // 多尺度检测
if (res.empty()) // 如果为空说明未检测到人脸
{
cout << "failed, Please try again." << endl;
exit(-1);
}
#if 0
for (size_t i=0; i!=res.size(); i++)
{
// 显示检测到的人脸
imshow("", res[i]);
waitKey(0);
}
#endif
/// 将人脸框出
for (size_t i=0; i!=face_rect.size(); i++)
{
rectangle(showImg, face_rect[i], Scalar(0,0,255));
}
imshow("", showImg); // 显示识别结果
waitKey(0);
#else
效果
3、人脸识别代码
Ptr<FaceRecognizer> faceR = createEigenFaceRecognizer(); // 创建人脸特征识别器
vector<Mat> images;
vector<int> labels;
vector<Rect> face_rect;
read_csv("at.txt", images, labels); // 读取数据集
string filename = "face_model.xml"; // 保存的文件名
// 如果定义了该宏,则不进行训练
#ifdef ALREADY_TRAIN
cout << "loading " << filename + "..." << endl;
faceR->load(filename);
cout << "OK" << endl;
#else
face_train(faceR, images, labels, filename); // 训练
#endif
//test(faceR, images); // 测试
//resize(tmp, tmp, Size(92, 112)); // 重新调整大小,调整到和训练数据一样的尺寸
while (true)
{
string filename;
cout << "Please input file, enter 'q' exit: " << flush;
cin >> filename;
if (filename == "q")
{
break;
}
if (access(filename.c_str(), 0) < 0)
{
cout << filename + " not exists." << endl;
continue;
}
Mat img = imread(filename, IMREAD_GRAYSCALE); // 读入灰度图
imwrite("img.png", img);
int label = face_identify(faceR, img);
printf("Identify the results: label = %d \n", label);
}
效果
由运行结果可见,预测到的标签是0, 在我创建的csv文件at.txt文件中,s1/7.pgm这个图片的标签就是0,所以识别成功!
3、完整代码
#include <opencv2\opencv.hpp>
#include <opencv\ml.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <opencv2/face.hpp>
#include <fstream>
#include <opencv2/calib3d/calib3d.hpp>
#include <io.h> // for access
using namespace std;
using namespace cv;
using namespace face;
// 定义了该宏,则不需要进行人脸的训练
#define ALREADY_TRAIN
/**
* 读取csv文件。使用CSV文件去读图像和标签,主要使用stringstream和getline方法。
* 生成csv文件可用本工程下的create_csv.py这个python文件,使用方法:
*
* python create_csv.py [数据图像路径] [输出的svc文件名]
*
* @param filename svc文件名
* @param images 用于存储测试图像
* @param labels 存储标签
* @param separator 分隔符
*/
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, IMREAD_GRAYSCALE));
labels.push_back(atoi(classlabel.c_str()));
}
}
}
/**
* 人脸训练
*
* @param faceR 识别器
* @param images 图像训练集
* @param labels 标签集
* @param saveName 训练结束后保存的模型文件名
*/
void face_train(Ptr<FaceRecognizer>& faceR, vector<Mat> &images, vector<int> &labels, string& saveName)
{
cout << "start train..." << endl;
faceR->train(images, labels); // 开始训练
faceR->save(saveName); //保存训练模型
cout << "train done." << endl;
}
/**
* 人脸识别
*
* @param faceR 识别器
* @param srcImg 待测图像
* @return 预测的标签值
*/
int face_identify(Ptr<FaceRecognizer>& faceR, Mat& srcImg)
{
int label_predict = -1;
double accuracy = -1;
faceR->predict(srcImg, label_predict, accuracy); // 预测
return label_predict;
}
/**
* 测试人脸识别
*
* @param faceR 识别器
* @param images 测试数据集
*/
void test(Ptr<FaceRecognizer>& faceR, vector<Mat>& images)
{
int label_predict = -1;
double accuracy = -1;
for (int i=0; i!=images.size(); i++)
{
faceR->predict(images[i], label_predict, accuracy);
// 打印预测到的标签值和准确率
printf("label_predict: %d accuracy : %f \n", label_predict, 100.0-accuracy);
}
}
/**
* 人脸多尺度检测
*
* @param face 分类器
* @param inputArr 带测图像
* @param face_rect 存储识别到的人脸区域框
* @return 检测到的人脸Mat图像
*/
vector<Mat> FaceDetectMultiScale(CascadeClassifier& face, Mat& inputArr, vector<Rect>& face_rect)
{
vector<Mat> res;
Mat img_src, img_equa;
img_src = inputArr;
if(img_src.channels() != 1)
cvtColor(img_src, img_src, CV_BGR2GRAY); // 转换为灰度图
equalizeHist(img_src, img_equa); //直方图均衡化
// 人脸检测,多尺度
face.detectMultiScale(
img_equa,
face_rect,
1.1, 2, 0 | CV_HAAR_SCALE_IMAGE,
Size(30, 30));
for (int i=0; i!=face_rect.size(); i++)
{
Mat tmp;
inputArr(face_rect[i]).copyTo(tmp);
res.push_back(tmp);
}
return res;
}
int main()
{
#if 0
CascadeClassifier face_cascade; //载入分类器
//加载分类训练器,OpenCv官方文档提供的xml文档,可以直接调用
//xml文档路径 opencv\sources\data\haarcascades
cout << "loading haarcascade_frontalface_alt.xml..." << endl;
if (!face_cascade.load("haarcascade_frontalface_alt.xml"))
{
cout << "load haarcascade_frontalface_alt failed!" << endl;
exit(-1);
}
cout << "OK" << endl;
Mat matTestImg = imread("test.jpg"); // 输入测试图像
resize(matTestImg, matTestImg, matTestImg.size());
Mat showImg;
matTestImg.copyTo(showImg);
vector<Rect> face_rect;
vector<Mat> res = FaceDetectMultiScale(face_cascade, matTestImg, face_rect); // 多尺度检测
if (res.empty()) // 如果为空说明未检测到人脸
{
cout << "failed, Please try again." << endl;
exit(-1);
}
#if 0
for (size_t i=0; i!=res.size(); i++)
{
// 显示检测到的人脸
imshow("", res[i]);
waitKey(0);
}
#endif
/// 将人脸框出
for (size_t i=0; i!=face_rect.size(); i++)
{
rectangle(showImg, face_rect[i], Scalar(0,0,255));
}
imshow("", showImg); // 显示识别结果
waitKey(0);
#else
Ptr<FaceRecognizer> faceR = createEigenFaceRecognizer(); // 创建人脸特征识别器
vector<Mat> images;
vector<int> labels;
vector<Rect> face_rect;
read_csv("at.txt", images, labels); // 读取数据集
string filename = "face_model.xml"; // 保存的文件名
// 如果定义了该宏,则不进行训练
#ifdef ALREADY_TRAIN
cout << "loading " << filename + "..." << endl;
faceR->load(filename);
cout << "OK" << endl;
#else
face_train(faceR, images, labels, filename); // 训练
#endif
//test(faceR, images); // 测试
//resize(tmp, tmp, Size(92, 112)); // 重新调整大小,调整到和训练数据一样的尺寸
while (true)
{
string filename;
cout << "Please input file, enter 'q' exit: " << flush;
cin >> filename;
if (filename == "q")
{
break;
}
if (access(filename.c_str(), 0) < 0)
{
cout << filename + " not exists." << endl;
continue;
}
Mat img = imread(filename, IMREAD_GRAYSCALE); // 读入灰度图
imwrite("img.png", img);
int label = face_identify(faceR, img);
printf("Identify the results: label = %d \n", label);
}
#endif
system("pause");
return 0;
}
ends…