小言_互联网的博客

OpenCV笔记--人脸识别算法Eigenfaces和Fisherfaces

329人阅读  评论(0)

目录

1--前言

2--处理ORL数据集

3--Eigenfaces复现过程

4--Fisherfaces复现过程

5--分析


1--前言

①SYSU模式识别课程作业

②配置:基于Windows11、OpenCV4.5.5、VSCode、CMake参考OpenCV配置方式

③原理及源码介绍:Face Recognition with OpenCV

④数据集:ORL Database of Faces

2--处理ORL数据集

①源码:


  
  1. import sys
  2. import os.path
  3. if __name__ == "__main__":
  4. BASE_PATH = './ORL/att_faces/orl_faces/'
  5. SEPARATOR = ";"
  6. dir_txt = open( "./dir.txt", 'w')
  7. label = 0
  8. for dirname, dirnames, filenames in os.walk(BASE_PATH):
  9. # dirname当前路径; dirnames当前路径下所有目录名(不包含子目录);filenames当前路径下的所有文件名(不包含子目录)
  10. for subdirname in dirnames: # 遍历每一个目录
  11. subject_path = os.path.join(dirname, subdirname)
  12. for filename in os.listdir(subject_path):
  13. abs_path = "%s/%s" % (subject_path, filename)
  14. print( "%s%s%d" % (abs_path, SEPARATOR, label))
  15. dir_txt.write(abs_path)
  16. dir_txt.write(SEPARATOR)
  17. dir_txt.write( str(label))
  18. dir_txt.write( "\n")
  19. label = label + 1
  20. dir_txt.close()

②运行及结果:

python create_csv.py

3--Eigenfaces复现过程

①源码:


  
  1. // 引用依赖
  2. #include "opencv2/core.hpp"
  3. #include "opencv2/face.hpp"
  4. #include "opencv2/highgui.hpp"
  5. #include "opencv2/imgproc.hpp"
  6. #include <iostream>
  7. #include <fstream>
  8. #include <sstream>
  9. // 使用相应的命名空间
  10. using namespace cv;
  11. using namespace cv::face;
  12. using namespace std;
  13. // 标准化函数
  14. static Mat norm_0_255(InputArray _src) {
  15. Mat src = _src. getMat();
  16. // Create and return normalized image:
  17. Mat dst;
  18. switch(src. channels()) {
  19. case 1:
  20. cv:: normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
  21. break;
  22. case 3:
  23. cv:: normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC3);
  24. break;
  25. default:
  26. src. copyTo(dst);
  27. break;
  28. }
  29. return dst;
  30. }
  31. // 读取CSV文件函数
  32. static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';') {
  33. std::ifstream file(filename.c_str(), ifstream::in);
  34. if (!file) {
  35. string error_message = "No valid input file was given, please check the given filename.";
  36. CV_Error(Error::StsBadArg, error_message);
  37. }
  38. string line, path, classlabel;
  39. while ( getline(file, line)) {
  40. stringstream liness(line);
  41. getline(liness, path, separator);
  42. getline(liness, classlabel);
  43. if(!path. empty() && !classlabel. empty()) {
  44. images. push_back( imread(path, 0));
  45. labels. push_back( atoi(classlabel. c_str()));
  46. }
  47. }
  48. }
  49. int main(int argc, const char *argv[]) {
  50. //检查argc是否符合要求
  51. if (argc < 2) {
  52. cout << "usage: " << argv[ 0] << " <csv.ext> <output_folder> " << endl;
  53. exit( 1);
  54. }
  55. string output_folder = ".";
  56. if (argc == 3) {
  57. output_folder = string(argv[ 2]);
  58. }
  59. // CSV文件的路径
  60. string fn_csv = string(argv[ 1]);
  61. // 初始化存储imgs和labels的向量
  62. vector<Mat> images;
  63. vector< int> labels;
  64. // 读取CSV文件
  65. try {
  66. read_csv(fn_csv, images, labels);
  67. } catch ( const cv::Exception& e) {
  68. cerr << "Error opening file \"" << fn_csv << "\". Reason: " << e.msg << endl;
  69. exit( 1);
  70. }
  71. // 判断img数目是否符合要求
  72. if(images. size() <= 1) {
  73. string error_message = "This demo needs at least 2 images to work. Please add more images to your data set!";
  74. CV_Error(Error::StsError, error_message);
  75. }
  76. // images的高度
  77. int height = images[ 0].rows;
  78. // 从训练集中选择一张图片作为测试集
  79. Mat testSample = images[images. size() - 1];
  80. int testLabel = labels[labels. size() - 1];
  81. images. pop_back();
  82. labels. pop_back();
  83. // 创建模型,使用PCA特征脸算法
  84. Ptr<EigenFaceRecognizer> model = EigenFaceRecognizer:: create();
  85. model-> train(images, labels); // 训练模型
  86. int predictedLabel = model-> predict(testSample); // 使用测试集测试模型
  87. // 打印准确率
  88. string result_message = format( "Predicted class = %d / Actual class = %d.", predictedLabel, testLabel);
  89. cout << result_message << endl;
  90. // 获取模型的特征值
  91. Mat eigenvalues = model-> getEigenValues();
  92. // 展示特征向量
  93. Mat W = model-> getEigenVectors();
  94. // 从训练集中获取样本均值
  95. Mat mean = model-> getMean();
  96. // 根据argc判断进行展示或保存操作
  97. if(argc == 2) {
  98. imshow( "mean", norm_0_255(mean. reshape( 1, images[ 0].rows)));
  99. } else {
  100. imwrite(format( "%s/mean.png", output_folder. c_str()), norm_0_255(mean. reshape( 1, images[ 0].rows)));
  101. }
  102. // 显示或保存特征脸
  103. for ( int i = 0; i < min( 10, W.cols); i++) {
  104. string msg = format( "Eigenvalue #%d = %.5f", i, eigenvalues. at< double>(i));
  105. cout << msg << endl;
  106. // 获取特征向量
  107. Mat ev = W. col(i). clone();
  108. // resize成原始大小,并归一化到0-255
  109. Mat grayscale = norm_0_255(ev. reshape( 1, height));
  110. // 显示图像并应用Jet颜色图以获得更好的观感。
  111. Mat cgrayscale;
  112. applyColorMap(grayscale, cgrayscale, COLORMAP_JET);
  113. // 根据argc判断进行展示或保存操作
  114. if(argc == 2) {
  115. imshow(format( "eigenface_%d", i), cgrayscale);
  116. } else {
  117. imwrite(format( "%s/eigenface_%d.png", output_folder. c_str(), i), norm_0_255(cgrayscale));
  118. }
  119. }
  120. // 在一些预定义的步骤中显示或保存图像重建的过程:
  121. for( int num_components = min(W.cols, 10); num_components < min(W.cols, 300); num_components+= 15) {
  122. // 从模型中分割特征向量
  123. Mat evs = Mat(W, Range:: all(), Range( 0, num_components));
  124. Mat projection = LDA:: subspaceProject(evs, mean, images[ 0]. reshape( 1, 1));
  125. Mat reconstruction = LDA:: subspaceReconstruct(evs, mean, projection);
  126. // 归一化
  127. reconstruction = norm_0_255(reconstruction. reshape( 1, images[ 0].rows));
  128. // 根据argc判断进行展示或保存操作
  129. if(argc == 2) {
  130. imshow(format( "eigenface_reconstruction_%d", num_components), reconstruction);
  131. } else {
  132. imwrite(format( "%s/eigenface_reconstruction_%d.png", output_folder. c_str(), num_components), reconstruction);
  133. }
  134. }
  135. // 如果没有写入输出文件夹,则等待键盘输入
  136. if(argc == 2) {
  137. waitKey( 0);
  138. }
  139. return 0;
  140. }

②编译过程:

CMakeLists.txt如下:


  
  1. cmake_minimum_required(VERSION 3.24) # 指定 cmake的 最小版本
  2. project(test) # 设置项目名称
  3. find_package(Opencv REQUIRED)
  4. INCLUDE_DIRECTORIES(${OpenCV_INCLUDE_DIRS})
  5. add_executable(eigenfaces_demo eigenfaces.cpp) # 生成可执行文件
  6. target_link_libraries(eigenfaces_demo ${OpenCV_LIBS} ) # 设置target需要链接的库

  
  1. mkdir build
  2. cd build
  3. cmake ..
  4. cd ..
  5. mingw32-make

③运行及结果展示:

./eigenfaces_demo.exe ./dir.txt ./Engenfaces_Result

特征图:(简单修改源程序生成的文件名,再按顺序进行拼接即可生成拼接图,拼接程序参考

重建过程:

均值图:

4--Fisherfaces复现过程

①源码:


  
  1. // 引用依赖
  2. #include "opencv2/core.hpp"
  3. #include "opencv2/face.hpp"
  4. #include "opencv2/highgui.hpp"
  5. #include "opencv2/imgproc.hpp"
  6. #include <iostream>
  7. #include <fstream>
  8. #include <sstream>
  9. // 使用相应的命名空间
  10. using namespace cv;
  11. using namespace cv::face;
  12. using namespace std;
  13. // 标准化函数
  14. static Mat norm_0_255(InputArray _src) {
  15. Mat src = _src. getMat();
  16. Mat dst;
  17. switch(src. channels()) {
  18. case 1:
  19. cv:: normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
  20. break;
  21. case 3:
  22. cv:: normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC3);
  23. break;
  24. default:
  25. src. copyTo(dst);
  26. break;
  27. }
  28. return dst;
  29. }
  30. // 读取csv文件函数
  31. static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';') {
  32. std::ifstream file(filename.c_str(), ifstream::in);
  33. if (!file) {
  34. string error_message = "No valid input file was given, please check the given filename.";
  35. CV_Error(Error::StsBadArg, error_message);
  36. }
  37. string line, path, classlabel;
  38. while ( getline(file, line)) {
  39. stringstream liness(line);
  40. getline(liness, path, separator);
  41. getline(liness, classlabel);
  42. if(!path. empty() && !classlabel. empty()) {
  43. images. push_back( imread(path, 0));
  44. labels. push_back( atoi(classlabel. c_str()));
  45. }
  46. }
  47. }
  48. int main(int argc, const char *argv[]) {
  49. //检查argc是否符合要求
  50. if (argc < 2) {
  51. cout << "usage: " << argv[ 0] << " <csv.ext> <output_folder> " << endl;
  52. exit( 1);
  53. }
  54. string output_folder = ".";
  55. if (argc == 3) {
  56. output_folder = string(argv[ 2]);
  57. }
  58. // CSV文件的路径
  59. string fn_csv = string(argv[ 1]);
  60. // 初始化存储imgs和labels的向量
  61. vector<Mat> images;
  62. vector< int> labels;
  63. // 读取CSV文件
  64. try {
  65. read_csv(fn_csv, images, labels);
  66. } catch ( const cv::Exception& e) {
  67. cerr << "Error opening file \"" << fn_csv << "\". Reason: " << e.msg << endl;
  68. exit( 1);
  69. }
  70. // 判断img数目是否符合要求
  71. if(images. size() <= 1) {
  72. string error_message = "This demo needs at least 2 images to work. Please add more images to your data set!";
  73. CV_Error(Error::StsError, error_message);
  74. }
  75. // images的高度
  76. int height = images[ 0].rows;
  77. // 从训练集中选择一张图片作为测试集
  78. Mat testSample = images[images. size() - 1];
  79. int testLabel = labels[labels. size() - 1];
  80. images. pop_back();
  81. labels. pop_back();
  82. // 创建模型,使用LDA线性判别分析
  83. Ptr<FisherFaceRecognizer> model = FisherFaceRecognizer:: create();
  84. model-> train(images, labels); // 训练模型
  85. int predictedLabel = model-> predict(testSample); // 使用测试集测试模型
  86. // 打印准确率
  87. string result_message = format( "Predicted class = %d / Actual class = %d.", predictedLabel, testLabel);
  88. cout << result_message << endl;
  89. // 获取模型的特征值
  90. Mat eigenvalues = model-> getEigenValues();
  91. // 展示特征向量
  92. Mat W = model-> getEigenVectors();
  93. // 从训练集中获取样本均值
  94. Mat mean = model-> getMean();
  95. // 根据argc判断进行展示或保存操作
  96. if(argc == 2) {
  97. imshow( "mean", norm_0_255(mean. reshape( 1, images[ 0].rows)));
  98. } else {
  99. imwrite(format( "%s/mean.png", output_folder. c_str()), norm_0_255(mean. reshape( 1, images[ 0].rows)));
  100. }
  101. // 显示或保存特征脸
  102. for ( int i = 0; i < min( 16, W.cols); i++) {
  103. string msg = format( "Eigenvalue #%d = %.5f", i, eigenvalues. at< double>(i));
  104. cout << msg << endl;
  105. // 获取特征向量
  106. Mat ev = W. col(i). clone();
  107. // resize成原始大小,并归一化到0-255
  108. Mat grayscale = norm_0_255(ev. reshape( 1, height));
  109. // 显示图像并应用Jet颜色图以获得更好的观感。
  110. Mat cgrayscale;
  111. applyColorMap(grayscale, cgrayscale, COLORMAP_BONE);
  112. // 根据argc判断进行展示或保存操作
  113. if(argc == 2) {
  114. imshow(format( "fisherface_%d", i), cgrayscale);
  115. } else {
  116. imwrite(format( "%s/fisherface_%d.png", output_folder. c_str(), i), norm_0_255(cgrayscale));
  117. }
  118. }
  119. // 在一些预定义的步骤中显示或保存图像重建的过程:
  120. for( int num_component = 0; num_component < min( 16, W.cols); num_component++) {
  121. // 从模型中分割特征向量
  122. Mat ev = W. col(num_component);
  123. Mat projection = LDA:: subspaceProject(ev, mean, images[ 0]. reshape( 1, 1));
  124. Mat reconstruction = LDA:: subspaceReconstruct(ev, mean, projection);
  125. // 归一化
  126. reconstruction = norm_0_255(reconstruction. reshape( 1, images[ 0].rows));
  127. // 根据argc判断进行展示或保存操作
  128. if(argc == 2) {
  129. imshow(format( "fisherface_reconstruction_%d", num_component), reconstruction);
  130. } else {
  131. imwrite(format( "%s/fisherface_reconstruction_%d.png", output_folder. c_str(), num_component), reconstruction);
  132. }
  133. }
  134. // 如果没有写入输出文件夹,则等待键盘输入
  135. if(argc == 2) {
  136. waitKey( 0);
  137. }
  138. return 0;
  139. }

②编译过程:

CMakeLists.txt如下:


  
  1. cmake_minimum_required(VERSION 3.24) # 指定 cmake的 最小版本
  2. project(test) # 设置项目名称
  3. find_package(Opencv REQUIRED)
  4. INCLUDE_DIRECTORIES(${OpenCV_INCLUDE_DIRS})
  5. #add_executable(eigenfaces_demo eigenfaces.cpp) # 生成可执行文件
  6. #target_link_libraries(eigenfaces_demo ${OpenCV_LIBS} ) # 设置target需要链接的库
  7. add_executable(fisherfaces_demo fisherfaces.cpp) # 生成可执行文件
  8. target_link_libraries(fisherfaces_demo ${OpenCV_LIBS} ) # 设置target需要链接的库

  
  1. mkdir build
  2. cd build
  3. cmake ..
  4. cd ..
  5. mingw32-make

③运行及结果展示:

./fisherfaces_demo.exe ./dir.txt ./Fisherfaces_Result

特征图:

重建过程:

均值图:

5--分析

未完待续!


转载:https://blog.csdn.net/weixin_43863869/article/details/127703544
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场