OpenCV3 使用GFTTDetector进行Shift-Tomasi角点检测、特征提取以及特征匹配


原创:转载请备注https://www.cnblogs.com/soulfly/articles/11283855.html
前言
如果使用Shift-Tomasi检测出的角点进行特征匹配?这个是本文的重点
作为一名OpenCV小白,在筛选特征提取方法时,发现Shift-Tomasi角点检测算法不错,通过调节参数能够实现交通牌边沿角点和白线绘制角点的提取,如下图示
 
第一步 初步探索:角点检测接口以及参数说明
在网上搜索了不少,大都是使用OpenCV的函数goodFeaturesToTrack实现,定义如下
void goodFeaturesToTrack( InputArray image, OutputArray corners,
int maxCorners, double qualityLevel, double minDistance,
InputArray mask = noArray(), int blockSize = 3,
bool useHarrisDetector = false, double k = 0.04 );
该函数使用的使用方法不是本文的讲解重点,就不再举例详细赘述,仅说明一下参数含义:
第一个参数image:8位或32位单通道灰度图像;
第二个参数corners:位置点向量,保存的是检测到的角点的坐标;
第三个参数maxCorners:定义可以检测到的角点的数量的最大值;
第四个参数qualityLevel:检测到的角点的质量等级,角点特征值小于qualityLevel*最大特征值的点将被舍弃;
第五个参数minDistance:两个角点间最小间距,以像素为单位;
第六个参数mask:指定检测区域,若检测整幅图像,mask置为空Mat();
第七个参数blockSize:计算协方差矩阵时窗口大小;
第八个参数useHarrisDetector:是否使用Harris角点检测,为false,则使用Shi-Tomasi算子;
第九个参数k:留给Harris角点检测算子用的中间参数,一般取经验值0.04~0.06。第八个参数为false时,该参数不起作用;
检测效果如下图所示:
可见牌子的边沿角点和绘制角点基本全部检测出来了,效果还不错,主要参数取值如下:
int maxCornerNumber = 300;
double qualityLevel = 0.01;
double minDistance = 10;
int blockSize = 10;
 
第二步 大海捞针:查找计算特征点(关键点:KeyPoint)的接口
这一步真是费了好多时间才找到相关接口,先是从网上查找相关资料,但是无一例外的全是讲解接口goodFeaturesToTrack和Shi-Tomasi算法原理,无意中发现大神“冠军的试炼”的博客:
OpenCV探索之路(二十三):特征检测和特征匹配方法汇总,
连接: https://www.cnblogs.com/skyfsm/p/7401523.html 中提到Harris角点特征匹配相关代码
但是这个是OpenCV2的实现方法,在OpenCV3中找不到。
发现这一个后,我确定了一个问题,即OpenCV3中肯定有相关的实现接口,于是采用暴力解决
,即在源码中全工程搜索“goodFeaturesToTrack”,终于找到的实现接口GFTTDetector:
该接口简介:使用goodFeaturesToTrack函数实现特征检测的封装类。
使用该接口就能直接计算出特征点,可用于计算特征描述符,进而用于匹配。
 
第三步 临门一脚:查找特征匹配的接口
本以为找到GFTTDetector类就大功告成,没想到,调用compute计算描述符时崩溃了。。。
这时回看大神“冠军的试炼”的博客,就轻松的找到了答案:换一个计算描述符的接口就行了,哈哈
 
源码如下:
int main(int argc, char** argv)
{
Mat leftImage1 = imread("D:/branch/openCV330/OpenCVTest/image/38-1-190504094217209-003481.jpg", cv::IMREAD_GRAYSCALE);
Mat rightImage2 = imread("D:/branch/openCV330/OpenCVTest/image/38-2-190504094217209-003481.jpg", cv::IMREAD_GRAYSCALE);
if (!leftImage1.data || !rightImage2.data)
{
return 0;
}
equalizeHist(leftImage1, leftImage1);
equalizeHist(rightImage2, rightImage2);
cv::Rect imageRect(0, 0, leftImage1.cols, leftImage1.rows);
cv::Rect leftRoiRect = cv::Rect(2300, 300, 1000, 1000)&imageRect;
cv::Rect rightRoiRect = cv::Rect(2200, 300, 1000, 1000)&imageRect;
Mat srcImage1 = leftImage1(leftRoiRect);
Mat srcImage2 = rightImage2(rightRoiRect);
 
// 定义用到的变量和类 [7/25/2019 wufuzheng]
int minHessian = 400;
cv::Ptr<ORB > orb = ORB::create();
orb->setScaleFactor(1.4);
orb->setNLevels(8);
orb->setScoreType(ORB::kBytes);
std::vector<KeyPoint> Keypoints1;
std::vector<KeyPoint> Keypoints2;
Mat descriptors1, descriptors2;
// 检测特征点 [7/25/2019 wufuzheng]
orb->detect(srcImage1, Keypoints1);
orb->detect(srcImage2, Keypoints2);
// 计算描述符 [7/26/2019 wufuzheng]
orb->compute(srcImage1, Keypoints1, descriptors1);
orb->compute(srcImage2, Keypoints2, descriptors2);
std::vector<DMatch> matches;
BFMatcher bfMatcher(NORM_HAMMING, true);
bfMatcher.match(descriptors1, descriptors2, matches);
// 匹配对筛选
double min_dist = 1000, max_dist = 0;
// 找出所有匹配之间的最大值和最小值
for (int i = 0; i < matches.size(); i++)
{
double dist = matches[i].distance;
if (dist < min_dist) min_dist = dist;
if (dist > max_dist) max_dist = dist;
}
// 当描述子之间的匹配不大于2倍的最小距离时,即认为该匹配是一个错误的匹配。
// 但有时描述子之间的最小距离非常小,可以设置一个经验值作为下限
std::vector<DMatch> goodMatches;
for (int i = 0; i < matches.size(); i++)
{
if (matches[i].distance <= max(2 * min_dist, 30.0))
goodMatches.push_back(matches[i]);
}
// 转为兴趣区坐标 [7/29/2019 wufuzheng]
//Geometries::Coordinate tmpRoiCoord(srcCoord.x - matchRoiRect.x, srcCoord.y - matchRoiRect.y, 0);
 
 
//绘制出匹配到的关键点
//Mat img_matches;
cv::drawMatches(srcImage1, Keypoints1, srcImage2, Keypoints2, goodMatches, img_matches);
cv::imshow("good match", img_matches);
//waitKey(0);
return 0;
}
匹配效果图如下:
 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM