8

アプリケーションのポイントは、既に設定されている画像のリストから画像を認識することです。画像のリストには、SIFT 記述子が抽出され、ファイルに保存されています。ここで興味深いものは何もありません:

std::vector<cv::KeyPoint> detectedKeypoints;
cv::Mat objectDescriptors;

// Extract data
cv::SIFT sift;
sift.detect(image, detectedKeypoints);
sift.compute(image, detectedKeypoints, objectDescriptors);

// Save the file
cv::FileStorage fs(file, cv::FileStorage::WRITE);
fs << "descriptors" << objectDescriptors;
fs << "keypoints" << detectedKeypoints;
fs.release();

次に、デバイスが写真を撮ります。SIFT 記述子も同様に抽出されます。ここでのアイデアは、記述子をファイルの記述子と比較することでした。私は OpenCV の FLANN マッチャーを使用してそれを行っています。画像ごとに類似性を定量化しようとしています。リスト全体を調べた後、最適な一致が得られるはずです。

const cv::Ptr<cv::flann::IndexParams>& indexParams = new cv::flann::KDTreeIndexParams(1);
const cv::Ptr<cv::flann::SearchParams>& searchParams = new cv::flann::SearchParams(64);

// Match using Flann
cv::Mat indexMat;
cv::FlannBasedMatcher matcher(indexParams, searchParams);
std::vector< cv::DMatch > matches;
matcher.match(objectDescriptors, readDescriptors, matches);

マッチング後、特徴ベクトル間で見つかった最も近い距離のリストを取得することがわかりました。最小距離を見つけ、それを使用して「適切な一致」をカウントし、それぞれのポイントのリストを取得することもできます。

// Count the number of mathes where the distance is less than 2 * min_dist
int goodCount = 0;
for (int i = 0; i < objectDescriptors.rows; i++)
{
    if (matches[i].distance <  2 * min_dist)
    {
        ++goodCount;
        // Save the points for the homography calculation
        obj.push_back(detectedKeypoints[matches[i].queryIdx].pt);
        scene.push_back(readKeypoints[matches[i].trainIdx].pt);
    }
}

これをより簡単に理解できるようにするために、コードの簡単な部分を示しています。一部はここにある必要がないことはわかっています。

続けて、このように適切な一致の数を数えるだけで十分だと思っていましたが、ほとんどの場合、記述子が最も多い画像を指すだけでした。この後に私が試みたのは、ホモグラフィの計算でした。目的は、それを計算して、有効なホモラフィかどうかを確認することでした。良い一致だけが、良い変換であるホモグラフィーを持つことが期待されていました。ホモグラフィの作成は、std::vector< cv::Point2f>であるobjシーンcv::findHomographyを使用するだけで行われました。オンラインで見つけたコードを使用して、ホモグラフィの有効性を確認しました。

bool niceHomography(cv::Mat H)
{
    std::cout << H << std::endl;

    const double det = H.at<double>(0, 0) * H.at<double>(1, 1) - H.at<double>(1, 0) * H.at<double>(0, 1);
    if (det < 0)
    {
        std::cout << "Homography: bad determinant" << std::endl;
        return false;
    }

    const double N1 = sqrt(H.at<double>(0, 0) * H.at<double>(0, 0) + H.at<double>(1, 0) * H.at<double>(1, 0));
    if (N1 > 4 || N1 < 0.1)
    {
        std::cout << "Homography: bad first column" << std::endl;
        return false;
    }

    const double N2 = sqrt(H.at<double>(0, 1) * H.at<double>(0, 1) + H.at<double>(1, 1) * H.at<double>(1, 1));
    if (N2 > 4 || N2 < 0.1)
    {
        std::cout << "Homography: bad second column" << std::endl;
        return false;
    }

    const double N3 = sqrt(H.at<double>(2, 0) * H.at<double>(2, 0) + H.at<double>(2, 1) * H.at<double>(2, 1));
    if (N3 > 0.002)
    {
        std::cout << "Homography: bad third row" << std::endl;
        return false;
    }

    return true;
}

この背後にある数学を理解していないので、テスト中に、この関数をホモグラフィの行列式が正であるかどうかの単純なチェックに置き換えることがありました。問題は、ここで問題が発生し続けたことです。同形異義語は、すべて悪いか、そうであってはならないときに良いものでした (行列式だけをチェックしていたとき)。

私は実際にホモグラフィを使用し、多くのポイントについて、ソース画像での位置を使用して宛先画像での位置を計算する必要があると考えました。次に、これらの平均距離を比較します。理想的には、正しい画像の場合、平均距離が非常に明らかに小さいことが理想的です。これはまったく機能ませんでした。すべての距離は巨大でした。正しい位置を計算するためにホモグラフィを逆に使用したのではないかと思いましたが、objシーンを相互に切り替えると、同様の結果が得られました。

私が試したその他のことは、SIFT の代わりに SURF 記述子、FLANN の代わりに BFMatcher (ブルート フォース)、最小距離に応じた数値の代わりにすべての画像のn 個の最小距離を取得すること、またはグローバルな最大距離に応じて距離を取得することでした。これらのアプローチはどれも明確な良い結果をもたらしませんでした。

私の唯一の次の戦略は、画像を鮮明にするか、またはセグメンテーションに使用されるいくつかのローカルしきい値またはアルゴリズムを使用してバイナリ画像に変換することです. 私の仕事で誰かが見ることができる提案や間違いを探しています。

これが関連しているかどうかはわかりませんが、これをテストしている画像をいくつか追加しました。多くの場合、テスト画像では、ほとんどの SIFT ベクトルが絵画よりもフレーム (コントラストが高い) に由来します。これが、画像を鮮明にすることがうまくいくと考えている理由ですが、以前に行ったことが間違っている場合に備えて、深く掘り下げたくありません。

画像のギャラリーは、タイトルの説明とともにここにあります。かなり解像度の高い画像ですので、参考になればと思います。

4

2 に答える 2

0

あなたは正しい道を進んでいます。

まず、「2*min_dist による適切な一致」https://stackoverflow.com/a/23019889/1983544ではなく、2 番目に近い比率を使用します。

第二に、ホモグラフィを別の方法で使用します。ホモグラフィを見つけると、H 行列だけでなく、それに一致する対応の数もわかります。>=15 などの妥当な数値かどうかを確認します。より小さい場合、オブジェクトは一致しません。

第三に、大きな視点変更がある場合、SIFT または SURF は画像を一致させることができません。代わりに MODS ( http://cmp.felk.cvut.cz/wbs/は Windows と Linux のバイナリ、およびアルゴリズムを説明する論文です) または ASIFT (はるかに遅く、はるかに劣りますが、オープン ソース)を使用してみてくださいhttp: //www.ipol.im/pub/art/2011/my-asift/

または、少なくとも SIFT の代わりに MSER または Hessian-Affine 検出器を使用します (SIFT を記述子として保持します)。

于 2014-05-14T13:56:54.447 に答える