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

news2024/11/28 13:29:15

目录

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数据集

①源码:

import sys
import os.path

if __name__ == "__main__":

    BASE_PATH = './ORL/att_faces/orl_faces/'
    SEPARATOR = ";"
    dir_txt = open("./dir.txt", 'w')

    label = 0
    for dirname, dirnames, filenames in os.walk(BASE_PATH):
        # dirname当前路径; dirnames当前路径下所有目录名(不包含子目录);filenames当前路径下的所有文件名(不包含子目录)
        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))
                dir_txt.write(abs_path)
                dir_txt.write(SEPARATOR)
                dir_txt.write(str(label))
                dir_txt.write("\n")
            label = label + 1
    dir_txt.close()

②运行及结果:

python create_csv.py

3--Eigenfaces复现过程

①源码:

// 引用依赖
#include "opencv2/core.hpp"
#include "opencv2/face.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <fstream>
#include <sstream>

// 使用相应的命名空间
using namespace cv;
using namespace cv::face;
using namespace std;

// 标准化函数
static Mat norm_0_255(InputArray _src) {
    Mat src = _src.getMat();
    // Create and return normalized image:
    Mat dst;
    switch(src.channels()) {
    case 1:
        cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
        break;
    case 3:
        cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC3);
        break;
    default:
        src.copyTo(dst);
        break;
    }
    return dst;
}

// 读取CSV文件函数
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(Error::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(int argc, const char *argv[]) {
    
    //检查argc是否符合要求
    if (argc < 2) {
        cout << "usage: " << argv[0] << " <csv.ext> <output_folder> " << endl;
        exit(1);
    }
    string output_folder = ".";
    if (argc == 3) {
        output_folder = string(argv[2]);
    }

    // CSV文件的路径
    string fn_csv = string(argv[1]);
    
    // 初始化存储imgs和labels的向量
    vector<Mat> images;
    vector<int> labels;

    // 读取CSV文件
    try {
        read_csv(fn_csv, images, labels);
    } catch (const cv::Exception& e) {
        cerr << "Error opening file \"" << fn_csv << "\". Reason: " << e.msg << endl;
        exit(1);
    }

    // 判断img数目是否符合要求
    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(Error::StsError, error_message);
    }

    // images的高度
    int height = images[0].rows;

    // 从训练集中选择一张图片作为测试集
    Mat testSample = images[images.size() - 1];
    int testLabel = labels[labels.size() - 1];
    images.pop_back();
    labels.pop_back();

    // 创建模型,使用PCA特征脸算法
    Ptr<EigenFaceRecognizer> model = EigenFaceRecognizer::create();
    model->train(images, labels); // 训练模型
    int predictedLabel = model->predict(testSample);  // 使用测试集测试模型

    // 打印准确率
    string result_message = format("Predicted class = %d / Actual class = %d.", predictedLabel, testLabel);
    cout << result_message << endl;
    // 获取模型的特征值
    Mat eigenvalues = model->getEigenValues();
    // 展示特征向量
    Mat W = model->getEigenVectors();
    // 从训练集中获取样本均值
    Mat mean = model->getMean();
    // 根据argc判断进行展示或保存操作
    if(argc == 2) {
        imshow("mean", norm_0_255(mean.reshape(1, images[0].rows)));
    } else {
        imwrite(format("%s/mean.png", output_folder.c_str()), norm_0_255(mean.reshape(1, images[0].rows)));
    }
    // 显示或保存特征脸
    for (int i = 0; i < min(10, W.cols); i++) {
        string msg = format("Eigenvalue #%d = %.5f", i, eigenvalues.at<double>(i));
        cout << msg << endl;
        // 获取特征向量
        Mat ev = W.col(i).clone();
        // resize成原始大小,并归一化到0-255
        Mat grayscale = norm_0_255(ev.reshape(1, height));
        // 显示图像并应用Jet颜色图以获得更好的观感。
        Mat cgrayscale;
        applyColorMap(grayscale, cgrayscale, COLORMAP_JET);
        // 根据argc判断进行展示或保存操作
        if(argc == 2) {
            imshow(format("eigenface_%d", i), cgrayscale);
        } else {
            imwrite(format("%s/eigenface_%d.png", output_folder.c_str(), i), norm_0_255(cgrayscale));
        }
    }
    // 在一些预定义的步骤中显示或保存图像重建的过程:
    for(int num_components = min(W.cols, 10); num_components < min(W.cols, 300); num_components+=15) {
        // 从模型中分割特征向量
        Mat evs = Mat(W, Range::all(), Range(0, num_components));
        Mat projection = LDA::subspaceProject(evs, mean, images[0].reshape(1,1));
        Mat reconstruction = LDA::subspaceReconstruct(evs, mean, projection);
        // 归一化
        reconstruction = norm_0_255(reconstruction.reshape(1, images[0].rows));
        // 根据argc判断进行展示或保存操作
        if(argc == 2) {
            imshow(format("eigenface_reconstruction_%d", num_components), reconstruction);
        } else {
            imwrite(format("%s/eigenface_reconstruction_%d.png", output_folder.c_str(), num_components), reconstruction);
        }
    }
    // 如果没有写入输出文件夹,则等待键盘输入
    if(argc == 2) {
        waitKey(0);
    }
    return 0;
}

②编译过程:

CMakeLists.txt如下:

cmake_minimum_required(VERSION 3.24)  # 指定 cmake的 最小版本
project(test) # 设置项目名称

find_package(Opencv REQUIRED)
INCLUDE_DIRECTORIES(${OpenCV_INCLUDE_DIRS})
add_executable(eigenfaces_demo eigenfaces.cpp) # 生成可执行文件
target_link_libraries(eigenfaces_demo ${OpenCV_LIBS} ) # 设置target需要链接的库
mkdir build

cd build

cmake ..

cd ..

mingw32-make

③运行及结果展示:

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

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

重建过程:

均值图:

4--Fisherfaces复现过程

①源码:

// 引用依赖
#include "opencv2/core.hpp"
#include "opencv2/face.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <fstream>
#include <sstream>

// 使用相应的命名空间
using namespace cv;
using namespace cv::face;
using namespace std;

// 标准化函数
static Mat norm_0_255(InputArray _src) {
    Mat src = _src.getMat();
    Mat dst;
    switch(src.channels()) {
    case 1:
        cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
        break;
    case 3:
        cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC3);
        break;
    default:
        src.copyTo(dst);
        break;
    }
    return dst;
}

// 读取csv文件函数
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(Error::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(int argc, const char *argv[]) {

    //检查argc是否符合要求
    if (argc < 2) {
        cout << "usage: " << argv[0] << " <csv.ext> <output_folder> " << endl;
        exit(1);
    }
    string output_folder = ".";
    if (argc == 3) {
        output_folder = string(argv[2]);
    }

    // CSV文件的路径
    string fn_csv = string(argv[1]);

    // 初始化存储imgs和labels的向量
    vector<Mat> images;
    vector<int> labels;
    
    // 读取CSV文件
    try {
        read_csv(fn_csv, images, labels);
    } catch (const cv::Exception& e) {
        cerr << "Error opening file \"" << fn_csv << "\". Reason: " << e.msg << endl;
        exit(1);
    }

    // 判断img数目是否符合要求
    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(Error::StsError, error_message);
    }

    // images的高度
    int height = images[0].rows;
    
    // 从训练集中选择一张图片作为测试集
    Mat testSample = images[images.size() - 1];
    int testLabel = labels[labels.size() - 1];
    images.pop_back();
    labels.pop_back();
    
    // 创建模型,使用LDA线性判别分析
    Ptr<FisherFaceRecognizer> model = FisherFaceRecognizer::create();
    model->train(images, labels); // 训练模型

    int predictedLabel = model->predict(testSample); // 使用测试集测试模型
    
    // 打印准确率
    string result_message = format("Predicted class = %d / Actual class = %d.", predictedLabel, testLabel);
    cout << result_message << endl;
    // 获取模型的特征值
    Mat eigenvalues = model->getEigenValues();
    // 展示特征向量
    Mat W = model->getEigenVectors();
    // 从训练集中获取样本均值
    Mat mean = model->getMean();
    // 根据argc判断进行展示或保存操作
    if(argc == 2) {
        imshow("mean", norm_0_255(mean.reshape(1, images[0].rows)));
    } else {
        imwrite(format("%s/mean.png", output_folder.c_str()), norm_0_255(mean.reshape(1, images[0].rows)));
    }
    // 显示或保存特征脸
    for (int i = 0; i < min(16, W.cols); i++) {
        string msg = format("Eigenvalue #%d = %.5f", i, eigenvalues.at<double>(i));
        cout << msg << endl;
        // 获取特征向量
        Mat ev = W.col(i).clone();
        // resize成原始大小,并归一化到0-255
        Mat grayscale = norm_0_255(ev.reshape(1, height));
        // 显示图像并应用Jet颜色图以获得更好的观感。
        Mat cgrayscale;
        applyColorMap(grayscale, cgrayscale, COLORMAP_BONE);
        // 根据argc判断进行展示或保存操作
        if(argc == 2) {
            imshow(format("fisherface_%d", i), cgrayscale);
        } else {
            imwrite(format("%s/fisherface_%d.png", output_folder.c_str(), i), norm_0_255(cgrayscale));
        }
    }
    // 在一些预定义的步骤中显示或保存图像重建的过程:
    for(int num_component = 0; num_component < min(16, W.cols); num_component++) {
        // 从模型中分割特征向量
        Mat ev = W.col(num_component);
        Mat projection = LDA::subspaceProject(ev, mean, images[0].reshape(1,1));
        Mat reconstruction = LDA::subspaceReconstruct(ev, mean, projection);
        // 归一化
        reconstruction = norm_0_255(reconstruction.reshape(1, images[0].rows));
        // 根据argc判断进行展示或保存操作
        if(argc == 2) {
            imshow(format("fisherface_reconstruction_%d", num_component), reconstruction);
        } else {
            imwrite(format("%s/fisherface_reconstruction_%d.png", output_folder.c_str(), num_component), reconstruction);
        }
    }
    // 如果没有写入输出文件夹,则等待键盘输入
    if(argc == 2) {
        waitKey(0);
    }
    return 0;
}

②编译过程:

CMakeLists.txt如下:

cmake_minimum_required(VERSION 3.24)  # 指定 cmake的 最小版本
project(test) # 设置项目名称

find_package(Opencv REQUIRED)
INCLUDE_DIRECTORIES(${OpenCV_INCLUDE_DIRS})
#add_executable(eigenfaces_demo eigenfaces.cpp) # 生成可执行文件
#target_link_libraries(eigenfaces_demo ${OpenCV_LIBS} ) # 设置target需要链接的库
add_executable(fisherfaces_demo fisherfaces.cpp) # 生成可执行文件
target_link_libraries(fisherfaces_demo ${OpenCV_LIBS} ) # 设置target需要链接的库
mkdir build

cd build

cmake ..

cd ..

mingw32-make

③运行及结果展示:

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

特征图:

重建过程:

均值图:

5--分析

未完待续!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/3659.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

云栖探馆!云小宝首秀遇上老司机小龙,猜猜谁赢了?

为啥人人都喜欢秋天呢&#xff1f;因为我们打喷嚏都是“爱秋”啊&#xff5e; 为啥大家会来云栖大会呢&#xff1f;因为云栖大会让我们在一“栖”啊&#xff5e; 2022云栖大会龙蜥峰会&#xff0c;小龙来啦~&#xff01; ​ 去年&#xff0c;小龙作为萌新来到云栖大会&#…

归并排序.

归并排序介绍 归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用金典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各个答案"修补"在一起,即分而治之) 归并排序的思想示…

为什么程序员会秃头?盘点程序员糟心的几大因素

程序员与脱发似乎存在某种必然的逻辑连接&#xff0c;程序员秃头已经成为大家心中的思维定势。 一提到程序员&#xff0c;难免会想起来java&#xff0c; c&#xff0c; python以及无休止的debug环节&#xff0c;不难想象经常会有程序员跳楼自杀的情况。因为实在是生存不易&…

L5W1作业1 手把手实现循环神经网络

欢迎来到课程5的第一个作业&#xff01;在此作业中&#xff0c;你将使用numpy实现你的第一个循环神经网络。 循环神经网络&#xff08;RNN&#xff09;在解决自然语言处理和其他序列任务上非常有效&#xff0c;因为它们具有“记忆”&#xff0c;可以一次读取一个输入 x⟨t⟩x^…

C语言百日刷题第六天

C语言百日刷题第六天51.鸡兔同笼问题52.输出所有形如aabb的完全平方数53.3n1问题54.输出100~999的所有水仙花数55.韩信点兵56.倒三角形57.求子序列的和58.分数化小数59.开灯问题60.蛇形填数51.鸡兔同笼问题 分析&#xff1a;小学生数学问题。设鸡为a个&#xff0c;兔为b个&…

大数据技术基础实验十:Hive实验——新建Hive表

大数据技术基础实验十&#xff1a;Hive实验——新建Hive表 文章目录大数据技术基础实验十&#xff1a;Hive实验——新建Hive表一、前言二、实验目的三、实验要求四、实验原理五、实验步骤1、启动Hive2、创建表3、显示表4、显示表列5、更改表6、删除表或者列六、最后我想说一、前…

vue学习笔记——简单入门总结(三)

文章目录1.Vue的理解&#xff1a;1.1.mvvm模型&#xff1a;1.2.vue2的数据代理&#xff1a;1.3.vue2的生命周期&#xff1a;1.4.vue中的render函数&#xff1a;1.5. mixin混入&#xff1a;2.Vue组件间通信&#xff1a;2.0.props&#xff1a;2.1.全局事件总线&#xff1a;2.2.消…

WeMos Mini ESP32-S2FN4R2介绍

WeMos Mini ESP32-S2FN4R2介绍LOLIN S2 Mini V1.0.0 ESP32-S2 4MB FLASH 2MB PSRAM WIFI开发板 &#x1f33c;功能介绍 基于 ESP32-S2FN4R2TYPE-C USB27个数字输入/输出引脚&#xff0c;所有引脚都支持中断/pwm/I2C/单线ADC、DAC、I2C、SPI、UART、USB OTG &#x1f4cd; 详细…

棋盘(马蹄集)

棋盘 难度&#xff1a;白银 0时间限制&#xff1a;1秒 巴占用内存&#xff1a;64M 求一个N*N棋盘中的方块总数。 格式 输入格式&#xff1a;输入整型N 输出格式&#xff1a;输出整型 CSDN盛溪的猫 #include<bits/stdc.h> using namespace std; int main(){ long n,sum1;…

Mybatis要点总结

一、了解orm框架 1.什么是ORM框架&#xff1a;对象关系映射&#xff08;Object Relational Mapping&#xff0c;简称ORM&#xff09;&#xff0c;该模式是为了解决面向对象与关系数据库互补匹配的现象的技术&#xff1b;orm框架是连接数据库的桥梁&#xff0c;主要提供了人持久…

大数据技术之Zookeeper总结Ⅰ

zookeeper总结目录1. Zookeeper 入门1.1 zookeeper概述1.2 Zookeeper特点1.3 ZooKeeper 数据模型的结构2. Zookeeper 本地安装2.1 本地模式安装2.2 配置参数解读3. Zookeeper 集群操作3.1 集群操作3.2 Zookeeper 集群启动停止脚本3.3 客户端命令行语法1. Zookeeper 入门 1.1 z…

数据结构七:七大排序

目录 1&#xff1a;排序的概率 2.插入排序 2.1&#xff1a;直接插入排序-----稳定 2.1.1&#xff1a;基本思想 2.2&#xff1a;希尔排序 2.2.1&#xff1a;概念&#xff1a; 3.选择排序 3.1&#xff1a;选择排序 3.1.1&#xff1a;概念 3.2:堆排序 4.交换排序 4.1&…

微信小程序自动化测试之路

1. 前言 在每次发布新版本之前、都需要回归核心功能、已确保上线后小程序也能按照预期运行. 目前这部分回归工作是由测试同事手工去验证测试用例、按照每周一版本的迭代节奏、回归就花了测试挺多时间的. 最近前端工作比较轻松、故在思考能否把这部分重复的工作交给程序自动来进…

【EhCache: 一款Java的进程内缓存框架】EhCache 是什么、代码实战 Demo

文章目录1 EhCache 是什么2 代码实战 DemoTestEH.javaehcache.xml1 EhCache 是什么 Ehcache 是一种开源的、基于标准的缓存&#xff0c;可提高性能、卸载数据库并简化可扩展性。它是最广泛使用的基于 Java 的缓存&#xff0c;因为它健壮、经过验证、功能齐全&#xff0c;并且与…

python 基于PHP+MySQL的装修网站的设计与实现

至今为止,越来越多企业公司都已经实现了线上推广,提高了企业的运营工作效率,为装修公司设计一款强大的智能装修网,集企业信息展示和信息管理于一体,结合企业与外部的在线交流功能,主要用于大力宣传企业服务、企业产品等信息,让更多的人了解,提高企业的知名度 1&#xff1a;系统…

Spring Data Neo4j(1.对象映射)

文章目录一、Spring Data Neo4j二、注释NodeIdVersion(乐观锁)PropertyRelationship一、Spring Data Neo4j Spring Data Neo4j或简称SDN是下一代Spring Data模块&#xff0c;由Neo4j&#xff0c;Inc.创建和维护。与VMware的Spring Data Team密切合作。 它支持所有官方支持的Ne…

<Linux> shell运行原理及Linux权限的理解

文章目录一、shell 命令及其运行原理shell外壳shell运行原理二、Linux 权限的概念1.用户分类2.切换用户3.用户提权三、Linux 权限管理1.文件访问者的分类&#xff08;人&#xff09;2.文件类型和访问权限&#xff08;事物属性&#xff09;四、文件权限值的表示方法1.字符表示法…

Pycharm 配置远程SSH服务器环境(切换不同虚拟环境)

1.首先在Xshell上通过conda创建新的虚拟环境 2.此时在 /home/y210101004/.conda/envs下多了刚刚创建的环境的文件夹 3.路径说明&#xff01; &#xff08;注意&#xff01;&#xff09;该环境的编译器python3.6就在.../jiayan_test/bin里面 &#xff08;注意&#xff01;&…

04.函数

一、 函数 在计算机科学中&#xff0c;子程序&#xff08;英语&#xff1a;Subroutine, procedure, function, routine, method, subprogram, callable unit&#xff09;&#xff0c;是一个大型程序中的某部分代码&#xff0c; 由一个或多个语句块组 成。它负责完成某项特定任务…

ctfshow学习记录-misc入门(图片篇-颜色通道50-59)

目录misc50misc51misc52misc53misc54misc55misc56misc57misc58misc59misc51-52的wp和脚本参考的是csdn博主&#xff1a;z.volcano 九某人的碎碎念&#xff1a;这篇一更&#xff0c;说明近期是真的没有时间写wp了。虽说好多都是之前做过的题&#xff0c;但是wp整理起来还是比较耗…