OpenCV中使用PCA主成分分析,将图片降维分类。用很多张手写数字0-9演示。
首先,使用终端到工作目录输入:ls num/*.png > num.dat 得到num.dat文件(存储所有图片路径)
采用PCA降维后可以看到,没有标签的图片有了大致形状,通过结合标签学习,把分类图片映射到basis空间后的相似度用于识别数字。
#include
#include
#include
#include
#include
#include
using namespace cv;
using namespace std;
class MyPCA
{
public:
vector featuresImg;
Mat result;
PCA pca;
MyPCA(const string filename, int show = 0, int maxComponents = 10, const string winName = "Features") {
this->show = show;
this->maxComponents = maxComponents;
this->winName = winName;
// Read in the data. This can fail if not valid
try {
read_imgList(filename, images);
}
catch (cv::Exception& e) {
cerr << "Error opening file \"" << filename << "\". Reason: " << e.msg << endl;
exit(1);
}
// Quit if there are not enough images for this demo.
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);
}
data = formatImagesForPCA(images);
// perform PCA
pca = PCA(data, cv::Mat(), PCA::DATA_AS_COL, maxComponents);
pca.project(data, result);
showAllFeatures();
}
// show the result feature images
void showAllFeatures() {
Mat img;
for(int i = 0; i < result.rows; i++){
img = result.row(i);
img = img.reshape(images[0].channels(), images[0].rows);
featuresImg.push_back(img);
}
if (show){
for (int i = 0; i < featuresImg.size(); i++){
imshow(winName+(char)i, featuresImg[i]);
}
}
}
void test() {
cout << "Data size " << data.size() << endl;
cout << "Result size " << result.size() << endl;
cout << "Features size "< images;
// Reshape and stack images into a rowMatrix
Mat data;
int maxComponents;
int ch;
int rows;
string winName;
void read_imgList(const string& filename, vector& images) {
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;
while (getline(file, line)) {
images.push_back(imread(line, 0));
}
cout << "Read success. " << images.size() << " pictures." << endl;
}
Mat formatImagesForPCA(const vector &data) {
Mat dst(static_cast(data.size()), data[0].rows*data[0].cols, CV_32F);
for (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);
}
return dst;
}
Mat toGrayscale(InputArray _src) {
Mat src = _src.getMat();
// only allow one channel
if (src.channels() != 1) {
CV_Error(Error::StsBadArg, "Only Matrices with one channel are supported");
}
// create and return normalized image
Mat dst;
cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
return dst;
}
};
int main()
{
string filename = "num.dat";
MyPCA pca(filename, 1);
pca.test();
int key = 0;
while (key != 'q')
key = waitKey();
//delete pca;
return 0;
}
运行结果: