降维在机器学习领域其实是很重要的一部分,因为在高维情形下回出现样本稀疏,计算距离、内积困难,是所有机器学习面临的共同问题,被称为维数灾难(Curse of dimensionality),而降维就是解决的一个办法,它不仅让运算量变简单,还因为将原始数据投影在主特征分量上可以抵抗一些噪声的干扰。因为想通过降维来缩小图像配准过程中特征点匹配的运算量,也在公众号机器学习算法工程师中看到了一些降维的方法,比如PCA、核化(kernelized,应该就是核机制吧,实现非线性降维)、流行学习、度量学习。当然最成熟的还是PCA,虽然很早就出现了PCA-SIFT,但还是想先自己动手实现一下。思路是先导出Lowe格式的特征点txt文件,然后再在import的时候修改函数降维,写入descr_pca数组中再导出,得到64维的特征点。这时再导入降维之后的数据,通过这些数据来实现图像配准。
这时候就又出现问题了,构建kd树的过程很慢,而且无法得到配准结果。后来才意识到自己用的boat的图像的特征点数据却在实验中用的beaver图像,当改正这个错误,并且导入原始的特征点数据后做实验,结果匹配对的错误率很高,怀疑是不是因为stack_imgs把两幅图像显示在一起,造成坐标变换的原因。但是最起码img1部分的特征点应该正常啊,现在的情况是完全不对。。
从调试情况来看,import部分没有问题,第一个点都是(254,297),对应的第二幅图中检测到的是(134,258),与txt中的数据吻合。在Lowe格式的txt特征点文件中,第一行是特征点个数和描述子维数,对每一个特征点,第一行四个数据依次是特征点的y坐标,x坐标,特征点的尺度,特征点的方向,然后是128个double型数字https://blog.csdn.net/masibuaa/article/details/9204157。问题似乎出在构建kd树之后的寻找匹配对的过程中。Kd树是对图2的特征点feat2构建的,对feat1中的特征点遍历,在kd树中寻找对应的匹配点。找到的第一对是(3,15)-(4,20).
源码,尤其是c语言,对指针的运用真的是好复杂。如下,在导入特征点中和对kd树中进行knn查找的过程中分别有两重指针和三重指针。
static int import_lowe_features( char*filename, struct feature** features )//静态函数,不能被其他文件使用,所以其他文件也可以有相同的函数名
int kdtree_bbf_knn( struct kd_node*kd_root, struct feature* feat, int k,
struct feature*** nbrs, int max_nn_chks )
在import_lowe_features函数中,有下面关键的两句:
f = calloc( n, sizeof(struct feature) );//在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针
*features = f;//相当于feature=&f??把features复数指向f //首地址赋给*features
于是,将import_features(path1, 1, &feat1);改为import_features(path1,1, import_feat1);//第三个参数是指针的指针,struct feature** import_feat1=NULL//初始化,运行的时候异常。
看来还是要用&feat1,因为源码中原始的特征点检测也是这么写的:n1 = sift_features( img1, &feat1 );
后来发现在 feat = feat1 + i;//指针的加法 之前,动态分配长度为n的内存之后,fscanf坐标值的时候就出错了。fscanf读取txt文件,要求txt文件编码方式为ANSI,这个没有出错。
fscanf( file, " %lf %lf %lf %lf", &y, &x, &s, &o ) != 4 )//%lf是double类型输入 fscanf返回读取的长度
两个格式控制符%lf之间是空格,适用于数据之间是空格,若数据之间是逗号,格式控制符之间也是逗号,这个也没有出错。
结果,尴尬了,一步步调试,看第一个特征点的各个参数,坐标是对的,一个个看128维描述子,发现到64的时候就跳变为第二个特征点了。真相大白,原来是自己在做导入降维后的txt文件时把d修改为64,在这里验证128维的时候忘记改回去了。。
如下是按照lowe格式导入特征点信息做的图像配准:
其中特征点导入费时4s左右。
这是直接对图像做的特征点检测和配准:
其中特征点检测就耗时26s
回头再看导入64维的描述子。速度奇慢,且无法完成配准。报错说找到的匹配对太少。打开降维后的txt文件:
7875 64
297.440434 254.241265 80.338874 -1.866019
2 01 0 0 0 0 0 -1 0 0 0 0 0 0 0 -1 0 0 0
0 00 0 3 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0
-1 00 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 1 0 0
0 00 0
557.449920 181.560168 42.599985 1.464965
4 -10 -1 0 0 0 3 0 0 1 0 0 0 0 0 -1 -1 0 0
0 00 0 0 -2 1 0 0 0 0 0 3 1 -1 1 0 0 0 1
0 21 0 0 0 0 -1 -3 0 -1 0 0 0 0 -1 -2 0 0 0
0 00 -1
可以看到64个特征数据,分为20*3+4.而在导入的时候,特征点的坐标是取一行四个数值那行的前两个值的,这样就会把一部分描述子也误当做坐标值和尺度大小即梯度。
Pcad 过程中对特征值和特征向量的行列数还是认识不够,最后将result写成方阵才不中断。后来导出成了4*4维的描述子。这样再导入到程序中来配准,找到500多个匹配对,但是画不出匹配的连线。调试过程中发现匹配对也不正确,会不会是降维后kd树中查找knn中阈值也要改变。