BRISK:Binary Robust Invariant Scalable Keypoints。它是一种二进制的特征描述算子。它具有较好的旋转不变性、尺度不变性,较好的鲁棒性等。在对有较大模糊的图像配准时,BRISK算法在其中表现最为出色。
算法原理参考下面这篇文章,其中的表达描述的很清楚。
参考文章:https://blog.csdn.net/hujingshuang/article/details/47045497
特征检测与步骤:
1、构建尺度空间-------->高斯金字塔构建;
2、特征点检测;
3、FAST9-16寻找特征点----------->连续9个点大于或小于当前值都被视为特征点;
4、特征点定位;
5、关键点描述子。
大体上来说,只要是涉及特征点寻找的,都要保持旋转不变性,尺度不变性,光照强度不变性等。只需要解决以上问题,特征点的检测就较为准确。
代码部分:
#include
#include
#include
using namespace cv;
using namespace std;
int main(int argc, char**argv)
{
Mat img1 = imread("D:/test/box.png",IMREAD_GRAYSCALE);
Mat img2 = imread("D:/test/box_in_scene.png", IMREAD_GRAYSCALE);
if (!img1.data || !img2.data)
{
cout << "图片未找到!!!" << endl;
return -1;
}
imshow("img1_box", img1);
imshow("img2_scene", img2);
//用Brisk算法去检测特征点
vector keypoint_obj;
vector keypoint_scene;
double t1 = getTickCount();//计算运行时间
Ptr detect = BRISK::create();
Mat desciptor_obj, descriptor_scene;
//检测并计算描述子
detect->detectAndCompute(img1, Mat(), keypoint_obj, desciptor_obj);
detect->detectAndCompute(img2, Mat(), keypoint_scene, descriptor_scene);
double t2 = getTickCount();
double t = (t2 - t1) * 1000 / getTickFrequency();
//匹配描述子,这里使用FLANN匹配,也可以使用(BF)暴力匹配
vector matches;
FlannBasedMatcher fbmatcher(new flann::LshIndexParams(20, 10, 2));
//匹配描述子
fbmatcher.match(desciptor_obj, descriptor_scene, matches);
vector goodmatches;//找到最优匹配点
double minDist = 1000;
double maxDist = 0;//初始化
for (int i = 0; i < desciptor_obj.rows; i++)
{
double dist = matches[i].distance;
if (dist > maxDist)
{
maxDist = dist;
}
if (dist < minDist)
{
minDist = dist;
}
}
for (int i = 0; i < desciptor_obj.rows; i++)
{
double dist = matches[i].distance;
//比最小距离还小的就是最优匹配点
if (dist < max(2 * minDist, 0.02))
{
goodmatches.push_back(matches[i]);
}
}
Mat resultImg;
drawMatches(img1, keypoint_obj, img2, keypoint_scene, goodmatches, resultImg,
Scalar::all(-1), Scalar::all(-1), vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
imshow("BRISK Matches demo",resultImg);
printf("BRISK 执行时间为(ms):%f",t);
//使用透视矩阵画出匹配物体
vector obj;
vector scene_in_obj;
for (size_t i= 0; i < goodmatches.size(); i++)
{
obj.push_back(keypoint_obj[goodmatches[i].queryIdx].pt);
scene_in_obj.push_back(keypoint_scene[goodmatches[i].trainIdx].pt);
}
//生成透视矩阵
Mat H = findHomography(obj, scene_in_obj, RANSAC);
vectorobj_corner(4);
vectorscene_corner(4);
obj_corner[0] = Point(0, 0);
obj_corner[1] = Point(img1.cols, 0);
obj_corner[2] = Point(img1.cols,img1.rows);
obj_corner[3] = Point(0, img1.rows);
//透视变换
perspectiveTransform(obj_corner, scene_corner, H);
Mat pptfImg = resultImg.clone();
line(pptfImg, scene_corner[0] + Point2f(img1.cols, 0), scene_corner[1] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
line(pptfImg, scene_corner[1] + Point2f(img1.cols, 0), scene_corner[2] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
line(pptfImg, scene_corner[2] + Point2f(img1.cols, 0), scene_corner[3] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
line(pptfImg, scene_corner[3] + Point2f(img1.cols, 0), scene_corner[0] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
imshow("pptfImg demo",pptfImg);
waitKey(0);
return 0;
}
可以看到,BRISK算法的执行效率大概在3秒左右,上一篇文章所提到的KAZE大概在2秒左右,AKAZE则更少,虽然BRISK效率慢了点,但是在图像配准应用中,速度比较:SIFT