今天做下特征点提取的实验,特征提取这块可谓是所有机器学习中的第一步了。
那接下来试试几种不同的特征提取方法。
1.SURF
SURF全称为“加速稳健特征”(Speeded Up Robust Feature),它的理念是, 不仅在任何尺度下拍摄的物体都能检测到一致的关键点,而且每个被检测的特征点都对应一个尺度因子。 理想情况下,对于两幅图像中不同尺度的的同一个物体点, 计算得到的两个尺度因子之间的比率应该等于图像尺度的比率。不过他的提取速度还是比较慢的,但是优点就是尺度不变。
上面的图是单单提取完特征点后的对比结果,可以看到还是有一些尺度不变性的,下面是优化过的,为了减去一些没有必要的杂点。 也可以说是降维了,降维完后面的对比速度会更快。
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// opencv_day7.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include "highgui/highgui.hpp" #include "opencv2/nonfree/nonfree.hpp" #include "opencv2/legacy/legacy.hpp" #include <iostream> using namespace cv; using namespace std; int main() { Mat image01 = imread("1.png", 1); Mat image02 = imread("2.png", 1); //灰度图转换 Mat image1, image2; cvtColor(image01, image1, CV_RGB2GRAY); cvtColor(image02, image2, CV_RGB2GRAY); //提取特征点 SurfFeatureDetector surfDetector(2000); // 海塞矩阵阈值,在这里调整精度,值越大点越少,越精准 vector<KeyPoint> keyPoint1, keyPoint2; surfDetector.detect(image1, keyPoint1); surfDetector.detect(image2, keyPoint2); //特征点描述,为下边的特征点匹配做准备 SurfDescriptorExtractor SurfDescriptor; Mat imageDesc1, imageDesc2; SurfDescriptor.compute(image1, keyPoint1, imageDesc1); SurfDescriptor.compute(image2, keyPoint2, imageDesc2); FlannBasedMatcher matcher; vector<vector<DMatch> > matchePoints;//由于KNN设置为两个近邻点,所以要用二维的来存储匹配点 vector<DMatch> GoodMatchePoints;//存放好的匹配结果 vector<Mat> train_desc(1, imageDesc1); matcher.add(train_desc); matcher.train(); matcher.knnMatch(imageDesc2, matchePoints, 2);//用Knn降低质量不好的匹配点,2为邻近点的个数 cout << "total match points: " << matchePoints.size() << endl; // Lowe's algorithm,获取优秀匹配点 for (int i = 0; i < matchePoints.size(); i++) { if (matchePoints[i][0].distance < 0.6 * matchePoints[i][1].distance) { GoodMatchePoints.push_back(matchePoints[i][0]); } } Mat first_match; drawMatches(image02, keyPoint2, image01, keyPoint1, GoodMatchePoints, first_match); imshow("first_match ", first_match); waitKey(); return 0; }
OpenCV提供了两种Matching方式:
• Brute-force matcher (cv::BFMatcher)
• Flann-based matcher (cv::FlannBasedMatcher)
Brute-force matcher就是用暴力方法找到点集一中每个descriptor在点集二中距离最近的descriptor;
Flann-based matcher 使用快速近似最近邻搜索算法寻找(用快速的第三方库近似最近邻搜索算法)
一般把点集一称为 train set (训练集)对应模板图像,点集二称为 query set(查询集)对应查找模板图的目标图像。
为了提高检测速度,你可以调用matching函数前,先训练一个matcher。训练过程可以首先使用cv::FlannBasedMatcher来优化,为descriptor建立索引树,这种操作将在匹配大量数据时发挥巨大作用(比如在上百幅图像的数据集中查找匹配图像)。而Brute-force matcher在这个过程并不进行操作,它只是将train descriptors保存在内存中
使用KNN-matching算法,令K=2。则每个match得到两个最接近的descriptor,然后计算最接近距离和次接近距离之间的比值,当比值大于既定值时,才作为最终match。
两点比例:ratio
ratio=0. 4:对于准确度要求高的匹配;
ratio=0. 6:对于匹配点数目要求比较多的匹配;
ratio=0. 5:一般情况下。
2.SIFT
Surf可以说是sift的提速版了。而SIFT(尺度不变特征转换, ScaleInvariant Feature Transform) 是另一种著名的尺度不变特征检测法。我们知道,SURF相对于SIFT而言,特征点检测的速度有着极大的提升,所以在一些实时视频流物体匹配上有着很强的应用。而SIFT因为其巨大的特征计算量而使得特征点提取的过程异常花费时间,所以在一些注重速度的场合难有应用场景。
但是SIFT的精度会更好的。
SIFT特征检测的代码只要在SURF的代码改一下就可以了。
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// opencv_day7.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include "highgui/highgui.hpp" #include "opencv2/nonfree/nonfree.hpp" #include "opencv2/legacy/legacy.hpp" #include <iostream> using namespace cv; using namespace std; int main() { Mat image01 = imread("1.png", 1); Mat image02 = imread("2.png", 1); //灰度图转换 Mat image1, image2; cvtColor(image01, image1, CV_RGB2GRAY); cvtColor(image02, image2, CV_RGB2GRAY); //提取特征点 SiftFeatureDetector siftDetector(800); // 海塞矩阵阈值,在这里调整精度,值越大点越少,越精准 vector<KeyPoint> keyPoint1, keyPoint2; siftDetector.detect(image1, keyPoint1); siftDetector.detect(image2, keyPoint2); //特征点描述,为下边的特征点匹配做准备 SiftDescriptorExtractor SiftDescriptor; Mat imageDesc1, imageDesc2; SiftDescriptor.compute(image1, keyPoint1, imageDesc1); SiftDescriptor.compute(image2, keyPoint2, imageDesc2); FlannBasedMatcher matcher; vector<vector<DMatch> > matchePoints; vector<DMatch> GoodMatchePoints; vector<Mat> train_desc(1, imageDesc1); matcher.add(train_desc); matcher.train(); matcher.knnMatch(imageDesc2, matchePoints, 2); cout << "total match points: " << matchePoints.size() << endl; // Lowe's algorithm,获取优秀匹配点 for (int i = 0; i < matchePoints.size(); i++) { if (matchePoints[i][0].distance < 0.6 * matchePoints[i][1].distance) { GoodMatchePoints.push_back(matchePoints[i][0]); } } Mat first_match; drawMatches(image02, keyPoint2, image01, keyPoint1, GoodMatchePoints, first_match); imshow("first_match ", first_match); imwrite("first_match.jpg", first_match); waitKey(); return 0; }
3.ORB
ORB是ORiented Brief的简称,是brief算法的改进版。ORB算法比SIFT算法快100倍,比SURF算法快10倍。在计算机视觉领域有种说法,ORB算法的综合性能在各种测评里较其他特征提取算法是最好的。
ORB算法是brief算法的改进,那么我们先说一下brief算法有什么去缺点。
BRIEF的优点在于其速度,其缺点是:
- 不具备旋转不变性
- 对噪声敏感
- 不具备尺度不变性。
在一些对于速度要求比较高的应用场景,用ORB会比较好
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// opencv_day7.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include "highgui/highgui.hpp" #include "opencv2/nonfree/nonfree.hpp" #include "opencv2/legacy/legacy.hpp" #include <iostream> using namespace cv; using namespace std; int main() { Mat image01 = imread("1.png", 1); Mat image02 = imread("2.png", 1); imshow("p2", image01); imshow("p1", image02); //灰度图转换 Mat image1, image2; cvtColor(image01, image1, CV_RGB2GRAY); cvtColor(image02, image2, CV_RGB2GRAY); //提取特征点 OrbFeatureDetector OrbDetector(1000); // 在这里调整精度,值越小点越少,越精准 vector<KeyPoint> keyPoint1, keyPoint2; OrbDetector.detect(image1, keyPoint1); OrbDetector.detect(image2, keyPoint2); //特征点描述,为下边的特征点匹配做准备 OrbDescriptorExtractor OrbDescriptor; Mat imageDesc1, imageDesc2; OrbDescriptor.compute(image1, keyPoint1, imageDesc1); OrbDescriptor.compute(image2, keyPoint2, imageDesc2); flann::Index flannIndex(imageDesc1, flann::LshIndexParams(12, 20, 2), cvflann::FLANN_DIST_HAMMING); vector<DMatch> GoodMatchePoints; Mat macthIndex(imageDesc2.rows, 2, CV_32SC1), matchDistance(imageDesc2.rows, 2, CV_32FC1); flannIndex.knnSearch(imageDesc2, macthIndex, matchDistance, 2, flann::SearchParams()); // Lowe's algorithm,获取优秀匹配点 for (int i = 0; i < matchDistance.rows; i++) { if (matchDistance.at<float>(i, 0) < 0.6 * matchDistance.at<float>(i, 1)) { DMatch dmatches(i, macthIndex.at<int>(i, 0), matchDistance.at<float>(i, 0)); GoodMatchePoints.push_back(dmatches); } } Mat first_match; drawMatches(image02, keyPoint2, image01, keyPoint1, GoodMatchePoints, first_match); imshow("first_match ", first_match); imwrite("first_match.jpg", first_match); waitKey(); return 0; }
可不知道为什么,总感觉怪怪的使用起来。
FLANN介绍
FLANN库全称是Fast Library for Approximate Nearest Neighbors,它是目前最完整的(近似)最近邻开源库。不但实现了一系列查找算法,还包含了一种自动选取最快算法的机制。
flann::Index_类
该类模板是最近邻索引类,该类用于抽象不同类型的最近邻搜索的索引。
构造函数flann::Index_<T>::Index_
1
2
3
4
5
6
7flann::Index_<T>::Index_(const Mat& features, const IndexParams& params) /* Parameters: features – Matrix of containing the features(points) to index. The size of the matrix is num_features x feature_dimensionality and the data type of the elements in the matrix must coincide with the type of the index. params – Structure containing the index parameters. The type of index that will be constructed depends on the type of this parameter. See the description. */
参数features,是包含用于构建索引的特征的矩阵;参数params,是包含索引参数的结构。
该构造函数所实例的快速搜索结构是根据参数params所指定的特定算法来构建的。params是由IndexParams的派生类的引用。
其中:
-
LinearIndexParams,该结构对应的索引进行线性的、暴力(brute-force)的搜索。
-
KDTreeIndexParams,该方法对应的索引结构由一组随机kd树构成(randomized kd-trees),它可以平行地进行搜索。
1
2
3
4
5
6struct KDTreeIndexParams : public IndexParams { KDTreeIndexParams( int trees = 4 ); }; //trees:The number of parallel kd-trees to use. Good values are in the range
- KMeansIndexParams,该方法对应的索引结构是一个层次k均值树(a hierarchical k-means tree)。
1
2
3
4
5
6
7
8
9struct KMeansIndexParams : public IndexParams { KMeansIndexParams( int branching = 32, int iterations = 11, flann_centers_init_t centers_init = CENTERS_RANDOM, float cb_index = 0.2 ); };
- CompositeIndexParams,该结构结合随机kd树和层次k均值树来构建索引。
1
2
3
4
5
6
7
8
9
10struct CompositeIndexParams : public IndexParams { CompositeIndexParams( int trees = 4, int branching = 32, int iterations = 11, flann_centers_init_t centers_init = CENTERS_RANDOM, float cb_index = 0.2 ); };
- LshIndexParams,该结构使用multi-probe LSH方法创建索引(Multi-Probe LSH: Efficient Indexing for High-Dimensional Similarity Search by Qin Lv, William Josephson, Zhe Wang, Moses Charikar, Kai Li., Proceedings of the 33rd International Conference on Very Large Data Bases (VLDB). Vienna, Austria. September 2007)。
1
2
3
4
5
6
7
8struct LshIndexParams : public IndexParams { LshIndexParams( unsigned int table_number, unsigned int key_size, unsigned int multi_probe_level ); };
- AutotunedIndexParams,该结构是根据数据自动选取最优的索引类型来提供最好的性能。
1
2
3
4
5
6
7
8
9struct AutotunedIndexParams : public IndexParams { AutotunedIndexParams( float target_precision = 0.9, float build_weight = 0.01, float memory_weight = 0, float sample_fraction = 0.1 ); };
- SavedIndexParams,该结构用于加载存放在硬盘的索引结构。
1
2
3
4
5struct SavedIndexParams : public IndexParams { SavedIndexParams( std::string filename ); }; //filename:The filename in which the index was saved.
最后
以上就是火星上冬天最近收集整理的关于Opencv暑期历程--Day7 (特征提取)的全部内容,更多相关Opencv暑期历程--Day7内容请搜索靠谱客的其他文章。
发表评论 取消回复