首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >iOS上的OpenCV :与SurfFeatureDetector和FlannBasedMatcher的错误匹配

iOS上的OpenCV :与SurfFeatureDetector和FlannBasedMatcher的错误匹配
EN

Stack Overflow用户
提问于 2012-12-10 03:00:35
回答 2查看 4K关注 0票数 1

我正在尝试使用OpenCV的特征检测工具,以确定较大的场景图像中是否存在小样本图像。

我使用了here中的代码作为参考(没有单应性部分)。

代码语言:javascript
复制
UIImage *sceneImage, *objectImage1;
cv::Mat sceneImageMat, objectImageMat1;
cv::vector<cv::KeyPoint> sceneKeypoints, objectKeypoints1;
cv::Mat sceneDescriptors, objectDescriptors1;
cv::SurfFeatureDetector *surfDetector;
cv::FlannBasedMatcher flannMatcher;
cv::vector<cv::DMatch> matches;
int minHessian;
double minDistMultiplier;

minHessian = 400;
minDistMultiplier= 3;
surfDetector = new cv::SurfFeatureDetector(minHessian);

sceneImage = [UIImage imageNamed:@"twitter_scene.png"];
objectImage1 = [UIImage imageNamed:@"twitter.png"];

sceneImageMat = cv::Mat(sceneImage.size.height, sceneImage.size.width, CV_8UC1);
objectImageMat1 = cv::Mat(objectImage1.size.height, objectImage1.size.width, CV_8UC1);

cv::cvtColor([sceneImage CVMat], sceneImageMat, CV_RGB2GRAY);
cv::cvtColor([objectImage1 CVMat], objectImageMat1, CV_RGB2GRAY);

if (!sceneImageMat.data || !objectImageMat1.data) {
    NSLog(@"NO DATA");
}

surfDetector->detect(sceneImageMat, sceneKeypoints);
surfDetector->detect(objectImageMat1, objectKeypoints1);

surfExtractor.compute(sceneImageMat, sceneKeypoints, sceneDescriptors);
surfExtractor.compute(objectImageMat1, objectKeypoints1, objectDescriptors1);

flannMatcher.match(objectDescriptors1, sceneDescriptors, matches);

double max_dist = 0; double min_dist = 100;

for( int i = 0; i < objectDescriptors1.rows; i++ )
{ 
    double dist = matches[i].distance;
    if( dist < min_dist ) min_dist = dist;
    if( dist > max_dist ) max_dist = dist;
}

cv::vector<cv::DMatch> goodMatches;
for( int i = 0; i < objectDescriptors1.rows; i++ )
{ 
    if( matches[i].distance < minDistMultiplier*min_dist )
    { 
        goodMatches.push_back( matches[i]);
    }
}
NSLog(@"Good matches found: %lu", goodMatches.size());

cv::Mat imageMatches;
cv::drawMatches(objectImageMat1, objectKeypoints1, sceneImageMat, sceneKeypoints, goodMatches, imageMatches, cv::Scalar::all(-1), cv::Scalar::all(-1),
                cv::vector<char>(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);

for( int i = 0; i < goodMatches.size(); i++ )
{
    //-- Get the keypoints from the good matches
    obj.push_back( objectKeypoints1[ goodMatches[i].queryIdx ].pt );
    scn.push_back( objectKeypoints1[ goodMatches[i].trainIdx ].pt );
}

cv::vector<uchar> outputMask;
cv::Mat homography = cv::findHomography(obj, scn, CV_RANSAC, 3, outputMask);
int inlierCounter = 0;
for (int i = 0; i < outputMask.size(); i++) {
    if (outputMask[i] == 1) {
        inlierCounter++;
    }
}
NSLog(@"Inliers percentage: %d", (int)(((float)inlierCounter / (float)outputMask.size()) * 100));

cv::vector<cv::Point2f> objCorners(4);
objCorners[0] = cv::Point(0,0);
objCorners[1] = cv::Point( objectImageMat1.cols, 0 );
objCorners[2] = cv::Point( objectImageMat1.cols, objectImageMat1.rows );
objCorners[3] = cv::Point( 0, objectImageMat1.rows );

cv::vector<cv::Point2f> scnCorners(4);

cv::perspectiveTransform(objCorners, scnCorners, homography);

cv::line( imageMatches, scnCorners[0] + cv::Point2f( objectImageMat1.cols, 0), scnCorners[1] + cv::Point2f( objectImageMat1.cols, 0), cv::Scalar(0, 255, 0), 4);
cv::line( imageMatches, scnCorners[1] + cv::Point2f( objectImageMat1.cols, 0), scnCorners[2] + cv::Point2f( objectImageMat1.cols, 0), cv::Scalar( 0, 255, 0), 4);
cv::line( imageMatches, scnCorners[2] + cv::Point2f( objectImageMat1.cols, 0), scnCorners[3] + cv::Point2f( objectImageMat1.cols, 0), cv::Scalar( 0, 255, 0), 4);
cv::line( imageMatches, scnCorners[3] + cv::Point2f( objectImageMat1.cols, 0), scnCorners[0] + cv::Point2f( objectImageMat1.cols, 0), cv::Scalar( 0, 255, 0), 4);

[self.mainImageView setImage:[UIImage imageWithCVMat:imageMatches]];

这是有效的,但我一直得到大量的匹配,即使小图像不是大图像的一部分。

下面是一个好的输出示例:

下面是一个糟糕输出的例子:

这两个输出都是相同代码的结果。唯一的区别是小样本图像。

有了这样的结果,我不可能知道样本图像何时不在较大的图像中。

在做研究的时候,我发现了this堆栈溢出问题。我按照那里给出的答案,并尝试了“findFundamentalMat 2计算机视觉应用程序编程指南”一书中建议的步骤,但我无法使其对不同大小的图像起作用(似乎是OpenCV::findFundamentalMat函数的一个限制)。

我遗漏了什么?有没有办法使用SurfFeatureDetector和FlannBasedMatcher来知道何时一个样本图像是较大图像的一部分,而另一个样本图像不是?有没有其他更好的方法来达到这个目的呢?

更新:

我更新了上面的代码以包含我使用的完整函数,包括尝试实际绘制单应性。另外,这里有3张图片-1个场景,和两个我试图在场景中找到的小物体。我得到了更好的爪子图标的内部百分比,而不是twitter图标,它实际上是在场景中。此外,由于某些原因,无法绘制单应性:

Twitter Icon

Paw Icon

Scene

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-12-10 04:14:00

您的匹配器将始终将较小的描述符列表中的每个点与较大的列表之一进行匹配。然后,您必须自己寻找这些匹配中哪些有意义,哪些没有意义。为此,您可以丢弃超过最大允许描述符距离的每个匹配,或者您可以尝试查找转换矩阵(例如,使用findHomography)并检查是否有足够多的匹配与其相对应。

票数 3
EN

Stack Overflow用户

发布于 2015-05-18 15:35:14

这是一个老帖子,但从一个类似的作业,我必须做的课程。消除不良输出的一种方法是检查大多数匹配线是否(相对地)彼此平行,并删除指向错误方向的匹配项。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13790659

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档