人脸检测与识别 (环境:opencv3.3.0 + vs2015)
首先,全部代码实现参考冰不语,感谢大佬提供代码(查看官网也可),帮助素人学习。
总的来说,当你走过一遍以后,会发现其实很简单,基本都是调用opencv库和opencv_contrib库,关于opencv_contrib的配置方法,CSDN上真正对你路子的方法很少,所以建议初学者安装版本时,选择你参考的安装方法的版本,调试起来会更方便,如果你是3.3.0版本,需要配置contrib的话,可以私信我,我可以分享编译好的install文件给你,免除配置烦恼。
至于为什么写这篇文章,是应为冰不语的版本时opencv2.*的版本,自己再写3.3版本时,遇到很多坑,然后一一填满,所以避免opencv3新手入坑吧,写了这篇总结。
重点开始
- 数据准备 ORL人脸数据库,参考:人脸识别之一数据收集和预处理 本人数据准备:
#include <opencv2/opencv.hpp>;
#include <iostream>
using namespace cv;
using namespace std;
char ad[128] = { 0 };
int main()
{
vector<Rect> faces;
Mat image, image_gray;
for (int i = 1; i < 11; i++)
{
sprintf_s(ad, "你的照片路径(注意分割符用\\或者/)\\%d.jpg", i);
image = imread(ad);
cvtColor(image, image_gray, COLOR_BGR2GRAY);
equalizeHist(image_gray, image_gray);
CascadeClassifier face_cascade; //载入分类器
if (!face_cascade.load("分类器存放目录\\haarcascade_frontalface_alt.xml"))
{
cout << "Load haarcascade_frontalface_alt failed" << endl;
return 0;
}
vector<Rect> faceRect;
face_cascade.detectMultiScale(image_gray, faceRect, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30));
for (size_t j = 0; j < faceRect.size(); j++)
{
Mat faceROI = image(faceRect[j]);
Mat MyFace;
if (faceROI.cols > 100)
{
resize(faceROI, MyFace, Size(92, 112));
string str = format("保存路径\\s41\\%d.jpg", i);
imwrite(str, MyFace);
}
}
}
}
这部分没遇到什么问题,如有问题,欢迎提问
-
模型训练
#include <iostream> #include <fstream> #include <sstream> #include <math.h> #include <opencv2/opencv.hpp> #include <opencv2/face/facerec.hpp> #include <opencv2/face.hpp> using namespace std; using namespace cv; using namespace cv::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() { system("color 3F"); //读取文件路径 string fn_csv = "路径\\att_faces\\at.txt"; //定义容器存放图像数据和标签 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); } //训练集去除最后一张图片 Mat testSample = images[images.size() - 1]; int testLabel = labels[labels.size() - 1]; images.pop_back(); labels.pop_back(); Ptr<EigenFaceRecognizer> model = EigenFaceRecognizer::create(); model->train(images, labels); model->write("MyFacePCAModel.xml"); Ptr<FisherFaceRecognizer> model1 = FisherFaceRecognizer::create(); model1->train(images, labels); model1->write("MyFaceFisherModel.xml"); Ptr<LBPHFaceRecognizer> model2 = LBPHFaceRecognizer::create(); model2->train(images, labels); model2->write("MyFaceLBPHModel.xml"); // 下面对测试图像进行预测,predictedLabel是预测标签结果 int predictedLabel = model->predict(testSample); int predictedLabel1 = model1->predict(testSample); int predictedLabel2 = model2->predict(testSample); 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; waitKey(0); return 0; }
问题汇总 1.这里有难度的地方就是at.txt文件的制作,我是按照冰不语的方式做的,但是有一个问题就是,我做出来的,我本人的照片并不是对象41标签,而是35,无所谓的,能找到自己就行。
2.特征模型的建立,继续我大哥,冰不语:opencv3.3 API变换,你以为这样就够了嘛,不是的,当我训练完成以后,在进行测试识别的时候, 出现了OpenCV Error: Unspecified error错误,不得不说,百度拯救了我,没错,在opencv3.3以前,save对应load, 3.3就要变成write对应read, 水平真的有限,你体会的到我被那哥错误支配半天的痛苦吗,我都要放弃的时候,找到了答案,题外话,遇到问题,百度百度再百度,人类那么多,总会有和你问题一样的“先行者”,加油,你行的!
- 识别自己的脸
冰不语是调用的摄像头,我选择读自己其他的照片,别说这个简单,没有参考的去做这个,你做你还真能行!
代码奉上:
#include <opencv2/opencv.hpp>
#include <opencv2/face.hpp>
#include <opencv2/face/facerec.hpp>
#include <iostream>
using namespace std;
using namespace cv;
using namespace cv::face;
int main()
{
system("color 3F");
Mat image, image_gray;
image = imread("huangbo.jpg");
//namedWindow("苏宝宝本人");
//imshow("苏宝宝本人", image);
cvtColor(image, image_gray, CV_BGR2GRAY);
equalizeHist(image_gray, image_gray);
//imshow("苏宝宝", image_gray);
CascadeClassifier cascade;
cascade.load("haarcascade_frontalface_alt.xml");
vector<Rect> faces(0);
cascade.detectMultiScale(image_gray, faces, 1.1, 2, 0 | 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 = image_gray(faces[i]);
text_lb = Point(faces[0].x, faces[0].y);
rectangle(image, faces[0], Scalar(0, 255, 0), 1, 8, 0);
}
}
Ptr<EigenFaceRecognizer> modelPCA = EigenFaceRecognizer::create();
modelPCA -> read("MyFacePCAModel.xml");
int predictPCA = 50;
Mat face_test;
if (face.rows >= 120)
{
resize(face, face_test, Size(92, 112));
}
if (!face_test.empty())
{
predictPCA = modelPCA->predict(face_test);
}
if (predictPCA == 50)
{
string name2 = "Not RanRansu";
putText(image, name2, text_lb, FONT_HERSHEY_COMPLEX, 1, Scalar(255, 0, 0));
cout << "未匹配到合适的人脸" << endl;
namedWindow("人脸识别结果");
imshow("人脸识别结果", image);
}
if (predictPCA == 35)
{
string name = "RanRanSu";
putText(image, name, text_lb, FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255));
cout << "我们可爱的苏宝宝本人" << endl;
namedWindow("人脸识别结果");
imshow("人脸识别结果", image);
}
waitKey(0);
return 0;
}
那个model ->read,真是是拿智商在支配我,别说了,多看基础东西!
没有结果的博客不是好博客。。。。。。
警告!!!!!!!!!!!
胆小勿看下滑。。。。。
感谢我可爱的舍友RanRanSu出境,祝愿他生活幸福,少和媳妇闹矛盾,好好走下去!!!!
我本人比较帅
把识别不出的仙女奉上:
最长的一篇博客,真心希望对你有用,生活快乐!
上一篇: Java实现一个简单的内存缓存类