若该文为原创文章,转载请注明出处
本文章博客地址:http://www.javashuo.com/article/p-gbonmlye-nu.html
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么本身研究
红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…(点击传送门)web
上一篇:《OpenCV开发笔记(六十八):红胖子8分钟带你使用特征点Flann最邻近差值匹配识别(图文并茂+浅显易懂+程序源码)》
下一篇:《OpenCV开发笔记(七十):红胖子带你傻瓜式编译VS2017x64版本的openCV4》算法
红胖子,来也!
特征点、匹配,那么如何使用特征点和匹配来识别已有的物体,也就剩最关键的最后一步:寻找已知的物体了。数组
尺度不变特征变换(Scale-invariant feature transform,SIFT),是用于图像处理领域的一种描述。这种描述具备尺度不变性,可在图像中检测出关键点,是一种局部特征描述子。ide
SURF算法采用了不少方法来对每一步进行优化从而提升速度。分析显示在结果效果至关的状况下SURF的速度是SIFT的3倍。SURF善于处理具备模糊和旋转的图像,可是不善于处理视角变化和光照变化。(SIFT特征是局部特征,其对旋转、尺度缩放、亮度变化保持不变性,对视角变化、仿射变换、噪声也保持必定程度的稳定性)。
针对图像场景的特色,选择不一样的特征点,列出以前特征点相关的博文:
《OpenCV开发笔记(六十三):红胖子8分钟带你深刻了解SIFT特征点(图文并茂+浅显易懂+程序源码)》
《OpenCV开发笔记(六十四):红胖子8分钟带你深刻了解SURF特征点(图文并茂+浅显易懂+程序源码)》
《OpenCV开发笔记(六十五):红胖子8分钟带你深刻了解ORB特征点(图文并茂+浅显易懂+程序源码)》svg
最佳特征匹配老是尝试全部可能的匹配,从而使得它总可以找到最佳匹配,这也是BruteForce(暴力法)的原始含义,涉及到的类为BFMatcher类。
《OpenCV开发笔记(六十七):红胖子8分钟带你深刻了解特征点暴力匹配(图文并茂+浅显易懂+程序源码)》函数
一种近似法,算法更快可是找到的是最近邻近似匹配,因此当咱们须要找到一个相对好的匹配可是不须要最佳匹配的时候每每使用FlannBasedMatcher。
《OpenCV开发笔记(六十八):红胖子8分钟带你使用特征点Flann最邻近差值匹配识别(图文并茂+浅显易懂+程序源码)》优化
对已知物体:过滤、去噪后、提取已知物体的特征点;
对场景:过滤、去噪后、提取场景的特征点;
对已知物体特征点集合和场景中的特征点集合去匹配,计算投影矩阵;
若成功计算变换矩阵就表示识别到物体;
经过原始的四个点位置进行变换矩阵计算,便可获得场景中的已知物体的四个顶点,该四个顶点链接起来就是已知物体的位置。ui
Mat findHomography(InputArray srcPoints, InputArray dstPoints, int method = 0, double ransacReprojThreshold = 3, OutputArray mask=noArray(), const int maxIters = 2000, const double confidence = 0.995);
void perspectiveTransform( InputArray src, InputArray dst, InputArray m);
本文章博客地址:http://www.javashuo.com/article/p-gbonmlye-nu.html.net
void OpenCVManager::testFindKnownObject() { QString fileName1 = "21.jpg"; QString fileName2 = "24.jpg"; int width = 400; int height = 300; cv::Mat srcMat = cv::imread(fileName1.toStdString()); cv::Mat srcMat3 = cv::imread(fileName2.toStdString()); cv::resize(srcMat, srcMat, cv::Size(width, height)); cv::resize(srcMat3, srcMat3, cv::Size(width, height)); cv::String windowName = _windowTitle.toStdString(); cvui::init(windowName); cv::Mat windowMat = cv::Mat(cv::Size(srcMat.cols * 2, srcMat.rows * 3), srcMat.type()); cv::Ptr<cv::xfeatures2d::SIFT> _pSift = cv::xfeatures2d::SiftFeatureDetector::create(); cv::Ptr<cv::xfeatures2d::SURF> _pSurf = cv::xfeatures2d::SurfFeatureDetector::create(450, 10, 10, true, true); cv::Ptr<cv::Feature2D> _pFeature2D; cv::Ptr<cv::DescriptorMatcher> _pDescriptorMatcher; int type = 0; int findType = 0; int k1x = 25; int k1y = 25; int k2x = 75; int k2y = 25; int k3x = 75; int k3y = 75; int k4x = 25; int k4y = 75; // 定义匹配器 cv::Ptr<cv::FlannBasedMatcher> pFlannBasedMatcher = cv::FlannBasedMatcher::create(); cv::Ptr<cv::BFMatcher> pBFMatcher = cv::BFMatcher::create(); // 定义结果存放 std::vector<cv::DMatch> listDMatch; // 存储特征点检测器检测特征后的描述字 cv::Mat descriptor1; cv::Mat descriptor2; bool moveFlag = true; // 移动的标志,不用每次都匹配 std::vector<cv::Point2f> obj_corners(4); std::vector<cv::Point2f> scene_corners(4); windowMat = cv::Scalar(0, 0, 0); while(true) { cv::Mat mat; { std::vector<cv::KeyPoint> keyPoints1; std::vector<cv::KeyPoint> keyPoints2; int typeOld = type; int findTypeOld = findType; int k1xOld = k1x; int k1yOld = k1y; int k2xOld = k2x; int k2yOld = k2y; int k3xOld = k3x; int k3yOld = k3y; int k4xOld = k4x; int k4yOld = k4y; mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1), cv::Range(srcMat.cols * 0, srcMat.cols * 1)); mat = cv::Scalar(0); cvui::trackbar(windowMat, 0 + width * 0, 0 + height * 0, 165, &type, 0, 1); cv::String str; switch(type) { case 0: str = "sift"; _pFeature2D = _pSift; break; case 1: str = "surf"; _pFeature2D = _pSurf; break; default: break; } cvui::printf(windowMat, width / 4 + width * 0 - 20, 40 + height * 0, str.c_str()); cvui::trackbar(windowMat, width / 2 + width * 0, 0 + height * 0, 165, &findType, 0, 1); switch(findType) { case 0: str = "BFMatcher"; _pDescriptorMatcher = pBFMatcher; break; case 1: str = "FlannBasedMatcher"; _pDescriptorMatcher = pFlannBasedMatcher; break; default: break; } cvui::printf(windowMat, width / 4 * 3 + width * 0 - 20, 40 + height * 0, str.c_str()); cvui::printf(windowMat, 0 + width * 0, 60 + height * 0, "k1x"); cvui::trackbar(windowMat, 0 + width * 0, 70 + height * 0, 165, &k1x, 0, 100); cvui::printf(windowMat, 0 + width * 0, 120 + height * 0, "k1y"); cvui::trackbar(windowMat, 0 + width * 0, 130 + height * 0, 165, &k1y, 0, 100); cvui::printf(windowMat, width / 2 + width * 0, 60 + height * 0, "k2x"); cvui::trackbar(windowMat, width / 2 + width * 0, 70 + height * 0, 165, &k2x, 0, 100); cvui::printf(windowMat, width / 2 + width * 0, 120 + height * 0, "k2y"); cvui::trackbar(windowMat, width / 2 + width * 0, 130 + height * 0, 165, &k2y, 0, 100); cvui::printf(windowMat, 0 + width * 0, 30 + height * 0 + height / 2, "k3x"); cvui::trackbar(windowMat, 0 + width * 0, 40 + height * 0 + height / 2, 165, &k3x, 0, 100); cvui::printf(windowMat, 0 + width * 0, 90 + height * 0 + height / 2, "k3y"); cvui::trackbar(windowMat, 0 + width * 0, 100 + height * 0 + height / 2, 165, &k3y, 0, 100); cvui::printf(windowMat, width / 2 + width * 0, 30 + height * 0 + height / 2, "k4x"); cvui::trackbar(windowMat, width / 2 + width * 0, 40 + height * 0 + height / 2, 165, &k4x, 0, 100); cvui::printf(windowMat, width / 2 + width * 0, 90 + height * 0 + height / 2, "k4y"); cvui::trackbar(windowMat, width / 2 + width * 0, 100 + height * 0 + height / 2, 165, &k4y, 0, 100); if( k1xOld != k1x || k1yOld != k1y || k2xOld != k2x || k2yOld != k2y || k3xOld != k3x || k3yOld != k3y || k4xOld != k4x || k4yOld != k4y || typeOld != type || findTypeOld != findType) { typeOld = type; findTypeOld = findType; moveFlag = true; } std::vector<cv::Point2f> srcPoints; std::vector<cv::Point2f> dstPoints; srcPoints.push_back(cv::Point2f(0.0f, 0.0f)); srcPoints.push_back(cv::Point2f(srcMat.cols - 1, 0.0f)); srcPoints.push_back(cv::Point2f(srcMat.cols - 1, srcMat.rows - 1)); srcPoints.push_back(cv::Point2f(0.0f, srcMat.rows - 1)); dstPoints.push_back(cv::Point2f(srcMat.cols * k1x / 100.0f, srcMat.rows * k1y / 100.0f)); dstPoints.push_back(cv::Point2f(srcMat.cols * k2x / 100.0f, srcMat.rows * k2y / 100.0f)); dstPoints.push_back(cv::Point2f(srcMat.cols * k3x / 100.0f, srcMat.rows * k3y / 100.0f)); dstPoints.push_back(cv::Point2f(srcMat.cols * k4x / 100.0f, srcMat.rows * k4y / 100.0f)); cv::Mat M = cv::getPerspectiveTransform(srcPoints, dstPoints); cv::Mat srcMat2; cv::warpPerspective(srcMat3, srcMat2, M, cv::Size(srcMat.cols, srcMat.rows), cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar::all(0)); mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1), cv::Range(srcMat.cols * 1, srcMat.cols * 2)); cv::addWeighted(mat, 0.0f, srcMat2, 1.0f, 0.0f, mat); if(moveFlag) { moveFlag = false; //特征点检测 // _pSift->detect(srcMat, keyPoints1); _pFeature2D->detectAndCompute(srcMat, cv::Mat(), keyPoints1, descriptor1); //绘制特征点(关键点) cv::Mat resultShowMat; cv::drawKeypoints(srcMat, keyPoints1, resultShowMat, cv::Scalar(0, 0, 255), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS); mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2), cv::Range(srcMat.cols * 0, srcMat.cols * 1)); cv::addWeighted(mat, 0.0f, resultShowMat, 1.0f, 0.0f, mat); //特征点检测 // _pSift->detect(srcMat2, keyPoints2); _pFeature2D->detectAndCompute(srcMat2, cv::Mat(), keyPoints2, descriptor2); //绘制特征点(关键点) cv::Mat resultShowMat2; cv::drawKeypoints(srcMat2, keyPoints2, resultShowMat2, cv::Scalar(0, 0, 255), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS); mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2), cv::Range(srcMat.cols * 1, srcMat.cols * 2)); cv::addWeighted(mat, 0.0f, resultShowMat2, 1.0f, 0.0f, mat); // FlannBasedMatcher最近邻匹配 _pDescriptorMatcher->match(descriptor1, descriptor2, listDMatch); // drawMatch绘制出来,并排显示了,高度同样,宽度累加(由于两个宽度相同,因此是两倍了) cv::Mat matchesMat; cv::drawMatches(srcMat, keyPoints1, srcMat2, keyPoints2, listDMatch, matchesMat); mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3), cv::Range(srcMat.cols * 0, srcMat.cols * 2)); cv::addWeighted(mat, 0.0f, matchesMat, 1.0f, 0.0f, mat); // 定义两个局部变量 std::vector<cv::Point2f> obj; std::vector<cv::Point2f> scene; // 从匹配成功的匹配对中获取关键点 for(int index = 0; index < listDMatch.size(); index++) { obj.push_back(keyPoints1[listDMatch[index].queryIdx].pt); scene.push_back(keyPoints2[listDMatch[index].trainIdx].pt); } // 计算透视变换 cv::Mat H = cv::findHomography(obj, scene, CV_RANSAC); // 从待测图片中获取角点 obj_corners[0] = cv::Point2f(0,0); obj_corners[1] = cv::Point2f(srcMat.cols,0); obj_corners[2] = cv::Point2f(srcMat.cols, srcMat.rows); obj_corners[3] = cv::Point2f(0, srcMat.rows); // 进行透视变换 cv::perspectiveTransform(obj_corners, scene_corners, H); } // 绘制出角点之间的线 qDebug() << __FILE__ << __LINE__ << scene_corners[0].x << scene_corners[0].y << scene_corners[1].x << scene_corners[1].y; cv::line(windowMat, scene_corners[0] + cv::Point2f(srcMat.cols * 1, srcMat.rows * 0), scene_corners[1] + cv::Point2f(srcMat.cols * 1, srcMat.rows * 0), cv::Scalar(0, 0, 255), 2); cv::line(windowMat, scene_corners[1] + cv::Point2f(srcMat.cols * 1, srcMat.rows * 0), scene_corners[2] + cv::Point2f(srcMat.cols * 1, srcMat.rows * 0), cv::Scalar(0, 0, 255), 2); cv::line(windowMat, scene_corners[2] + cv::Point2f(srcMat.cols * 1, srcMat.rows * 0), scene_corners[3] + cv::Point2f(srcMat.cols * 1, srcMat.rows * 0), cv::Scalar(0, 0, 255), 2); cv::line(windowMat, scene_corners[3] + cv::Point2f(srcMat.cols * 1, srcMat.rows * 0), scene_corners[0] + cv::Point2f(srcMat.cols * 1, srcMat.rows * 0), cv::Scalar(0, 0, 255), 2); } cv::imshow(windowName, windowMat); // 更新 cvui::update(); // 显示 // esc键退出 if(cv::waitKey(25) == 27) { break; } } }
对应版本号v1.63.0code
上一篇:《OpenCV开发笔记(六十八):红胖子8分钟带你使用特征点Flann最邻近差值匹配识别(图文并茂+浅显易懂+程序源码)》
下一篇:《OpenCV开发笔记(七十):红胖子带你傻瓜式编译VS2017x64版本的openCV4》