若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/107348874
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究
红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…(点击传送门)
上一篇:《OpenCV开发笔记(六十六):红胖子8分钟带你总结形态学操作-膨胀、腐蚀、开运算、闭运算、梯度、顶帽、黑帽(图文并茂+浅显易懂+程序源码)》
下一篇:持续补充中…
红胖子,来也!
特征点是用来匹配的,就是原始图像与目标图像之间存在哪些匹配的同类型的特征点,匹配点的多少则是作为一个相似度评定标准的输入,达到一定相似度则认为匹配到了。
本篇章结合sift特征点和暴力匹配,进行特征点匹配实现步骤原理讲解。
第四个图片的匹配效果不好,想要效果好需要根据图像特点去选择特征点提取的方式,此处主要是为了讲解流程。
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/107348874
最佳特征匹配总是尝试所有可能的匹配,从而使得它总能够找到最佳匹配,这也是BruteForce(暴力法)的原始含义,涉及到的类为BFMatcher类。
SIFT,即尺度不变特征变换(Scale-invariant feature transform,SIFT),是用于图像处理领域的一种描述。这种描述具有尺度不变性,可在图像中检测出关键点,是一种局部特征描述子。
针对图像场景的特点,选择不同的特征点,列出之前特征点相关的博文:
《OpenCV开发笔记(六十三):红胖子8分钟带你深入了解SIFT特征点(图文并茂+浅显易懂+程序源码)》
《OpenCV开发笔记(六十四):红胖子8分钟带你深入了解SURF特征点(图文并茂+浅显易懂+程序源码)》
《OpenCV开发笔记(六十五):红胖子8分钟带你深入了解ORB特征点(图文并茂+浅显易懂+程序源码)》
// 定义匹配器
cv::Ptr pBFMatcher = cv::BFMatcher::create();
// 定义结果存放
std::vector listDMatch;
// 存储特征点检测器检测特征后的描述字
cv::Mat descriptor1;
cv::Mat descriptor2;
_pSift->detectAndCompute(srcMat1, cv::Mat(), keyPoints1, descriptor1);
_pSift->detectAndCompute(srcMat1, cv::Mat(), keyPoints1, descriptor1);
// bfMatcher暴力匹配
pBFMatcher->match(descriptor1, descriptor2, listDMatch);
static Ptr create( int normType=NORM_L2,
bool crossCheck=false ) ;
void BFMatcher::match( InputArray queryDescriptors,
InputArray trainDescriptors,
std::vector& matches,
InputArray mask=noArray() ) const;
void drawMatches( InputArray img1,
const std::vector& keypoints1,
InputArray img2,
const std::vector& keypoints2,
const std::vector& matches1to2,
InputOutputArray outImg,
const Scalar& matchColor=Scalar::all(-1),
const Scalar& singlePointColor=Scalar::all(-1),
const std::vector& matchesMask=std::vector(),
int flags=DrawMatchesFlags::DEFAULT );
void OpenCVManager::testBFMatcher()
{
QString fileName1 = "13.jpg";
int width = 400;
int height = 300;
cv::Mat srcMat = cv::imread(fileName1.toStdString());
cv::resize(srcMat, srcMat, 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 _pSift = cv::xfeatures2d::SiftFeatureDetector::create();
int k1x = 0;
int k1y = 0;
int k2x = 100;
int k2y = 0;
int k3x = 100;
int k3y = 100;
int k4x = 0;
int k4y = 100;
cv::Ptr pBFMatcher;
pBFMatcher = cv::BFMatcher::create();
std::vector listDMatch;
cv::Mat descriptor1;
cv::Mat descriptor2;
bool moveFlag = true; // 移动的标志,不用每次都匹配
windowMat = cv::Scalar(0, 0, 0);
while(true)
{
cv::Mat mat;
{
std::vector keyPoints1;
std::vector keyPoints2;
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::printf(windowMat, 0 + width * 0, 10 + height * 0, "k1x");
cvui::trackbar(windowMat, 0 + width * 0, 20 + height * 0, 165, &k1x, 0, 100);
cvui::printf(windowMat, 0 + width * 0, 70 + height * 0, "k1y");
cvui::trackbar(windowMat, 0 + width * 0, 80 + height * 0, 165, &k1y, 0, 100);
cvui::printf(windowMat, width / 2 + width * 0, 10 + height * 0, "k2x");
cvui::trackbar(windowMat, width / 2 + width * 0, 20 + height * 0, 165, &k2x, 0, 100);
cvui::printf(windowMat, width / 2 + width * 0, 70 + height * 0, "k2y");
cvui::trackbar(windowMat, width / 2 + width * 0, 80 + height * 0, 165, &k2y, 0, 100);
cvui::printf(windowMat, 0 + width * 0, 10 + height * 0 + height / 2, "k3x");
cvui::trackbar(windowMat, 0 + width * 0, 20 + height * 0 + height / 2, 165, &k3x, 0, 100);
cvui::printf(windowMat, 0 + width * 0, 70 + height * 0 + height / 2, "k3y");
cvui::trackbar(windowMat, 0 + width * 0, 80 + height * 0 + height / 2, 165, &k3y, 0, 100);
cvui::printf(windowMat, width / 2 + width * 0, 10 + height * 0 + height / 2, "k4x");
cvui::trackbar(windowMat, width / 2 + width * 0, 20 + height * 0 + height / 2, 165, &k4x, 0, 100);
cvui::printf(windowMat, width / 2 + width * 0, 70 + height * 0 + height / 2, "k4y");
cvui::trackbar(windowMat, width / 2 + width * 0, 80 + 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)
{
moveFlag = true;
}
std::vector srcPoints;
std::vector 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(srcMat,
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);
_pSift->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);
_pSift->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);
// bfMatcher暴力匹配
pBFMatcher->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);
}
}
cv::imshow(windowName, windowMat);
// 更新
cvui::update();
// 显示
// esc键退出
if(cv::waitKey(25) == 27)
{
break;
}
}
}
对应版本号v1.61.0
上一篇:《OpenCV开发笔记(六十六):红胖子8分钟带你总结形态学操作-膨胀、腐蚀、开运算、闭运算、梯度、顶帽、黑帽(图文并茂+浅显易懂+程序源码)》
下一篇:持续补充中…