小さなサンプル画像が大きなシーン画像に存在するかどうかを判断するために、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 アイコン
シーン