最近在看图像匹配方面的资料,图像匹配的主要步骤是:
1.提取特征点:在两张待匹配的图像中寻找最容易识别的像素点,如角点或者纹理丰富的物体边缘点。
2.特征点描述子:对于检测出的特征点,用一些数学上的特征对其进行描述。常 用的描述子类型有FAST,SIFT,SURF,ORB,HARRIS,FREAK。
3.特征点之间的匹配:计算两幅图像中特征点的相似度,如欧氏距离、Hausdoff、马氏距离等。
4.去除错误匹配的点:对匹配上的点进行筛选,保留正确匹配点。常用的方法:Ransac,GTM。
用了SIFT做匹配,发现匹配的效果不理想,并且在cv里是nonfree的,找到的keypoint非常多,需要对找到的关键点进行筛选。继续找资料发现了ORB和FREAK,听说FREAK比SURF和ORB更牛X,模拟的是人眼的视网膜成像原理。ORB论文资料还没仔细看,博友的说法是:用FAST作为特征点提取的算法,FAST提取特征点的速度是很快,并在此基础上添加特征点的主方向,使得ORB具有旋转不变性。在匹配上ORB采用贪婪穷举的方法得到相关性较低的随机点对,通过阅读代码知道,ORB采用暴力方式测试Keypoints的距离,用到的是海明距离(Hamming Distance)。另一个改进是对于随机点对,ORB不在使用像素点的直接比较,而是选择该像素为中心的一个小patch作为比较对象,提高了抗噪能力。
unsigned int hamdist(unsigned int x, unsigned int y)
{
unsigned int dist = 0, val = x ^ y;
// Count the number of set bits
while(val)
{
++dist;
val &= val - 1;
}
return dist;
}
unsigned int hamdist2(unsigned char* a, unsigned char* b, size_t size)
{
HammingLUT lut;
unsigned int result;
result = lut((a), (b), size);
return result;
}
这段代码是计算海明距离的,第一个函数计算了两个unsigned int类型数据的海明距离,与第二个函数的区别是,后者是计算两个unsigned char 类型数组之间总的距离。
void naive_nn_search2(vector& keys1, Mat& descp1, vector& keys2, Mat& descp2, vector& matches)
{
for( int i = 0; i < (int)keys2.size(); i++)
{
unsigned int min_dist = INT_MAX;
unsigned int sec_dist = INT_MAX;
int min_idx = -1, sec_idx = -1;
unsigned char* query_feat = descp2.ptr(i);
for( int j = 0; j < (int)keys1.size(); j++)
{
unsigned char* train_feat = descp1.ptr(j);
unsigned int dist = hamdist2(query_feat, train_feat, 32);
//最短距离
if(dist < min_dist)
{
sec_dist = min_dist;
sec_idx = min_idx;
min_dist = dist;
min_idx = j;
}
//次短距离
else if(dist < sec_dist)
{
sec_dist = dist; sec_idx = j;
}
}
if(min_dist <= (unsigned int)(sec_dist * 0.8) && min_dist <=50)
{
matches.push_back(DMatch(i, min_idx, 0, (float)min_dist));
}
}
}
int main(int argc, char* argv[])
{
Mat img1 = imread(image_filename1, 1);
Mat img2 = imread(image_filename2, 1);
//GaussianBlur(img1, img1, Size(5, 5), 0);
//GaussianBlur(img2, img2, Size(5, 5), 0);
ORB orb1(100 /*ORB::CommonParams(1.2, 1)*/);
ORB orb2(10 /*ORB::CommonParams(1.2, 1)*/);
vector keys1, keys2;
Mat descriptors1, descriptors2;
int64 st, et;
//提取ORB特征;
orb1(img1, Mat(), keys1, descriptors1, false);
printf("tem feat num: %d\n", keys1.size());
st = cvGetTickCount();
orb2(img2, Mat(), keys2, descriptors2, false);
et = cvGetTickCount();
printf("orb2 extraction time: %f\n", (et-st)/(double)cvGetTickFrequency()/1000.);
printf("query feat num: %d\n", keys2.size());
// find matches
vector matches;
st = cvGetTickCount();
for(int i = 0; i < 10; i++)
{
naive_nn_search2(keys1, descriptors1, keys2, descriptors2, matches);
}
et = cvGetTickCount();
printf("match time: %f\n", (et-st)/(double)cvGetTickFrequency()/1000.);
printf("matchs num: %d\n", matches.size());
Mat showImg;
drawMatches(img2, keys2, img1, keys1, matches, showImg, CV_RGB(0, 255, 0), CV_RGB(0, 0, 255));
string winName = "Matches";
namedWindow( winName, WINDOW_AUTOSIZE );
imshow( winName, showImg );
waitKey(0);
}
运行结果为: