openCV学习笔记(十五) —— 人脸识别 —— 读取摄像头进行人脸图像采集和人脸识别

谁借莪1个温暖的怀抱¢ 2021-09-27 06:00 855阅读 0赞

实现以下功能:

  1. 交互式对话框:请选择要执行的动作

    1. 人脸采集:打开摄像头,采集照片,保存训练模型
    2. 人脸识别:

      1. 打开摄像头,采集照片,预识别;
      2. 输入图像的路径,图像识别
      3. 输出结果:

        1. 找到匹配的对象,输出名字;
        2. 未找到匹配的对象,提示:人脸采集并保存训练模型

程序

  1. /*
  2. 交互式对话框:请选择要执行的动作
  3. 1.人脸采集:
  4. 打开摄像头,采集照片,保存训练模型
  5. 2.人脸识别:
  6. <1>打开摄像头,采集照片,预识别;
  7. <2>输入图像的路径,图像识别
  8. 输出结果:
  9. 找到匹配的对象,输出名字;
  10. 未找到匹配的对象,提示:人脸采集并保存训练模型
  11. */
  12. #include <iostream>
  13. #include <fstream>
  14. #include <string>
  15. #include <vector>
  16. #include <direct.h>
  17. #include <io.h>
  18. #include <opencv2/opencv.hpp>
  19. #include <opencv2/highgui.hpp>
  20. #include <opencv2/objdetect.hpp>
  21. #include <opencv2/face.hpp>
  22. using namespace std;
  23. using namespace cv;
  24. using namespace cv::face;
  25. int face_image_save(string dir_name, string cascade_path);
  26. int face_model_train_save(string cvs_path);
  27. int face_recg(Mat image, string cascade_path);
  28. //void read_cvs(const string& filename, vector<Mat>& img, vector<int>& lable, char separator = ';');
  29. //void write_cvs(string& filename, string line, int label_number, char separator = ';');
  30. string cascade_xml_path = "F:\\project\\vs2017\\openCV_test\\openCV_test\\cascade\\haarcascades\\haarcascade_frontalface_default.xml";
  31. string face_image_path = "F:\\project\\vs2017\\openCV_test\\openCV_test\\face_recg\\face\\";
  32. string cvs_path = "F:\\project\\vs2017\\openCV_test\\openCV_test\\face_recg\\face\\at.txt";
  33. int label_number = 100;
  34. #define MY_SIZE Size(92, 112)
  35. int main()
  36. {
  37. while (true)
  38. {
  39. printf("\n<------------------ 欢迎使用人脸识别系统,请输入你的选择 ------------------>\n1 -- 人脸图像采集\n2 -- 人脸识别\n3 -- 退出系统\n");
  40. int action = 0;
  41. cin >> action;
  42. if (action == 1)
  43. {
  44. printf("请输入你的名字:");
  45. string name;
  46. cin >> name;
  47. string dir_name = face_image_path + name + "\\";
  48. int ret = face_image_save(dir_name, cascade_xml_path);
  49. if (ret == 0)
  50. {
  51. face_model_train_save(cvs_path);
  52. }
  53. }
  54. else if (action == 2)
  55. {
  56. printf("\n\n请选择图片来源:\n1 -- 从指定目录选择图片\n2 -- 打开摄像头读取图片\n");
  57. cin >> action;
  58. Mat test_img;
  59. switch (action)
  60. {
  61. case 1:
  62. {
  63. printf("请输入图片的完整路径\n");
  64. string img_path;
  65. while (true)
  66. {
  67. cin >> img_path;
  68. if (_access(img_path.c_str(), 0) == -1)
  69. {
  70. printf("没有找到图片,请重新选择图片!!!\n");
  71. }
  72. else
  73. {
  74. test_img = imread(img_path.c_str());
  75. break;
  76. }
  77. }
  78. }
  79. break;
  80. case 2:
  81. default:
  82. {
  83. printf("请对准摄像头,我们将读取照片...\n");
  84. //打开摄像头
  85. VideoCapture capture;
  86. capture.open(0);
  87. if (!capture.isOpened())
  88. {
  89. printf("Can't open camera...\n");
  90. return -1;
  91. }
  92. capture.read(test_img);
  93. capture.release();
  94. }
  95. break;
  96. }
  97. //人脸识别
  98. face_recg(test_img, cascade_xml_path);
  99. }
  100. else
  101. {
  102. break;
  103. }
  104. }
  105. return 0;
  106. }
  107. //使用CVS文件读取图片和标签
  108. void read_cvs(const string& filename, vector<Mat>& img, vector<int>& lable, char separator = ';')
  109. {
  110. Mat tmp_img;
  111. ifstream cvs_file(filename.c_str());
  112. assert(cvs_file);
  113. string line, path, tag;
  114. while (getline(cvs_file, line))
  115. {
  116. stringstream lines(line);
  117. getline(lines, path, separator);
  118. getline(lines, tag);
  119. if (!path.empty() && !tag.empty())
  120. {
  121. tmp_img = imread(path, IMREAD_GRAYSCALE); //读入图像时转成灰度图
  122. assert(!tmp_img.empty());
  123. img.push_back(tmp_img);
  124. lable.push_back(atoi(tag.c_str()));
  125. }
  126. }
  127. tmp_img.release();
  128. }
  129. void write_cvs(string& filename, string line, int label_number, char separator = ';')
  130. {
  131. ofstream cvs_file;
  132. string str = line + separator + format("%d\n", label_number);
  133. //printf("%s\n", str.c_str());
  134. cvs_file.open(filename.c_str(), ios::app);
  135. if (cvs_file.is_open())
  136. {
  137. cvs_file << str;
  138. cvs_file.close();
  139. }
  140. }
  141. int face_image_save(string dir_name, string cascade_path)
  142. {
  143. //printf("我们将保存你的图片到以下路径:%s\n", dir_name.c_str());
  144. if (_access(dir_name.c_str(), 0) == -1)
  145. {
  146. //printf("不存在文件夹,我们将创建...\n");
  147. _mkdir(dir_name.c_str());
  148. }
  149. else
  150. {
  151. printf("人脸图片已经保存在数据库,不需要重复读取\n");
  152. return -1;
  153. }
  154. VideoCapture capture;
  155. //打开笔记本摄像头
  156. capture.open(0);
  157. if (!capture.isOpened())
  158. {
  159. printf("can't open camera...\n");
  160. return -1;
  161. }
  162. //加载分类器
  163. CascadeClassifier cascade;
  164. cascade.load(cascade_path);
  165. if (cascade.empty())
  166. {
  167. printf("can't load classifier\n");
  168. return -1;
  169. }
  170. Mat img, img_gray, faceROI;
  171. vector<Rect> faces;
  172. int count = 0;
  173. string my_path, tmp_path;
  174. while (true)
  175. {
  176. capture.read(img);
  177. cvtColor(img, img_gray, CV_RGB2GRAY); //转化为灰度图
  178. equalizeHist(img_gray, img_gray); //直方图均衡化
  179. cascade.detectMultiScale(img_gray, faces, 1.1, 6, 0, Size(30, 30)); //人脸识别,获取faces矢量数据集
  180. if (faces.size() > 0)
  181. {
  182. for (int i = 0; i < faces.size(); ++i)
  183. {
  184. faceROI = img_gray(faces[i]);//ROI部分为将要保存的图片,用img_gray获取灰度图部分,保存成灰度图;如果将img_gray改为img,就变成彩色图片了
  185. resize(faceROI, faceROI, MY_SIZE); //调整ROI图片大小到指定大小
  186. rectangle(img, faces[i], Scalar(0, 255, 0), 2, 8, 0);
  187. imshow("view", img); //显示视频图像
  188. imshow("ROI", faceROI); //显示ROI区域
  189. tmp_path = format("%d.jpg", count++);
  190. my_path = dir_name + tmp_path;
  191. imwrite(my_path, faceROI); //保存采集到的图片到指定目录
  192. write_cvs(cvs_path, my_path, label_number);
  193. }
  194. }
  195. if (waitKey(30) == 27 || count == 20)
  196. {
  197. break;
  198. }
  199. }
  200. //保存的标签值
  201. label_number++;
  202. capture.release();
  203. destroyAllWindows();
  204. return 0;
  205. }
  206. int face_model_train_save(string cvs_path)
  207. {
  208. printf("创建人脸识别的模型并进行训练,保存训练结果中(需要一些时间)...\n");
  209. vector<Mat> faces;
  210. vector<int> labels;
  211. try
  212. {
  213. read_cvs(cvs_path, faces, labels);
  214. }
  215. catch (Exception &e)
  216. {
  217. cerr << "Error opening file, reason :" << e.msg << endl;
  218. return -1;
  219. }
  220. if (faces.size() <= 1)
  221. {
  222. printf("Too few face images\n");
  223. return -1;
  224. }
  225. /* 创建人脸识别的模型,并进行训练,之后保存训练结果*/
  226. double start1, start2, start3;
  227. double end1, end2, end3;
  228. //PCA特征脸算法
  229. start1 = (double)getTickCount();
  230. Ptr<EigenFaceRecognizer> eigen_model = EigenFaceRecognizer::create();
  231. eigen_model->train(faces, labels);
  232. eigen_model->save("my_eigen_face_model.xml");
  233. end1 = (getTickCount() - start1) / getTickFrequency();
  234. //LDA线性判别分析
  235. start2 = (double)getTickCount();
  236. Ptr<FisherFaceRecognizer> fisher_model = FisherFaceRecognizer::create();
  237. fisher_model->train(faces, labels);
  238. fisher_model->save("my_fisher_face_model.xml");
  239. end2 = (getTickCount() - start2) / getTickFrequency();
  240. //LBP局部二值模式直方图
  241. start3 = (double)getTickCount();
  242. Ptr<LBPHFaceRecognizer> lbph_model = LBPHFaceRecognizer::create();
  243. lbph_model->train(faces, labels);
  244. lbph_model->save("my_lbph_face_model.xml");
  245. end3 = (getTickCount() - start3) / getTickFrequency();
  246. printf("PAC算法训练所用时间: %f s\n", end1);
  247. printf("LDA算法训练所用时间: %f s\n", end2);
  248. printf("LBP算法训练所用时间: %f s\n", end3);
  249. printf("训练结束,保存成功!\n");
  250. return 0;
  251. }
  252. int face_recg(Mat image, string cascade_path)
  253. {
  254. printf("人脸识别中...\n");
  255. //显示读入的图片
  256. imshow("origin", image);
  257. waitKey(30);
  258. //加载分类器
  259. CascadeClassifier cascade;
  260. cascade.load(cascade_path);
  261. if (cascade.empty())
  262. {
  263. printf("can't load classifier\n");
  264. return -1;
  265. }
  266. //读取人脸识别模型
  267. double start1, start2, start3;
  268. double end1, end2, end3;
  269. start1 = (double)getTickCount();
  270. Ptr<EigenFaceRecognizer> eigen_model = Algorithm::load<EigenFaceRecognizer>("my_eigen_face_model.xml"); //Eigen Faces算法
  271. end1 = (getTickCount() - start1) / getTickFrequency();
  272. start2 = (double)getTickCount();
  273. Ptr<FisherFaceRecognizer> fisher_model = Algorithm::load<FisherFaceRecognizer>("my_fisher_face_model.xml");//Fisher Faces算法
  274. end2 = (getTickCount() - start2) / getTickFrequency();
  275. start3 = (double)getTickCount();
  276. Ptr<LBPHFaceRecognizer> lbph_model = Algorithm::load<LBPHFaceRecognizer>("my_lbph_face_model.xml"); //LBP 算法
  277. end3 = (getTickCount() - start3) / getTickFrequency();
  278. printf("加载PAC算法训练模型所用时间: %f s\n", end1);
  279. printf("加载LDA算法训练模型所用时间: %f s\n", end2);
  280. printf("加载LBP算法训练模型所用时间: %f s\n", end3);
  281. Mat faceROI, img_gray;
  282. int p_label;
  283. vector<Rect> faces;
  284. cvtColor(image, img_gray, CV_RGB2GRAY); //转化为灰度图
  285. equalizeHist(img_gray, img_gray); //直方图均衡化
  286. cascade.detectMultiScale(img_gray, faces, 1.1, 6, 0, Size(30, 30)); //人脸识别,获取faces矢量数据集
  287. //printf("size = %zd\n", faces.size());
  288. if (faces.size() > 0)
  289. {
  290. for (int i = 0; i < faces.size(); ++i)
  291. {
  292. faceROI = img_gray(faces[i]);
  293. resize(faceROI, faceROI, MY_SIZE); //调整成训练集一样的大小
  294. rectangle(image, faces[i], Scalar(0, 255, 0), 2, 8, 0);
  295. imshow("Origin", image);
  296. p_label = eigen_model->predict(faceROI);
  297. cout << "Eigen算法识别到的结果:" << p_label << endl;
  298. p_label = fisher_model->predict(faceROI);
  299. cout << "Fisher算法识别到的结果:" << p_label << endl;
  300. p_label = lbph_model->predict(faceROI);
  301. cout << "LBPH算法识别到的结果:" << p_label << endl;
  302. imshow("result", faceROI);
  303. }
  304. }
  305. destroyAllWindows();
  306. return 0;
  307. }

程序运行结果:

人脸图片采集

70

人脸识别-摄像头读取图片

70 1

从目录读取图片

70 2

从运行结果来看,LBPH算法最准确!

发表评论

表情:
评论列表 (有 0 条评论,855人围观)

还没有评论,来说两句吧...

相关阅读

    相关 opencv人脸识别

    我的劳动成果。 1.成功安装了opencv ,可是它还要编译。我放弃。 2.成功训练自己的人脸分类器。(虽然数据是别人的,算法也是系统写好的,图形库也是别人调好的)虽然识别

    相关 opencv人脸识别

    opencv人脸识别: 首先我们来简单的讲一下人脸识别流程:这里采用的是vs2017+opencv3.3扩展库 1、进行人脸检测 2、识别器训练与分类 3、人脸检测