OpenCV特征检测(三)SIFT,Surf及其引申的思考
尺度不变特征核心是不同尺度拍摄的两幅图像的同一个物体,对应的两个theta比率等于拍摄两幅图像的尺度的比率。
而OpenCV提供的SIFT和Surf正是利用尺度不变性就行特征点检测的代表。它们的原理可以参考本文的参考文献,写的很详细,本来想在这里介绍下它们的原理的,但是看到参考的blog中写的太好了,我不能写的这么清楚,就省去了。
使用起来也很方便,比如利用Sift找到匹配物体代码如下:
int main(int argc, char** argv){Mat img_scene = imread("./box_in_scene.png", CV_LOAD_IMAGE_GRAYSCALE);Mat img_object = imread("./box.png", CV_LOAD_IMAGE_GRAYSCALE);if (!img_object.data || !img_scene.data){std::cout << " --(!) Error reading images " << std::endl; return -1;}std::vector<KeyPoint> keypoints_object, keypoints_scene;//-- Step 1: Detect the keypoints using SIFT DetectorPtr<FeatureDetector> detector = SiftFeatureDetector::create(400);detector->detect(img_object, keypoints_object);detector->detect(img_scene, keypoints_scene); //-- Step 2: Calculate descriptors (feature vectors)Ptr<DescriptorExtractor> extractor = SiftDescriptorExtractor::create();Mat descriptors_object, descriptors_scene;extractor->compute(img_object, keypoints_object, descriptors_object);extractor->compute(img_scene, keypoints_scene, descriptors_scene);//-- Step 3: Matching descriptor vectors using FLANN matcherFlannBasedMatcher matcher;std::vector< DMatch > matches;matcher.match(descriptors_object, descriptors_scene, matches);double max_dist = 0; double min_dist = 100;//-- Quick calculation of max and min distances between keypointsfor (int i = 0; i < descriptors_object.rows; i++){double dist = matches[i].distance;if (dist < min_dist) min_dist = dist;if (dist > max_dist) max_dist = dist;}//-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist )std::vector< DMatch > good_matches;for (int i = 0; i < descriptors_object.rows; i++){if (matches[i].distance < 3 * min_dist){good_matches.push_back(matches[i]);}}Mat img_matches;drawMatches(img_object, keypoints_object, img_scene, keypoints_scene,good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);//-- Localize the objectstd::vector<Point2f> obj;std::vector<Point2f> scene;for (int i = 0; i < good_matches.size(); i++){//-- Get the keypoints from the good matchesobj.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); //-- Get the corners from the image_1 ( the object to be "detected" )std::vector<Point2f> obj_corners(4);obj_corners[0] = Point(0, 0);obj_corners[1] = Point(img_object.cols, 0);obj_corners[2] = Point(img_object.cols, img_object.rows);obj_corners[3] = Point(0, 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(img_object.cols, 0), scene_corners[1] + Point2f(img_object.cols, 0), Scalar(0, 255, 0), 4);line(img_matches, scene_corners[1] + Point2f(img_object.cols, 0), scene_corners[2] + Point2f(img_object.cols, 0), Scalar(0, 255, 0), 4);line(img_matches, scene_corners[2] + Point2f(img_object.cols, 0), scene_corners[3] + Point2f(img_object.cols, 0), Scalar(0, 255, 0), 4);line(img_matches, scene_corners[3] + Point2f(img_object.cols, 0), scene_corners[0] + Point2f(img_object.cols, 0), Scalar(0, 255, 0), 4);//-- Show detected matchesimshow("Good Matches & Object detection", img_matches);waitKey(0);return 0;
}
结果如下:
如果用Surf只用把代码中的Sift换成Surf即可。研究Sift和Surf原理会发现,他们都会用到Hessian矩阵,而且Hessian矩阵的特征值大小和它两个方向的边缘强度有关,特征向量是它梯度方向即垂直于边缘方向。
注意DescriptorExtractor和FeatureDetector是一回事,可以直接给DescriptorExtractor赋值为FeatureDetector。
/** Feature detectors in OpenCV have wrappers with a common interface that enables you to easily switch
between different algorithms solving the same problem. All objects that implement keypoint detectors
inherit the FeatureDetector interface. */
typedef Feature2D FeatureDetector;
/** Extractors of keypoint descriptors in OpenCV have wrappers with a common interface that enables you
to easily switch between different algorithms solving the same problem. This section is devoted to
computing descriptors represented as vectors in a multidimensional space. All objects that implement
the vector descriptor extractors inherit the DescriptorExtractor interface.*/
typedef Feature2D DescriptorExtractor;
通过这一点我们可以得到启发,其实利用它的这一思想,可以进行边缘检测。
比如对下图进行边缘检测,因为整体对比度不高,我们先试试用Canny边缘检测。
Mat gray;
int low_threshold = 100;
const int max_threshold = 128;void canny_edge_detector(int, void*)
{Mat edge;Canny(gray, edge, low_threshold, 2 * low_threshold);imshow("canny detect", edge);
}int main(int argc, char** argv)
{Mat src = imread("./demo.png", CV_LOAD_IMAGE_COLOR);imshow("source image", src);cvtColor(src, gray, CV_BGR2GRAY);namedWindow("canny detect");createTrackbar("canny threshold", "canny detect", &low_threshold, max_threshold, canny_edge_detector);canny_edge_detector(0, 0);waitKey(0);return 0;
}
结果如下:
在低阈值为100,高阈值为200时候,可以准确检测到白线的边缘,但是左侧边缘因为对比度低,丢失了,如果调整阈值,比较小的时候可以依稀看到左侧边缘,但是此时干扰太多,而且我们很难能够得到准确的阈值时多少,如果借助Hessian矩阵特征值,最大特征值是最小特征值的10倍以上,认为是边缘点(这个条件比较宽松,后续可以再改进)
int main(int argc, char** argv)
{Mat src = imread("./demo.png", CV_LOAD_IMAGE_COLOR);imshow("source image", src);Mat gray;cvtColor(src, gray, CV_BGR2GRAY);// 高斯滤波Mat filter;cv::GaussianBlur(gray, filter, cv::Size(3, 3), 1.1, 1.1);cv::GaussianBlur(filter, filter, cv::Size(3, 3), 1.1, 1.1);// 利用cornerEigenValsAndVecs计算Hessian矩阵特征值和特征向量Mat dst; Mat result = Mat::zeros(src.size(), CV_8UC1);cornerEigenValsAndVecs(filter, dst, 3, 3); // dst每一个元素是Vec6ffor (int r = 0; r < dst.rows; r++){for (int c = 0; c < dst.cols; c++){float lamda1 = dst.at<Vec6f>(r, c)[0];float lamda2 = dst.at<Vec6f>(r, c)[1];if (lamda1 == 0 || lamda2 == 0) continue; if (lamda1 > 10 * lamda2 || lamda2 > 10 * lamda1){result.at<uchar>(r, c) = 255;}}}// 数学形态学 腐蚀Mat k1 = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));Mat k2 = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));morphologyEx(result, result, MORPH_ERODE, k2, Point(-1, -1), 1);morphologyEx(result, result, MORPH_DILATE, k1, Point(-1, -1), 1);imshow("my edge detector", result);waitKey(0);return 0;
}
可以保留所有的边缘,后面再根据一些过滤条件,应该可以获取边缘信息。
参考:
《OpenCV计算机视觉编程攻略(第2版)》 [加] Robert 著 相银初 译
https://blog.csdn.net/zddblog/article/details/7521424
https://www.jianshu.com/p/db4bbe760d2e
http://www.doc88.com/p-6458994174161.html
OpenCV特征检测(三)SIFT,Surf及其引申的思考相关推荐
- opencv中的SIFT,SURF,ORB,FAST 特征描叙算子比较
opencv中的SIFT,SURF,ORB,FAST 特征描叙算子比较 参考: http://wenku.baidu.com/link?url=1aDYAJBCrrK-uk2w3sSNai7h52x_ ...
- OpenCV + CPP 系列(卅五)图像特征提取(SURF特征检测、SIFT特征检测)
文章目录 一.SIFT特征检测 二.SURF特征检测 演示SURF.SIFT特征检测 OpenCV-python 角点特征检测之二(SIFT.SURF.ORB) 一.SIFT特征检测 SIFT(Sca ...
- 图像特征检测描述:SIFT、SURF、ORB、HOG、LBP特征的原理概述
版权声明:本文为博主原创文章,转载请标明原始博文地址: https://blog.csdn.net/yuanlulu/article/details/82148429 </div>< ...
- 三种强大的物体识别算法——SIFT/SURF、haar特征、广义hough变换的特性对比分析
识别算法概述: SIFT/SURF基于灰度图, 一.首先建立图像金字塔,形成三维的图像空间,通过Hessian矩阵获取每一层的局部极大值,然后进行在极值点周围26个点进行NMS,从而得到粗略的特征点, ...
- linux/ubuntu下简单好用的python opencv安装教程 ( 解决 imshow, SIFT, SURF, CSRT使用问题)
linux/ubuntu下简单好用的python opencv安装教程 ( 解决 imshow, SIFT, SURF, CSRT使用问题) 参考文章: (1)linux/ubuntu下简单好用的py ...
- OpenCV系列之SIFT尺度不变特征变换 | 三十九
目标 在这一章当中, 我们将学习SIFT算法的概念 我们将学习找到SIFT关键点和描述算符. 理论 在前两章中,我们看到了一些像Harris这样的拐角检测器.它们是旋转不变的,这意味着即使图像旋转了, ...
- 【Python+OpenCV】主流特征点检测器和描述子总结与实现附拼接结果(SIFT,SURF,ORB,AKAZE,FAST,BRIEF,CenSurE,BEBLID,SuperPoint)
文章目录 准备工作 SIFT SURF ORB AKAZE FAST与BRIEF CenSurE BEBLID 匹配点后的图像拼接 SuperPoint 总结 准备工作 先准备两张待处理的图像,要求有 ...
- 物体识别算法——SIFT/SURF、haar特征、广义hough变换的对比分析
著作权归作者所有. 商业转载请联系作者获得授权,非商业转载请注明出处. 作者:cvvision 链接:http://www.cvvision.cn/7780.html 来源:CV视觉网 识别算法概述: ...
- SIFT,SURF,ORB,FAST 特征提取算法比较
SIFT,SURF,ORB,FAST 特征提取算法比较 主要的特征检测方法有以下几种,在一般的图像处理库中(如OpenCV, VLFeat, Boofcv等)都会实现. FAST ,Machine L ...
最新文章
- 激动~这是我看到的最好的目标检测RCNN了!
- Spring Boot 整合 Freemarker
- PPT讲解机器人产业发展现状与未来展望,重磅资料
- LINUX CentOS7安装字体库
- 6月统计|.NET薪资一旦高起来,岂是其他语言能比的!
- python 代理服务器_Python实现HTTP代理服务器
- 关于UNIX功能测试宏
- 你那不是拖延症,只是习惯性逃避
- C++ Struct和Union区别
- sqlserver备份还原丢失dbo_sqlserver数据库的备份与恢复sql实现
- 水经注地图发布服务中间件的适用范围
- IDEA添加快捷输入
- aabResGuard使用
- 软件推荐:强力卸载软件HIBIT
- Facebook 企业广告账户开户流程、资料准备、开户时间、开户须知及OE链接
- WPF在mxs里引用图片资源并释放的方法
- 《nodejs+gulp+webpack基础实战篇》课程笔记(六)--附加课
- 大咖说·图书分享|了不起的JavaScript工程师:从前端到全端高级进阶
- Zigbee(E18-MS1-PCB)使用记录
- springboot 快速启动(十二)——发送短信