Boooil's BLOG.

图像特征匹配开发手记Vol_2

2021/01/24 Share

关于算法的优化


  • 区别

    基于特征的匹配分为特征点提取和匹配两个步骤,本篇主要针对特征点提取三种方法进行比较,分别是SIFT,SURF以及ORB三种方法,这三种方法在OpenCV里面都已实现。SURF基本就是SIFT的全面升级版,有 SURF基本就不用考虑SIFT,而ORB的强点在于计算时间,以下具体比较:

    计算速度: ORB>>SURF>>SIFT(各差一个量级)

    旋转鲁棒性: SURF>ORB~SIFT(表示差不多)

    模糊鲁棒性: SURF>ORB~SIFT

    尺度变换鲁棒性: SURF>SIFT>ORB(ORB并不具备尺度变换性)

    所以结论就是,如果对计算实时性要求非常高,可选用ORB算法,但基本要保证正对拍摄;如果对实行性要求稍高,可以选择SURF;基本不用SIFT。

经过测试,实际上SIFT和SURF在计算时给人的直观时间差并不大。而ORB算法的速度明显要高于前两者,并且能够明显的察觉到。

SIFT和SURF算法可以使用BRUTEFORCE和FLANNBASED匹配器;而ORB只能使用BRUTEFORCE,使用FLANNBASED会报margin state不一致的错误,不知道为什么。


  • 基于匹配DMatch排序的优化算法

    DMatch类中有成员变量distance,即欧氏距离,这个距离越小越好(less is beter),将得到的欧氏距离进行从小到大排序,最小的数值便是比较的两张图片的相似程度。

1
2
3
4
5
6
7
List<DMatch> matches_list = matches.toList();//将MatOfDMatch转为List,方便操作
Collections.sort(matches_list, new Comparator<DMatch>() {
@Override
public int compare(DMatch o1, DMatch o2) {
return (int) (o1.distance-o2.distance);
}
});

​ 比较的时候用到了Collection中的sort方法重写。

​ 可以直接将此处的最小distance作为评价依据,但是这个最小匹配点不一定可靠。所以我们在此基础上要进行RANSAC筛选。


  • RANSAC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
double max_dist = 0; double min_dist = 100;
for( int i = 0; i < descriptors1.rows(); i++ ){
double dist = matches_list.get(i).distance;
if( dist < min_dist ) min_dist = dist;
if( dist > max_dist ) max_dist = dist;
}
System.out.println(min_dist);
System.out.println(max_dist);
List<DMatch> good_matches_list = new ArrayList<DMatch>();
for( int i = 0; i < descriptors1.rows(); i++ ){
if( matches_list.get(i).distance <= 2*min_dist){
good_matches_list.add( matches_list.get(i));
}
}

​ 找出matches里distance的最大值和最小值,将范围定位在(min,0.2*min)内,将这些匹配点筛选出来,作为good_matches(预筛选)。

​ 经过预筛选后,进行RANSAC算法提纯。

​ RANSAC算法具体步骤参考博客https://blog.csdn.net/liuhaitaowq/article/details/52503806

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//RANSAC优化  
//根据matches将特征点对齐,将坐标转换为float类型
List<KeyPoint> keypoint_1 = new ArrayList<KeyPoint>();
List<KeyPoint> keypoint_2 = new ArrayList<KeyPoint>();
keypoint_1 = kp1.toList();
keypoint_2 = kp2.toList();
List<KeyPoint> R_keypoint_1 = new ArrayList<KeyPoint>();
List<KeyPoint> R_keypoint_2 = new ArrayList<KeyPoint>();
for (int i=0;i<good_matches_list.size();i++) {
R_keypoint_1.add(keypoint_1.get(good_matches_list.get(i).queryIdx));
R_keypoint_2.add(keypoint_2.get(good_matches_list.get(i).trainIdx));
//这两句话的理解:R_keypoint1是要存储img01中能与img02匹配的特征点,
//matches中存储了这些匹配点对的img01和img02的索引值
}
List<Point> p1 = new ArrayList<Point>();
List<Point> p2 = new ArrayList<Point>();
for (int i=0;i<good_matches_list.size();i++){
p1.add(R_keypoint_1.get(i).pt);
p2.add(R_keypoint_2.get(i).pt);
}
MatOfPoint2f mp1 = new MatOfPoint2f();
mp1.fromList(p1);
MatOfPoint2f mp2 = new MatOfPoint2f();
mp2.fromList(p2);
Mat Fundamental = new Mat();
Mat m_RANSACStatus = new Mat();//用于存储RANSAC后每个点的状态
Fundamental = Calib3d.findFundamentalMat(mp1,mp2,RANSAC,3,0.99,m_RANSACStatus);
//Fundamental = Calib3d.findHomography(mp1,mp2,RANSAC,10,m_RANSACStatus);
List<KeyPoint> RR_kp1_list = new ArrayList<KeyPoint>();
List<KeyPoint> RR_kp2_list = new ArrayList<KeyPoint>();
List<DMatch> RR_match_list = new ArrayList<DMatch>();
int index = 0;
for(int i=0;i<good_matches_list.size();i++){
double[] d = m_RANSACStatus.get(i,0);
if(d[0]!=0){
RR_kp1_list.add(keypoint_1.get(i));
RR_kp2_list.add(keypoint_2.get(i));
good_matches_list.get(i).queryIdx=index;
good_matches_list.get(i).trainIdx=index;
RR_match_list.add(good_matches_list.get(i));
index++;
}
}
Collections.sort(RR_match_list, new Comparator<DMatch>() {
@Override
public int compare(DMatch o1, DMatch o2) {
return (int) (o1.distance-o2.distance);
}
});
MatOfKeyPoint RR_kp1 = new MatOfKeyPoint();
RR_kp1.fromList(RR_kp1_list);
MatOfKeyPoint RR_kp2 = new MatOfKeyPoint();
RR_kp2.fromList(RR_kp2_list);
MatOfDMatch RR_match = new MatOfDMatch();
RR_match.fromList(RR_match_list);

​ RR_Match就是经过RANSAC算法后的匹配DMatch结果,将此DMatch的distance作为评价的指标。


SURF+FLANNBASED和ORB+BRUTEFORCE的组合,前者准确,后者快。

前者需要14秒左右,后者仅需要5秒左右。对于一个软件来说,匹配一次14秒的缓慢无疑是灾难性的…..但是后者的准确性和泛用性也是一个问题。这还是一个有待解决的问题。