使用SURF算法检测两幅图关键点后暴力匹配
SURF特征检测
使用SURF(Speeded Up Robust Features)算法来检测两张图像之间的关键点,并使用FLANN(Fast Library for Approximate Nearest Neighbors)基于特征描述符向量进行匹配
图像特征点检测(SURF)、(FLANN)匹配和目标定位
1.feature_description—SURF_matching_Demo.cpp(Debug模式)使用SURF算法检测两幅图关键点后暴力匹配
box.png
box_in_scene.png
minHessian=400
minHessian=1000
minHessian=10000
#include <iostream> // 包含标准输入输出流库
#include "opencv2/core.hpp" // 包括OpenCV的核心功能头文件
#ifdef HAVE_OPENCV_XFEATURES2D // 如果定义了HAVE_OPENCV_XFEATURES2D
#include "opencv2/highgui.hpp" // 包括用户界面相关功能的头文件
#include "opencv2/features2d.hpp" // 包括特征检测相关功能的头文件
#include "opencv2/xfeatures2d.hpp" // 包括特殊特征检测的头文件(非free模块)
using namespace cv; // 使用cv命名空间
using namespace cv::xfeatures2d; // 使用cv的xfeatures2d命名空间
using std::cout; // 使用标准库中的cout
using std::endl; // 使用标准库中的endl
const char* keys = // 定义命令行参数
"{ help h | | Print help message. }"
"{ input1 | box.png | Path to input image 1. }"
"{ input2 | box_in_scene.png | Path to input image 2. }";
int main( int argc, char* argv[] ) // 主函数
{
CommandLineParser parser( argc, argv, keys ); // 创建命令行解析器
Mat img1 = imread( samples::findFile( parser.get<String>("input1") ), IMREAD_GRAYSCALE ); // 读取第一张图片为灰度图
Mat img2 = imread( samples::findFile( parser.get<String>("input2") ), IMREAD_GRAYSCALE ); // 读取第二张图片为灰度图
if ( img1.empty() || img2.empty() ) // 如果图片读取失败
{
cout << "Could not open or find the image!\n" << endl; // 打印错误信息
parser.printMessage(); // 打印帮助信息
return -1; // 返回错误代码
}
//-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
int minHessian = 400; // 设置SURF算法的Hessian阈值
Ptr<SURF> detector = SURF::create( minHessian ); // 创建SURF特征检测器
std::vector<KeyPoint> keypoints1, keypoints2; // 存放两张图片的关键点
Mat descriptors1, descriptors2; // 存放两张图片的描述符
detector->detectAndCompute( img1, noArray(), keypoints1, descriptors1 ); // 检测并计算img1的关键点和描述符
detector->detectAndCompute( img2, noArray(), keypoints2, descriptors2 ); // 检测并计算img2的关键点和描述符
//-- Step 2: Matching descriptor vectors with a brute force matcher
// Since SURF is a floating-point descriptor NORM_L2 is used
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::BRUTEFORCE); // 创建暴力匹配器
std::vector< DMatch > matches; // 存放匹配结果
matcher->match( descriptors1, descriptors2, matches ); // 执行匹配
//-- Draw matches
Mat img_matches; // 存放匹配之后的图片
drawMatches( img1, keypoints1, img2, keypoints2, matches, img_matches ); // 绘制匹配结果
//-- Show detected matches
imshow("Matches", img_matches ); // 在窗口中显示匹配结果
waitKey(); // 等待用户按键
return 0; // 程序成功结束
}
#else
int main() // 如果没定义HAVE_OPENCV_XFEATURES2D
{
std::cout << "This tutorial code needs the xfeatures2d contrib module to be run." << std::endl; // 提示需要xfeatures2d模块
return 0; // 程序结束
}
#endif
这段代码是使用OpenCV库进行图像特征点检测和匹配的示例。它通过SURF算法来检测两幅图片中的特征点,并使用暴力匹配器来找出这些特征点之间的匹配关系。最终将匹配的结果用图形化的方式展示出来。这对于很多计算机视觉任务,比如物体识别、图像拼接等是非常实用的。如果环境中没有安装OpenCV的xfeatures2d模块,则给出提示信息。
2.feature_detection—SURF_detection_Demo.cpp SURF特征检测
#include <iostream> // 包含输入输出流的头文件
#include "opencv2/core.hpp" // 包含OpenCV核心功能的头文件
#ifdef HAVE_OPENCV_XFEATURES2D
#include "opencv2/highgui.hpp" // 包含OpenCV GUI功能的头文件
#include "opencv2/features2d.hpp" // 包含OpenCV特征检测相关功能的头文件
#include "opencv2/xfeatures2d.hpp" // 包含OpenCV extra features2d模块的头文件,例如SURF
using namespace cv; // 使用cv命名空间
using namespace cv::xfeatures2d; // 使用cv::xfeatures2d命名空间,因为SURF是其中的一部分
using std::cout; // 使用标准命名空间下的cout
using std::endl; // 使用标准命名空间下的endl
int main( int argc, char* argv[] )
{
CommandLineParser parser( argc, argv, "{@input | box.png | input image}" ); // 命令行参数解析器
Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ), IMREAD_GRAYSCALE ); // 读取图像文件转换为灰度图
if ( src.empty() )
{
cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1;
}
//-- Step 1: Detect the keypoints using SURF Detector
// 步骤1:使用SURF检测器检测关键点
int minHessian = 400; // Hessian算子的阈值
Ptr<SURF> detector = SURF::create( minHessian ); // 创建SURF检测器
std::vector<KeyPoint> keypoints; // 关键点的向量
detector->detect( src, keypoints ); // 检测关键点
//-- Draw keypoints
// 绘制关键点
Mat img_keypoints;
drawKeypoints( src, keypoints, img_keypoints ); // 将检测到的关键点绘制到图上
//-- Show detected (drawn) keypoints
// 显示检测到(绘制的)关键点
imshow("SURF Keypoints", img_keypoints ); // 创建一个窗口展示关键点
waitKey(); // 等待任意键输入
return 0;
}
#else
int main()
{
std::cout << "This tutorial code needs the xfeatures2d contrib module to be run." << std::endl;
return 0;
}
#endif
这段代码的功能是使用SURF算法来检测图像中的关键点。首先,它使用命令行参数解析器读取图像,并将其转换为灰度图。如果无法读取图像,它会打印错误消息并退出程序。如果图像读取成功,它创建一个SURF检测器,并根据指定的Hessian阈值来检测图像中的关键点。然后,它将这些关键点绘制在源图像上,并使用imshow
函数显示结果。如果没有安装OpenCV的xfeatures2d类的附加模块,它会在命令行输出一条信息,说明需要xfeatures2d模块才能运行此代码。
3. SURF_FLANN_matching_Demo.cpp 使用SURF(Speeded Up Robust Features)算法来检测两张图像之间的关键点,并使用FLANN(Fast Library for Approximate Nearest Neighbors)基于特征描述符向量进行匹配
#include <iostream> // 包含标准输入输出流库
#include "opencv2/core.hpp" // 包含OpenCV核心功能库
#ifdef HAVE_OPENCV_XFEATURES2D // 如果定义了HAVE_OPENCV_XFEATURES2D(检查xfeatures2d模块是否可用)
#include "opencv2/highgui.hpp" // 包含OpenCV高级GUI库
#include "opencv2/features2d.hpp" // 包含OpenCV特征点检测库
#include "opencv2/xfeatures2d.hpp" // 包含OpenCV附加特征点检测库
using namespace cv; // 使用cv命名空间
using namespace cv::xfeatures2d; // 使用cv::xfeatures2d命名空间
using std::cout; // 使用cout(标准输出)
using std::endl; // 使用endl(换行符)
const char* keys = // 定义命令行参数
"{ help h | | Print help message. }" // 帮助信息
"{ input1 | box.png | Path to input image 1. }" // 输入图像1的路径
"{ input2 | box_in_scene.png | Path to input image 2. }"; // 输入图像2的路径
int main( int argc, char* argv[] ) // 主函数
{
CommandLineParser parser( argc, argv, keys ); // 命令行解析器
Mat img1 = imread( samples::findFile( parser.get<String>("input1") ), IMREAD_GRAYSCALE ); // 读取输入图像1为灰度图
Mat img2 = imread( samples::findFile( parser.get<String>("input2") ), IMREAD_GRAYSCALE ); // 读取输入图像2为灰度图
if ( img1.empty() || img2.empty() ) // 如果任一图像为空则打印错误信息
{
cout << "Could not open or find the image!\n" << endl;
parser.printMessage(); // 打印帮助信息
return -1; // 返回-1表示错误
}
//-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
int minHessian = 400; // 定义Hessian阈值
Ptr<SURF> detector = SURF::create( minHessian ); // 创建SURF检测器
std::vector<KeyPoint> keypoints1, keypoints2; // 定义关键点向量
Mat descriptors1, descriptors2; // 定义描述符矩阵
detector->detectAndCompute( img1, noArray(), keypoints1, descriptors1 ); // 检测图像1的关键点和描述符
detector->detectAndCompute( img2, noArray(), keypoints2, descriptors2 ); // 检测图像2的关键点和描述符
//-- Step 2: Matching descriptor vectors with a FLANN based matcher
// Since SURF is a floating-point descriptor NORM_L2 is used
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::FLANNBASED); // 创建基于FLANN的描述符匹配器
std::vector< std::vector<DMatch> > knn_matches; // 定义K邻近匹配向量
matcher->knnMatch( descriptors1, descriptors2, knn_matches, 2 ); // 执行K邻近匹配
//-- Filter matches using the Lowe's ratio test
const float ratio_thresh = 0.7f; // 定义Lowe's比率测试阈值
std::vector<DMatch> good_matches; // 定义良好匹配向量
for (size_t i = 0; i < knn_matches.size(); i++) // 遍历所有K邻近匹配
{
if (knn_matches[i][0].distance < ratio_thresh * knn_matches[i][1].distance) // 如果满足Lowe's比率测试则认为是良好匹配
{
good_matches.push_back(knn_matches[i][0]); // 添加到良好匹配向量中
}
}
//-- Draw matches
Mat img_matches; // 定义匹配结果图像
drawMatches( img1, keypoints1, img2, keypoints2, good_matches, img_matches, Scalar::all(-1),
Scalar::all(-1), std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS ); // 绘制良好匹配
//-- Show detected matches
imshow("Good Matches", img_matches ); // 显示匹配结果图像
waitKey(); // 等待按键事件
return 0; // 返回0表示成功
}
#else // 如果没有定义HAVE_OPENCV_XFEATURES2D
int main() // 主函数
{
std::cout << "This tutorial code needs the xfeatures2d contrib module to be run." << std::endl; // 打印错误信息
return 0; // 返回0表示成功
}
#endif
这段代码是一个使用OpenCV库进行图像处理的例子,特别是使用SURF(Speeded Up Robust Features)算法来检测两张图像之间的关键点,并使用FLANN(Fast Library for Approximate Nearest Neighbors)基于特征描述符向量进行匹配。首先,代码读取两张图像并将它们转换成灰度图。然后,SURF算法被用于检测关键点并计算描述符。接着,运用FLANN匹配器对这两组描述符进行匹配,并使用Lowe's比率测试过滤出良好的匹配点。最后,良好的匹配点被绘制并显示出来。如果没有安装OpenCV的xfeatures2d模块,代码将打印一条错误信息。
drawMatches( img1, keypoints1, img2, keypoints2, good_matches, img_matches, Scalar::all(-1),
Scalar::all(-1), std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
4.SURF_FLANN_matching_homography_Demo.cpp 图像特征点检测、匹配和目标定
// 引用必要的库
#include <iostream>
#include "opencv2/core.hpp"
#ifdef HAVE_OPENCV_XFEATURES2D // 判断是否有xfeatures2d模块,如果有则进行下面的操作
#include "opencv2/calib3d.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/features2d.hpp"
#include "opencv2/xfeatures2d.hpp"
// 使用命名空间简化代码
using namespace cv;
using namespace cv::xfeatures2d;
using std::cout;
using std::endl;
// 定义程序参数
const char* keys =
"{ help h | | 打印帮助信息}"
"{ input1 | box.png | 第一张输入图像路径}"
"{ input2 | box_in_scene.png | 第二张输入图像路径}";
// 程序主函数
int main( int argc, char* argv[] )
{
// 定义命令行解析器
CommandLineParser parser( argc, argv, keys );
// 读取图片
Mat img_object = imread( samples::findFile( parser.get<String>("input1") ), IMREAD_GRAYSCALE );
Mat img_scene = imread( samples::findFile( parser.get<String>("input2") ), IMREAD_GRAYSCALE );
// 判断图片是否读取成功
if ( img_object.empty() || img_scene.empty() )
{
cout << "无法打开或找到图片!\n" << endl;
parser.printMessage(); //打印错误信息
return -1;
}
//-- Step 1: 使用SURF检测器检测关键点并计算描述符
int minHessian = 400; //设置SURF算法中的hessian阈值
Ptr<SURF> detector = SURF::create( minHessian ); // 创建SURF检测器
std::vector<KeyPoint> keypoints_object, keypoints_scene; // 定义储存关键点的向量
Mat descriptors_object, descriptors_scene; //定义储存描述符的矩阵
detector->detectAndCompute( img_object, noArray(), keypoints_object, descriptors_object ); // 在目标图片中检测关键点并计算描述符
detector->detectAndCompute( img_scene, noArray(), keypoints_scene, descriptors_scene ); //在场景图片中检测关键点并计算描述符
//-- Step 2: 通过FLANN匹配器对描述符向量进行匹配
// 由于SURF是一个浮点数描述符,此处使用NORM_L2
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::FLANNBASED);
std::vector< std::vector<DMatch> > knn_matches; //定义knn匹配的结果向量
matcher->knnMatch( descriptors_object, descriptors_scene, knn_matches, 2 ); //knn匹配
//-- Step 3: 利用Lowe's比率测试过滤匹配点
const float ratio_thresh = 0.75f;
std::vector<DMatch> good_matches; //定义储存优质匹配点的向量
for (size_t i = 0; i < knn_matches.size(); i++)
{
if (knn_matches[i][0].distance < ratio_thresh * knn_matches[i][1].distance) //通过比率测试进行筛选
{
good_matches.push_back(knn_matches[i][0]);
}
}
//-- Step 4: 绘制优质匹配点
Mat img_matches;
drawMatches( img_object, keypoints_object, img_scene, keypoints_scene, good_matches, img_matches, Scalar::all(-1),
Scalar::all(-1), std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
//-- Step 5: 找到场景图片中的目标位置
std::vector<Point2f> obj;
std::vector<Point2f> scene;
for( size_t i = 0; i < good_matches.size(); i++ )
{
//-- 从优质匹配点中获取关键点
obj.push_back( keypoints_object[ good_matches[i].queryIdx ].pt );
scene.push_back( keypoints_scene[ good_matches[i].trainIdx ].pt );
}
Mat H = findHomography( obj, scene, RANSAC ); //计算单应性矩阵
//-- Step 6: 获取目标图片的角点(the object to be "detected")
std::vector<Point2f> obj_corners(4);
obj_corners[0] = Point2f(0, 0);
obj_corners[1] = Point2f( (float)img_object.cols, 0 );
obj_corners[2] = Point2f( (float)img_object.cols, (float)img_object.rows );
obj_corners[3] = Point2f( 0, (float)img_object.rows );
std::vector<Point2f> scene_corners(4);
perspectiveTransform( obj_corners, scene_corners, H); //对目标点进行透视投影变换
//-- Draw lines between the corners (the mapped object in the scene - image_2 )
line( img_matches, scene_corners[0] + Point2f((float)img_object.cols, 0),
scene_corners[1] + Point2f((float)img_object.cols, 0), Scalar(0, 255, 0), 4 );
line( img_matches, scene_corners[1] + Point2f((float)img_object.cols, 0),
scene_corners[2] + Point2f((float)img_object.cols, 0), Scalar( 0, 255, 0), 4 );
line( img_matches, scene_corners[2] + Point2f((float)img_object.cols, 0),
scene_corners[3] + Point2f((float)img_object.cols, 0), Scalar( 0, 255, 0), 4 );
line( img_matches, scene_corners[3] + Point2f((float)img_object.cols, 0),
scene_corners[0] + Point2f((float)img_object.cols, 0), Scalar( 0, 255, 0), 4 );
//-- Step 7: 展示检测到的匹配
imshow("Good Matches & Object detection", img_matches );
waitKey(); //等待用户按键
return 0;
}
#else
int main()
{
std::cout << "这个教程代码需要xfeatures2d contrib模块才能运行." << std::endl;
return 0;
}
#endif
以上代码实现了一个物体识别程序,它能从一张场景图像中找到另一张目标图像的位置。首先,通过SURF检测器找到两张图片的关键点和描述符。接着,通过FLANN匹配器找到匹配的点,并通过Lowe's比率测试进行筛选,得到优质的匹配点。最后,根据这些匹配点找到目标图片在场景图片中的位置,并在匹配图上绘制出目标的角点。