OpenCV  4.10.0
开源计算机视觉
正在加载...
正在搜索...
无匹配项
samples/cpp/pca.cpp

一个使用PCA进行降维并保持一定量方差变化的示例

/*
* pca.cpp
*
* 作者
* Kevin Hughes <kevinhughes27[at]gmail[dot]com>
*
* 特别感谢
* Philipp Wagner <bytefish[at]gmx[dot]de>
*
* 此程序演示了如何使用OpenCV PCA实现
* 指定保留的方差量。通过使用滑动条来
* 改变保留方差值,进一步展示了效果。
* 程序接受一个文本文件作为输入,每行
*
* 包含一个完整图像路径。PCA将对该
* 图像列表应用。作者建议使用
* AT&T人脸数据集的前15个面孔
* http://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html
* 因此,例如,您的输入文本文件可能如下所示
*
* <path_to_at&t_faces>/orl_faces/s1/1.pgm
*
* <path_to_at&t_faces>/orl_faces/s2/1.pgm
* <path_to_at&t_faces>/orl_faces/s3/1.pgm
* <path_to_at&t_faces>/orl_faces/s4/1.pgm
* <path_to_at&t_faces>/orl_faces/s5/1.pgm
* <path_to_at&t_faces>/orl_faces/s6/1.pgm
m <path_to_at&t_faces>/orl_faces/s7/1.pgm
* <path_to_at&t_faces>/orl_faces/s8/1.pgm
* <path_to_at&t_faces>/orl_faces/s9/1.pgm
* <path_to_at&t_faces>/orl_faces/s10/1.pgm
* <path_to_at&t_faces>/orl_faces/s11/1.pgm
* <path_to_at&t_faces>/orl_faces/s12/1.pgm
* <path_to_at&t_faces>/orl_faces/s13/1.pgm
* <path_to_at&t_faces>/orl_faces/s14/1.pgm
* <path_to_at&t_faces>/orl_faces/s15/1.pgm
*
*/
#include <iostream>
#include <fstream>
#include <sstream>
#include <opencv2/core.hpp>
使用命名空间 cv;
使用命名空间 std;
// 函数
静态 void read_imgList(const string& filename, vector<Mat>& images) {
std::ifstream file(filename.c_str(), ifstream::in);
如果 (!file) {
string error_message = "未提供有效的输入文件,请检查给出的文件名。";
CV_Error(Error::StsBadArg, error_message);
}
string line;
(getline(file, line)) {
images.push_back(imread(line, IMREAD_GRAYSCALE));
}
}
Mat formatImagesForPCA(const vector<Mat> &data)
{
Mat dst(static_cast<int>(data.size()), data[0].rows*data[0].cols, CV_32F);
(unsigned int i = 0; i < data.size(); i++)
{
Mat image_row = data[i].clone().reshape(1,1);
Mat row_i = dst.row(i);
image_row.convertTo(row_i,CV_32F);
}
}
静态 Mat toGrayscale(InputArray _src) {
Mat src = _src.getMat();
// 仅允许一个通道
if(src.channels() != 1) {
CV_Error(Error::StsBadArg, "仅支持单通道的矩阵");
}
// 创建并返回归一化图像
Mat dst;
cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
}
结构体 params
{
Mat data;
int ch;
int rows;
PCA pca;
string winName;
};
静态 void onTrackbar(int pos, void* ptr)
{
cout << "保留变异性 = " << pos << "% ";
cout << "重新计算PCA..." << std::flush;
double var = pos / 100.0;
结构体 params *p = (结构体 params *)ptr;
p->pca = PCA(p->data, cv::Mat(), PCA::DATA_AS_ROW, var);
Mat point = p->pca.project(p->data.row(0));
Mat reconstruction = p->pca.backProject(point);
reconstruction = reconstruction.reshape(p->ch, p->rows);
reconstruction = toGrayscale(reconstruction);
imshow(p->winName, reconstruction);
cout << "完成! 主要成分数量: " << p->pca.eigenvectors.rows << endl;
}
// 主程序
int main(int argc, char** argv)
{
cv::CommandLineParser parser(argc, argv, "{@input||image list}{help h||显示帮助信息}");
if (parser.has("help"))
{
parser.printMessage();
exit(0);
}
// 获取CSV文件路径。
string imgList = parser.get<string>("@input");
if (imgList.empty())
{
parser.printMessage();
exit(1);
}
// 保存图像的vector
vector<Mat> images;
// 读取数据。这可能失败,如果无效
try {
read_imgList(imgList, images);
}catch(const cv::Exception& e) {
cerr << "无法打开文件 \"" << imgList << "\". 原因: " << e.msg << endl;
exit(1);
}
// 如果演示没有足够的图像,则退出。
如果(images.size() <= 1) {
string error_message = "这个演示需要一个至少2张图片才能运行。请为您的数据集添加更多图片!";
CV_Error(Error::StsError, error_message);
}
// 将图片重新塑形组合为行矩阵
Mat data = formatImagesForPCA(images);
// 执行主成分分析
PCA pca(data, cv::Mat(), PCA::DATA_AS_ROW, 0.95); // 初始化跟踪条这里,这也是保留方差的一个常见值
// 展示保留方差对第一张图片的影响
Mat point = pca.project(data.row(0)); // 将其投影到特征空间,因此图片成为一个“点”
Mat reconstruction = pca.backProject(point); // 从“点”重新创建图片
reconstruction = reconstruction.reshape(images[0].channels(), images[0].rows); // 从行向量重塑为图片形状
reconstruction = toGrayscale(reconstruction); // 为了显示目的进行缩放
// 初始化高GUI窗口
string winName = "重建 | 按 'q' 退出";
namedWindow(winName, WINDOW_NORMAL);
// params结构体用于传递给跟踪条处理器
params p;
p.data = data;
p.ch = images[0].channels();
p.rows = images[0].rows;
p.pca = pca;
p.winName = winName;
// 创建跟踪条
int pos = 95;
createTrackbar("保留方差 (%)", winName, &pos, 100, onTrackbar, (void*)&p);
// 用户按q键之前显示
imshow(winName, reconstruction);
char key = 0;
while(key != 'q')
key = (char)waitKey();
return 0;
}
用于命令行解析。
定义 utility.hpp:820
类传递给错误。
定义 core.hpp:115
String msg
格式化的错误信息
定义 core.hpp:134
n维稠密数组类
定义 mat.hpp:812
CV_NODISCARD_STD Mat clone() const
创建数组和底层数据的完整副本。
Mat row(int y) const
为指定矩阵行创建矩阵头。
Mat reshape(int cn, int rows=0) const
在不复制数据的情况下改变二维矩阵的形状和/或通道数。
int channels() const
返回矩阵的通道数。
void convertTo(OutputArray m, int rtype, double alpha=1, double beta=0) const
将数组转换为另一种数据类型,带有可选缩放。
主成分分析。
定义 core.hpp:2513
这是传递只读输入数组的代理类。
定义 mat.hpp:160
Mat getMat(int idx=-1) const
void normalize(InputArray src, InputOutputArray dst, double alpha=1, double beta=0, int norm_type=NORM_L2, int dtype=-1, InputArray mask=noArray())
对数组进行规一化或者调整值域。
#define CV_32F
定义 interface.h:78
#define CV_8UC1
定义 interface.h:88
#define CV_Error(code, msg)
调用错误处理函数。
定义 base.hpp:320
void imshow(const String &winname, InputArray mat)
在指定的窗口中显示图像。
int waitKey(int delay=0)
等待按键被按下。
void namedWindow(const String &winname, int flags=WINDOW_AUTOSIZE)
创建一个窗口。
int createTrackbar(const String &trackbarname, const String &winname, int *value, int count, TrackbarCallback onChange=0, void *userdata=0)
创建一个滑块并将其附加到指定的窗口。
int main(int argc, char *argv[])
定义 highgui_qt.cpp:3
PyParams params(const std::string &tag, const std::string &model, const std::string &weights, const std::string &device)
与磁盘上文件关联的文件存储的“黑盒”表示。
定义 core.hpp:102
STL命名空间。