环境:
我在XP(32bit)电脑上搭建了Visual Studio 2010和OpenCV-3.1.0,OpenCV包含了OpenCV_contrib这个包。
OpenCV-3.1.0自带了6种能同时计算特征点和描述子的算法(笔者浏览了一遍,目测有6个函数)。分别是cv::xfeatures2d::SIFT、cv::xfeatures2d::SURF、cv::AKAZE、cv::BRISK、cv::KAZE、cv::ORB。
使用cv::xfeatures2d::SIFT、cv::xfeatures2d::SURF盈利的话,传闻是有专利问题的。
代码和图片来源:
在OpenCV-3.1.0的说明文档找到SURF例程,此处是链接。稍作修改,就可以编写一段对比多种算法的程序。而图片直接使用TUM的rgbd-dataset。此处是链接。
经过修改后的代码:
以下直接上代码。代码介绍:使用dataset内,最简单的一段“xyz”。读取头两帧RGB图像。分别用上述六种方法计算特征点和描述子。对比不同方法的速度。
#include
#include
#include "opencv2/core.hpp"
#include "opencv2/features2d.hpp"
#include "opencv2/xfeatures2d.hpp"
#include "opencv2/highgui.hpp"
#include
using namespace cv;
using namespace cv::xfeatures2d;
void readme();
/* @function main */
int main( int argc, char** argv )
{
std::cout << std::endl << "< Reading images..." << std::endl;
Mat img_1 = imread( "D:\\rgbd_dataset_freiburg1_xyz\\rgb\\1305031102.175304.png", IMREAD_GRAYSCALE );
Mat img_2 = imread( "D:\\rgbd_dataset_freiburg1_xyz\\rgb\\1305031102.211214.png", IMREAD_GRAYSCALE );
if( argc == 3 )
{
Mat img_1 = imread( argv[1], IMREAD_GRAYSCALE );
Mat img_2 = imread( argv[2], IMREAD_GRAYSCALE );
//readme(); return -1;
}
else
{
//readme();
}
if( !img_1.data || !img_2.data )
{ std::cout<< " --(!) Error reading images " << std::endl; return -1; }
//-- Step 1: Detect the keypoints using SURF Detector
int minHessian = 400;
//Ptr detector = SURF::create( minHessian );
std::vector keypoints_1, keypoints_2;
std::vector keypoints_11, keypoints_22;
std::vector keypoints_111, keypoints_222;
std::vector keypoints_1111, keypoints_2222;
std::vector keypoints_11111, keypoints_22222;
std::vector keypoints_111111, keypoints_222222;
clock_t time_stt = clock();
std::cout << std::endl << "< Extracting keypoints from images using SIFT..." << std::endl;
Ptr detector = SIFT::create( );
detector->detect( img_1, keypoints_1 );
detector->detect( img_2, keypoints_2 );
std::cout <<"img1:"<< keypoints_1.size() << " points img2:" <" << std::endl;
time_stt = clock();
std::cout << std::endl << "< Extracting keypoints from images using SURF..." << std::endl;
Ptr detectorSURF = SURF::create( );
detectorSURF->detect( img_1, keypoints_11 );
detectorSURF->detect( img_2, keypoints_22 );
std::cout <<"img11:"<< keypoints_11.size() << " points img22:" <" << std::endl;
std::cout << "time use in SURF is " << 1000 * (clock() - time_stt)/(double)CLOCKS_PER_SEC << "ms" << std::endl;
std::cout << "time of per keypoints is " << 1000 * (clock() - time_stt)/(double)CLOCKS_PER_SEC / (keypoints_11.size() + keypoints_22.size()) << "ms" << std::endl;
std::cout << ">" << std::endl;
time_stt = clock();
std::cout << std::endl << "< Extracting keypoints from images using ORB..." << std::endl;
Ptr detectorORB = ORB::create( );
detectorORB->detect( img_1, keypoints_111 );
detectorORB->detect( img_2, keypoints_222 );
std::cout <<"img111:"<< keypoints_111.size() << " points img222:" <" << std::endl;
time_stt = clock();
std::cout << std::endl << "< Extracting keypoints from images using AKAZE..." << std::endl;
Ptr detectorAKAZE = AKAZE::create( );
detectorAKAZE->detect( img_1, keypoints_1111 );
detectorAKAZE->detect( img_2, keypoints_2222 );
std::cout <<"img1111:"<< keypoints_1111.size() << " points img2222:" <" << std::endl;
time_stt = clock();
std::cout << std::endl << "< Extracting keypoints from images using BRISK..." << std::endl;
Ptr detectorBRISK = BRISK::create( );
detectorBRISK->detect( img_1, keypoints_11111 );
detectorBRISK->detect( img_2, keypoints_22222 );
std::cout <<"img11111:"<< keypoints_11111.size() << " points img22222:" <" << std::endl;
time_stt = clock();
std::cout << std::endl << "< Extracting keypoints from images using KAZE..." << std::endl;
Ptr detectorKAZE = KAZE::create( );
detectorKAZE->detect( img_1, keypoints_111111 );
detectorKAZE->detect( img_2, keypoints_222222 );
std::cout <<"img111111:"<< keypoints_111111.size() << " points img222222:" <" << std::endl;
//-- Draw keypoints
Mat img_keypoints_1;
Mat img_keypoints_2;
Mat img_keypoints_11;
Mat img_keypoints_22;
Mat img_keypoints_111;
Mat img_keypoints_222;
Mat img_keypoints_1111;
Mat img_keypoints_2222;
Mat img_keypoints_11111;
Mat img_keypoints_22222;
Mat img_keypoints_111111;
Mat img_keypoints_222222;
drawKeypoints( img_1, keypoints_1, img_keypoints_1, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
drawKeypoints( img_2, keypoints_2, img_keypoints_2, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
drawKeypoints( img_1, keypoints_11, img_keypoints_11, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
drawKeypoints( img_2, keypoints_22, img_keypoints_22, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
drawKeypoints( img_1, keypoints_111, img_keypoints_111, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
drawKeypoints( img_2, keypoints_222, img_keypoints_222, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
drawKeypoints( img_1, keypoints_1111, img_keypoints_1111, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
drawKeypoints( img_2, keypoints_2222, img_keypoints_2222, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
drawKeypoints( img_1, keypoints_11111, img_keypoints_11111, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
drawKeypoints( img_2, keypoints_22222, img_keypoints_22222, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
drawKeypoints( img_1, keypoints_111111, img_keypoints_111111, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
drawKeypoints( img_2, keypoints_222222, img_keypoints_222222, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
//-- Show detected (drawn) keypoints
imshow("Keypoints 1", img_keypoints_1 );
imshow("Keypoints 2", img_keypoints_2 );
/*
imshow("Keypoints 11", img_keypoints_11 );
imshow("Keypoints 22", img_keypoints_22 );
imshow("Keypoints 111", img_keypoints_111 );
imshow("Keypoints 222", img_keypoints_222 );
imshow("Keypoints 1111", img_keypoints_1111 );
imshow("Keypoints 2222", img_keypoints_2222 );
imshow("Keypoints 11111", img_keypoints_11111 );
imshow("Keypoints 22222", img_keypoints_22222 );
imshow("Keypoints 111111", img_keypoints_111111 );
imshow("Keypoints 222222", img_keypoints_222222 );
*/
waitKey(0);
return 0;
}
/* @function readme */
void readme()
{ std::cout << " Usage: ./SURF_detector " << std::endl; }
程序运行结果见下表。
函数 | 计算得到图片1的特征点数量(个) | 计算得到图片1的特征点数量(个) | 耗时(ms) | 平均每个特征点耗时(ms) |
SIFT | 2006 | 1596 | 2125 | 0.6030 |
SURF | 1908 | 1686 | 735 | 0.2045 |
ORB | 500 | 500 | 109 | 0.1100 |
AKAZE | 1454 | 1280 | 1750 | 0.6456 |
BRISK | 2516 | 1928 | 1078 | 0.2568 |
KAZE | 1742 | 1556 | 5937 | 1.8193 |
由于是同时计算两张图片,对比之前翻过的其他前辈做过的实验,耗时比较长。
本机XP,CPU是 Intel Core 2 DUo CPU E7300 @2.66GHz。2G内存。
本文没有干货……干货请看参考资料。
参考1:Feature Description,https://docs.opencv.org/3.1.0/d5/dde/tutorial_feature_description.html
参考2:RGB-D SLAM Dataset and Benchmark,https://vision.in.tum.de/data/datasets/rgbd-dataset
参考3:OpenCV特征点提取算法对比,http://www.p-chao.com/2017-06-14/opencv%e7%89%b9%e5%be%81%e7%82%b9%e6%8f%90%e5%8f%96%e7%ae%97%e6%b3%95%e5%af%b9%e6%af%94/
参考4:学习OpenCV——BOW特征提取函数(特征点篇),http://www.cnblogs.com/GarfieldEr007/p/5401859.html
参考5:Oriented FAST and Rotated BRIEF,http://www.cnblogs.com/ronny/p/4083537.html