目录
- 特征点检测
- 描述子计算
- 特征点匹配
- 绘图
- 各类函数的一些从属关系
特征点检测
特征点检测是指利用detecter去检测图像中感兴趣的点,一般指角点,边缘点等等,其中各类特征点的也有不同的定义方式,譬如角点有harris角点,FAST角点等等。以FAST角点为例(FAST角点属于ORB特征)。
步骤1:定义KeyPoint容器;
KeyPoint是C++中的一个模板类。可以理解为一种特殊的数据结构,检测出来的角点通常要存储起来,形成一个KeyPoint类型的容器(vector)。
步骤2:定义检测器(detector);
**detector可以看作是一个工具(函数),其功能是用于检测特征点,一般定义opencv中的Ptr智能指针指向一个detector,然后初始化为相应的特征。
步骤3:进行检测;
检测的过程很简单,调用相应的detect函数即可。代码如下:
std::vector<KeyPoint> keypoints;
//定义KeyPoint容器
Ptr<FeatureDetector> detector = ORB::create();
//定义检测器,初始化为相应的特征,
detector->detect(image, keypoints);
//进行检测,image为图像,是一个mat矩阵,检测点存于keypoints中
注释:
KeyPoint类下的属性以及访问方式:
①KeyPoint.pt;KeyPoint.pt.x;KeyPoint.pt.y;分别返回point2d类;x坐标,y坐标;**
②KeyPoint.size;特征点领域大小;
③KeyPoint.angle;特征点的角度;
④KeyPoint.response;特征点的强度;
⑤KeyPoint.octave;特征点所属金字塔的层数;
detect函数:
detector->detect(图像mat,容器keypoint);注意参数的类型
描述子计算
描述子是指对特征点周围的信息进行描述,常常以向量的形式进行表达,常见的描述子有 BRIEF,SIFT等等,像BRIEF描述子的基本原理是随机选取特征点附近的一对点,然后进行τ测试,将结果表达为向量。以BRIEF描述子为例,opencv中计算描述子的步骤如下:
步骤1:定义Mat矩阵;
以向量的形式存储描述子。
步骤2:定义描述器(descriptor);
同特征点的检测一样,定义一个Ptr智能指针,然后访问相应的描述子计算函数。
步骤3:计算描述子;
代码如下:
Mat descriptors;
//存放描述子
Ptr<DescriptorExtractor> descriptor = ORB::create();
//建立描述器
descriptor->compute(image, keypoints, descriptors);
//计算描述子
注释:
descriptor->comput(图像mat,容器keypoint,描述子矩阵mat);注意参数的类型
特征匹配
特征匹配是指对多张图像中相同的特征点一一对应起来,通俗地讲就是找相同点。通常匹配时是求解描述子的距离,各种距离的定义也不一样,在ORB特征匹配过程中采用的是汉明距离。特征匹配的意义不言而喻,在CV中的应用也非常广泛。特征匹配的步骤如下:
步骤1:定义Dmatch容器;
匹配时,需要把两种图像匹配点的信息,如坐标等等进行存储,一般是定义Dmatch容器。
步骤2:定义匹配器(matcher);
步骤3:开始匹配;
代码如下:
vector<DMatch> match;
//定义容器
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");
//定义匹配器,选择匹配方式
matcher->match(descriptors_1, descriptors_2, match);
//进行匹配
注释:
DMatch类的属性以及访问方法:
①match.distance;距离
②match.queryIdx;特征点1在keypoints_1的下标(索引),注意keypoints_1是一个vector;
③match.queryIdx;特征点1’ 在keypoints_2的下标(索引),注意keypoints_2也是一个vector;
举例:
**在第0个match中,我们可以看见,keypoints_1的第4个特征点与keypoints_2的第157个特征点是匹配的,并且汉明距离是22。
④参数:matcher->match(descriptors_1(描述子mat), descriptors_2(描述子mat), match(Dmatch类,存放结果));
特征筛选
特征筛选指把不合理的特征去除掉,通常是考察描述子之间的距离,当举例过大或者过小(每种距离不一样)时,则证明该匹配是错误匹配。
代码如下:
//找出所有匹配之间的最小距离和最大距离,
即是最相似的和最不相似的两组点之间的距离
double min_dist = 10000, max_dist = 0;
for (int i = 0; i < descriptors_1.rows; i++) {
double dist = match[i].distance;
if (dist < min_dist) min_dist = dist;
if (dist > max_dist) max_dist = dist;
}
printf("-- Max dist : %f \n", max_dist);
printf("-- Min dist : %f \n", min_dist);
//当描述子之间的距离大于两倍的最小距离时,
即认为匹配有误.但有时候最小距离会非常小,设置一个经验值30作为下限.
for (int i = 0; i < descriptors_1.rows; i++) {
if (match[i].distance <= max(2 * min_dist, 30.0)) {
matches.push_back(match[i]);
}
}
绘图
为了可视化,筛选好的匹配点可以绘制出来,基本的语句如下:
画特征点
Mat outimg1;
drawKeypoints(img_1, keypoints_1, outimg1, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
drawKeypoints()函数有5个参数,前三个参数依次为:原图像mat,keypoint容器,输出图像mat。
画匹配图
Mat img_match;
drawMatches(img_1, keypoints_1, img_2, keypoints_2, good_matches, img_goodmatch);
drawMatches()函数一共有6个参数,分别为:原图像1mat,keypoints_1容器,原图像2mat,keypoints_2容器,输出匹配图mat
效果如下:
各类函数的一些从属关系
学这一块的时候,我发现编程的时候特别乱,所以特地看了看opencv中的doucument,对各类函数以及类之间的关系有了一定的轮廓,也方便后面的学习。
继续学习中,先会掉包再说…