1

我正在尝试使用 OpenCV 的特征检测工具来确定较大的场景图像中是否存在小样本图像。
我使用这里的代码作为参考(没有单应性部分)。

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]];

这行得通,但我不断得到大量的匹配,即使小图像不是大图像的一部分。
这是一个良好输出
良好的输出
的示例: 这是一个错误输出的示例:
输出不良
两个输出都是相同代码的结果。唯一的区别是小样本图像。
有了这样的结果,我不可能知道样本图像何时不在较大的图像中。
在进行研究时,我发现了这个stackoverflow 问题。我按照那里给出的答案,并尝试了“OpenCV 2 Computer Vision Application Programming Cookbook”一书中建议的步骤,但我无法使其适用于不同尺寸的图像(似乎是 cv:: findFundamentalMat 函数)。

我错过了什么?有没有办法使用 SurfFeatureDetector 和 FlannBasedMatcher 来知道一个样本图像何时是更大图像的一部分,而另一个样本图像不是?有没有更适合该目的的不同方法?

更新:
我更新了上面的代码以包含我使用的完整函数,包括尝试实际绘制单应性。另外,这里有 3 张图像 - 1 个场景,以及我试图在场景中找到的两个小物体。我的爪子图标的内部百分比越来越好,而不是 Twitter 图标,它实际上在场景中。另外,由于某种原因没有绘制单应性:
Twitter Icon
Paw Icon
Scene

4

2 回答 2

3

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

于 2012-12-09T20:14:00.370 回答
0

这是一篇旧帖子,但我必须在课堂上完成类似的作业。删除错误输出的一种方法是检查大多数匹配线是否彼此平行(相对),并删除指向错误方向的匹配。

于 2015-05-18T07:35:13.500 回答