关于opencv自带的PCA降维我有话要说

关于opencv 里面的 PCA降维
今天终于把opencv自带的降维函数跑通了,花了我一天时间,,
首先得感谢这篇博客的作者:
http://blog.codinglabs.org/articles/pca-tutorial.html
看了他的“PCA的数学原理”,真的有种醍醐灌顶的感觉,把深奥的数学原理简单化,叙述形象清晰明了。


好啦,下面进入正题:
首先在降维之前我提取的VLAD特征是60*64维的,即3840维,我的图片库有5063张图片,所以降维前我的图片库的VLAD特征是5063*3840,我们给他取个名,叫VLAD_all,是5063行,3840列哦,行和列不要弄混了,我想把3840维的特征降为128维,也就是减少30倍,
最终使我的图片库特征变为5063*128,好啦,看代码:
PCA pca(before_PCA, Mat(), CV_PCA_DATA_AS_ROW, 128);
before_PCA存的就是我降维之前的库特征,就是那个5063*3840,这里不用转置直接带入就好,经过这一句之后,降维之后的特征向量是128*3840的(是128行,3840列,后面我都是严格按照行列的顺序写的,就不再赘述啦)
即Mat eigenvectors = pca.eigenvectors.clone(); 
eigenvectors里面存的就是那个128*3840的特征向量,注意这个矩阵不是降维后的结果奥,它只是中间产生的一个特征向量矩阵,这个矩阵很重要,详细了解请参考上面的“PCA的数学原理”,
好啦,下面开始最重要的:
Mat VLAD_all_pca = eigenvectors*VLAD_all.t();
注意这里用的是VLAD_all的转置哦,否则矩阵相乘的行和列对应不起来会中断,下面来分析这一行最重要的代码:
eigenvectors是128*3840的特征向量,VLAD_all.t()是3840*5063的库VLAD特征的转置,这样就正好可以对应起来了,eigenvectors是3840列,VLAD_all.t()是3840行,正好可以对应相乘,,好啦,同学们猜猜看相乘的结果VLAD_all_pca存的数据行和列分别是多少,
没错,这个VLAD_all_pca就是128*5063(视情况进行转置,我就在转置这一块吃过亏),现在我们把他作为图片库的新VLAD特征,这个才是讲过PCA降维之后的真正的图片库特征。是不是比之前的5063*3840少了好多,原本的5063*3840xml文件是327M,
降维后VLAD_all_pca的xml文件是10.9M,对,小了30倍,也就是说速度提高30倍(当然这个说法很粗鲁实际上会有很多别的时间开销)。
好啦,上代码:

//****************************原图,读图片路径,读xml文件路径三个地方都需要改,还有 pictures_num****************************

#include <boost/lexical_cast.hpp>       
#include <iostream>    
#include <string>
#include <iostream>
#include <vector>
#include <boost/filesystem.hpp>
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <opencv/ml.h>
#include <opencv2/nonfree/features2d.hpp>
#include <string>
#include <iostream>
#include <vector>
#include <boost/filesystem.hpp>
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <opencv/ml.h>
#include <opencv2/nonfree/features2d.hpp>
using namespace boost::filesystem;
using namespace std;
using namespace cv;
//#pragma comment( lib, "opencv_highgui249d.lib")
//#pragma comment( lib, "opencv_core49d.lib")
//全局变量们
#define numClusters 60 //聚类中心数,如果调用Extract_VLAD_Features函数,在surf下numClusters不大于64,在sift情况下numClusters应该是不大于128
Mat Descriptor_all(0, 64, CV_32FC1);
Mat VLAD_all(0, 64 * numClusters, CV_32FC1);//存储图片库总体的VLAD特征,
Mat centers(numClusters, 64, CV_32FC1);//其实这里的centers不定义大小也可以,聚类结束后centers里面自动存储聚类结果 centers(numClusters, 128, CV_32FC1);
Mat labels(0, numClusters, CV_32FC1);

Mat Extract_VLAD_Features(Mat &descriptors, Mat ¢ers, float alpha = 1);
float ComputeSimilarity(Mat vlad_feat_query, Mat vlad_feat_train);
void Extractor_allDescriptors(path&basepath);
void Extractor_allVLAD(char filePath[150], int n_picture);// 读取 n_picture 张图片



int main(){
	double time = static_cast<double>(getTickCount());

	FileStorage fsd("D:/kmeans_data/centers60_64_74picture.xml", FileStorage::READ);
	fsd["centers"] >> centers;
	fsd.release();

	//读取库图片的VLAD 特征向量
	double timedata = static_cast<double>(getTickCount());
	FileStorage fvlad("D:/kmeans_data/all_VLAD5063.xml", FileStorage::READ);
	fvlad["VLAD_all"] >> VLAD_all;
	fvlad.release();

	timedata = ((double)getTickCount() - timedata) / getTickFrequency();
	cout << "读VLAD_all数据用时:" << timedata << "秒" << endl << endl;

	////////降维处理,生成降维所需的特征向量:
	//double PCA_time = static_cast<double>(getTickCount());
	//int pca_num = 128;//降至128维
	//Mat before_PCA = VLAD_all.clone();//before_PCA用来存放降维之前的维度特征,它是VLAD_all的转置,即before_PCA是60*64行,5063列,5063是fvlad读取的图库特征数,图库是多少张图片before_PCA就有多少列,
	//Mat after_PCA_eigenvectors;//存放降维后的特征向量
	//cout << "正在进行PCA降维..." << endl;
	//PCA pca(before_PCA, Mat(), CV_PCA_DATA_AS_ROW, pca_num);
	//Mat eigenvectors = pca.eigenvectors.clone();//eigenvectors用来存放降维后的特征向量
	//PCA_time = ((double)getTickCount() - PCA_time) / getTickFrequency();
	//cout << "PCA降维用时:" << PCA_time << "秒" << endl << endl;
	//FileStorage f_pca("D:/kmeans_data/after_PCA_eigenvectors.xml", FileStorage::WRITE);
	//f_pca << "after_PCA_eigenvectors" << eigenvectors;
	//f_pca.release();

	////////读取上面的特征向量,对输入数据进行真正的降维处理:
	double time_T = static_cast<double>(getTickCount());
	Mat after_PCA_eigenvectors;//存放降维后的特征向量
	FileStorage f_pca("D:/kmeans_data/after_PCA_eigenvectors.xml", FileStorage::READ);
	f_pca["after_PCA_eigenvectors"] >> after_PCA_eigenvectors;
	f_pca.release();
	Mat VLAD_all_pca = after_PCA_eigenvectors*VLAD_all.t();//VLAD_all_pca用于存放真正降维后的 all_VLAD5063 数据

	FileStorage fs_pca("D:/kmeans_data/VLAD_all_pca.xml", FileStorage::WRITE);
	fs_pca << "VLAD_all_pca" << VLAD_all_pca;
	fs_pca.release();
	cout << "已成功提取降维后数据!" << endl;

	time_T = ((double)getTickCount() - time_T) / getTickFrequency();
	cout << "读取特征、PCA矩阵相乘用时:" << time_T << "秒" << endl << endl;

	time = ((double)getTickCount() - time) / getTickFrequency();
	cout << "总共用时:" << time << "秒" << endl << endl;

	system("pause");
	return 0;
}

下面来看看效果:右下三个图片是在5063张酷图片里面找的和原图最相似的三张图,



第一张是降维之前的识别结果,后两张是降维之后的识别结果,可以看到特征从3840维降到128维之后识别效果好像还是挺好的,细心的同学可以看到我的数据,降维前的识别速度大概是9.8S,降维后1.3S,当然这还包括读文件什么的,很多环节都可以优化的哦。

其实我之前还参考了这里:http://blog.csdn.net/u010555682/article/details/52563970

只是觉得他提取的特征向量的行列和我的有出入,可能是我没理解透彻吧,童鞋们怕被绕就别看他的了.

奥,对了,关于VLAD特征做图片检索可以参考这个人写的文章,虽然我不喜欢这个作者,但文章还是有参考价值的:

http://www.cnblogs.com/mafuqiang/p/6909556.html

想细细研究图像检索可以看这篇硕士论文,写的很不错:基于GMM_VLAD的图像检索_陈曼玉

猜你喜欢

转载自blog.csdn.net/guanyonglai/article/details/78418078
今日推荐