关于算法的优化
区别
基于特征的匹配分为特征点提取和匹配两个步骤,本篇主要针对特征点提取三种方法进行比较,分别是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不一致的错误,不知道为什么。
1 2 3 4 5 6 7
| List<DMatch> matches_list = matches.toList(); 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筛选。
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
|
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)); } 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(); Fundamental = Calib3d.findFundamentalMat(mp1,mp2,RANSAC,3,0.99,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秒的缓慢无疑是灾难性的…..但是后者的准确性和泛用性也是一个问题。这还是一个有待解决的问题。