特征点提取与匹配
特征点概述
如何高效且准确的匹配出两个不同视角的图像中的同一个物体,是许多计算机视觉应用中的第一步。虽然图像在计算机中是以灰度矩阵的形式存在的,但是利用图像的灰度并不能准确的找出两幅图像中的同一个物体。这是由于灰度受光照的影响,并且当图像视角变化后,同一个物体的灰度值也会跟着变化。所以,就需要找出一种能够在相机进行移动和旋转(视角发生变化),仍然能够保持不变的特征,利用这些不变的特征来找出不同视角的图像中的同一个物体。
为了能够更好的进行图像匹配,需要在图像中选择具有代表性的区域,例如:图像中的角点、边缘和一些区块,但在图像识别出角点是最容易,也就是说角点的辨识度是最高的。所以,在很多的计算机视觉处理中,都是提取交掉作为特征,对图像进行匹配,例如SFM,视觉SLAM等。
例如:相机从远处得到的是角点,但是在近处就可能不是角点;或者,当相机旋转后,角点就发生了变化。为此,计算机视觉的研究者们设计了许多更为稳定的的特征点,这些特征点不会随着相机的移动,旋转或者光照的变化而变化。例如:SIFT,SURF,ORB等
一个图像的特征点由两部分构成:关键点(Keypoint)和描述子(Descriptor)。
关键点指的是该特征点在图像中的位置,有些还具有方向、尺度信息;描述子通常是一个向量,按照人为的设计的方式,描述关键点周围像素的信息。通常描述子是按照外观相似的特征应该有相似的描述子设计的。因此,在匹配的时候,只要两个特征点的描述子在向量空间的距离相近,就可以认为它们是同一个特征点。
特征点的匹配通常需要以下三个步骤
- 提取图像中的关键点,这部分是查找图像中具有某些特征(不同的算法有不同的)的像素
- 根据得到的关键点位置,计算特征点的描述子
- 根据特征点的描述子,进行匹配
特征点描述子
- 一个好的描述子是准确匹配的基础
- 从图像中提取到特征的关键点信息,通常只是其在图像的位置信息(有可能包含尺度和方向信息),仅仅利用这些信息无法很好的进行特征点的匹配 ,所以就需要更详细的信息,将特征区分开来,这就是特征描述子
- 特征的描述子通常是一个精心设计的向量,描述了关键点及其周围像素的信息。
- 为了能够更好的匹配,一个好的描述子通常要具有以下特性:
- 不变性 指特征不会随着图像的放大缩小旋转而改变。
- 鲁棒性 对噪声、光照或者其他一些小的形变不敏感
- 可区分性 每一个特征描述子都是独特的,具有排他性,尽可能减少彼此间的相似性。
- 特征点的不变性主要体现在两个方面:
尺度不变性
旋转不变性
常用的特征点算法
- 图像的特征点包含两个部分
- 特征点的提取,在图像检测到特征点的位置
- 特征点的描述,也就是描述子。
SIFT
SURF
FAST
OpenCV3中的特征图提取与匹配
int main() {
Mat img1 = imread("F:\\test\\1.jpg");
Mat img2 = imread("F:\\test\\2.jpg");
// 1.初始化
std::cout << "init" << std::endl;
vector<KeyPoint> keypoints1, keypoint2;
Mat descriptors1, descriptors2;
Ptr<ORB> orb = ORB::create();
// 2.提取特征点
std::cout << "detect" << std::endl;
orb->detect(img1, keypoints1);
orb->detect(img2, keypoint2);
// 3.计算特征描述符
std::cout << "compute" << std::endl;
orb->compute(img1, keypoints1, descriptors1);
orb->compute(img2, keypoint2, descriptors2);
// 4.对两幅图像的BRIEF描述符进行匹配,使用BFMatch,Hanming距离作为参考.
std::cout << "match" << std::endl;
vector<DMatch> matches;
BFMatcher bfMatcher(NORM_HAMMING);
bfMatcher.match(descriptors1, descriptors2, matches);
//imshow("output", matches);
std::cout << "draw matches" << std::endl;
Mat image_matches;
drawMatches(img1, keypoints1, img2, keypoint2, matches,
image_matches, Scalar(0, 255, 0), Scalar::all(-1), vector<char>(), 0);
imshow("matches", image_matches);
waitKey(0);
return 0;
}