1

小さなサンプル画像が大きなシーン画像に存在するかどうかを判断するために、OpenCV の機能検出ツールを使用しようとしています。here
のコードを参照として使用しました(ホモグラフィ部分なし)。

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

これは機能しますが、小さな画像が大きな画像の一部ではない場合でも、かなりの量の一致が得られます。
良い出力の例を
良い出力
次に示します。悪い出力の例を次に示します。
悪い出力
両方の出力が同じコードの結果です。唯一の違いは、小さなサンプル画像です。
このような結果では、サンプル画像が大きな画像にないときを知ることは不可能です。
調査中に、このスタックオーバーフローの質問を見つけまし。そこで与えられた答えに従い、「OpenCV 2 Computer Vision Application Programming Cookbook」本で提案されている手順を試しましたが、さまざまなサイズの画像で機能させることができませんでした (cv:: の制限のようです)。 findFundamentalMat 関数)。

私は何が欠けていますか?SurfFeatureDetector と FlannBasedMatcher を使用して、あるサンプル画像がより大きな画像の一部であり、別のサンプル画像がそうでない場合を知る方法はありますか? その目的に適した別の方法はありますか?

更新:
上記のコードを更新して、ホモグラフィを実際に描画しようとするなど、使用する完全な関数を含めました。さらに、ここに 3 つの画像があります。1 つのシーンと、シーン内で見つけようとしている 2 つの小さなオブジェクトです。実際にシーン内にある Twitter アイコンではなく、足アイコンのインライア パーセンテージが向上しています。さらに、何らかの理由でホモグラフィーが描かれていません:
Twitter アイコン
Paw アイコン
シーン

4

2 に答える 2

3

マッチャーは常に、小さな記述子リストから大きなリストの 1 つまでのすべてのポイントを照合します。次に、これらの一致のどれが意味を成し、どれが意味をなさないかを自分で探す必要があります。これを行うには、最大許容記述子距離を超えるすべての一致を破棄するか、(findHomography などを使用して) 変換行列を見つけて、それに対応する一致が十分にあるかどうかを確認します。

于 2012-12-09T20:14:00.370 に答える