Opencv暑期历程--Day7 (特征提取)

今天做下特征点提取的实验,特征提取这块可谓是所有机器学习中的第一步了。

那接下来试试几种不同的特征提取方法。

1.SURF

SURF全称为“加速稳健特征”(Speeded Up Robust Feature),它的理念是, 不仅在任何尺度下拍摄的物体都能检测到一致的关键点,而且每个被检测的特征点都对应一个尺度因子。 理想情况下,对于两幅图像中不同尺度的的同一个物体点, 计算得到的两个尺度因子之间的比率应该等于图像尺度的比率。不过他的提取速度还是比较慢的,但是优点就是尺度不变。

上面的图是单单提取完特征点后的对比结果,可以看到还是有一些尺度不变性的,下面是优化过的,为了减去一些没有必要的杂点。 也可以说是降维了,降维完后面的对比速度会更快。

 

// 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的代码改一下就可以了。

// 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会比较好

// 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_

flann::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),它可以平行地进行搜索。

struct 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)。
struct 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均值树来构建索引。
struct 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)。
struct LshIndexParams : public IndexParams
{
    LshIndexParams(
        unsigned int table_number,
        unsigned int key_size,
        unsigned int multi_probe_level );
};
  • AutotunedIndexParams,该结构是根据数据自动选取最优的索引类型来提供最好的性能。
struct AutotunedIndexParams : public IndexParams
{
    AutotunedIndexParams(
        float target_precision = 0.9,
        float build_weight = 0.01,
        float memory_weight = 0,
        float sample_fraction = 0.1 );
};
  • SavedIndexParams,该结构用于加载存放在硬盘的索引结构。
struct SavedIndexParams : public IndexParams
{
    SavedIndexParams( std::string filename );
};
//filename:The filename in which the index was saved.



 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值