35

この質問は、OpenCV 関数に関するものですfindHomographygetPerspectiveTransform&getAffineTransform

  1. findHomographyとはどう違いgetPerspectiveTransformますか?ドキュメントからの私の理解は、4 つ以上の対応関係 (おそらく最小二乗法のようなものを使用して) を提供した場合でも、4 つの対応関係 (getPerspectiveTransformホモグラフィ/遠近法変換を計算するために必要な最小値) を使用して変換を計算することです? findHomography)。これは正しいです?(その場合、OpenCV がまだ getPerspectiveTransform をサポートし続けている唯一の理由はレガシーであるべきですか?)

  2. findHomography私の次の懸念は、アフィン変換の計算に相当するものがあるかどうかを知りたいということです? つまり、最小二乗法または同等の堅牢な方法を使用して計算およびアフィン変換を行う関数です。ドキュメントによると、getAffineTransform対応は 3 つしか取りません (これは、アフィン変換を計算するために必要な最小値です)。

一番、

4

5 に答える 5

43

Q #1 : そうです、findHomography は 2 組の点の間で最適な変換を見つけようとします。これは、RANSAC と呼ばれる最小二乗法よりも賢い方法を使用します。RANSAC は、外れ値を拒否する機能を備えています。データ ポイントの少なくとも 50% + 1 が OK であれば、RANSAC はそれらを見つけるために最善を尽くし、信頼できる変換を構築します。

getPerspectiveTransform には多くの有効な理由があります。これは findHomography のベースであり、4 つのポイントしかなく、それらが正しいものであることがわかっている多くの状況で役立ちます。通常、findHomography は自動的に検出された点のセットで使用されます。多くの点を見つけることができますが、信頼性は低くなります。getPerspectiveTransform は、手動のマーキングや四角形の自動検出など、4 つのコーナーが確実にわかっている場合に適しています。

Q #2アフィン変換に相当するものはありません。アフィン変換はホモグラフィのサブセットであるため、findHomography を使用できます。

于 2012-06-28T05:58:17.413 に答える
13

@vasileが書いたすべてに同意します。いくつかの観察を追加したいだけです:

getPerspectiveTransform()とは、正しい対応であることが知られている4つまたは3 つのポイント (それぞれ) でgetAffineTransform()動作することを意図しています。実際のカメラで撮影された現実の画像では、対応する点の自動または手動のマーキングではなく、正確な対応を取得することはできません。

外れ値は常にあります。ポイントを介して曲線を当てはめたいという単純なケースを見てください (たとえば、生成方程式をノイズy1 = f(x) = 3.12x + gauss_noiseまたはy2 = g(x) = 0.1x^2 + 3.1x + gauss_noise. 二次関数はやり過ぎかもしれませんが、ほとんどの場合 (外れ値を削除した後) はそうではありません。直線をそこに当てはめたい場合は、それが正しいモデルであることを十分に確認する必要があります。そうしないと、使用できない結果が得られます。

そうは言っても、アフィン変換が正しいものであると確信している場合は、次の提案があります

  • RANSACfindHomographyが機能に組み込まれている を使用して、外れ値を取り除き、画像変換の初期推定値を取得します。
  • 3 つの正しい一致対応 (見つかったホモグラフィに適合するもの) を選択するか、1 番目の画像から 2 番目の画像に 3 点を再投影します (ホモグラフィを使用)
  • これらの 3 つの一致 (取得できる限り正しいもの) を使用します。getAffineTransform()
  • 必要に応じて、それらすべてを独自にラップしますfindAffine()-そして出来上がり!
于 2012-06-28T09:08:03.317 に答える
4

Q#2 に関して、estimateRigidTransform は getAffineTransform に相当するオーバーサンプリングされたものです。これが最初に投稿されたときに OCV にあったかどうかはわかりませんが、2.4 で利用できます。

于 2014-08-17T23:44:08.087 に答える
3

過剰決定方程式系のアフィン変換を見つけるための簡単な解決策があります。

  1. 一般に、アフィン変換は、線形方程式 Ax=B の過剰決定系の解を疑似逆行列または同様の手法を使用して見つけることに注意してください。したがって、

x = (AA t ) -1 A t B

さらに、これは、solve(A, B, X) への単純な呼び出しによってコアの openCV 機能で処理されます。

  1. opencv/modules/imgproc/src/imgwarp.cpp の Affine 変換のコードをよく理解してください。実際に行うことは次の 2 つだけです。

    を。入力を再配置して、システム Ax=B を作成します。

    b. 次に、solve(A, B, X) を呼び出します。

注: openCV コード内の関数のコメントは無視してください。これらは紛らわしく、行列内の要素の実際の順序を反映していません。[u, v]'= Affine * [x, y, 1] を解いている場合、再配置は次のようになります。

         x1 y1 1 0  0  1
         0  0  0 x1 y1 1
         x2 y2 1 0  0  1
    A =  0  0  0 x2 y2 1
         x3 y3 1 0  0  1
         0  0  0 x3 y3 1

    X = [Affine11, Affine12, Affine13, Affine21, Affine22, Affine23]’

         u1 v1
    B =  u2 v2
         u3 v3 

あなたがする必要があるのは、さらにポイントを追加することだけです。Solve(A, B, X) を過決定システムで機能させるには、DECOMP_SVD パラメータを追加します。このトピックに関するパワーポイントのスライドを見るには、このリンクを使用してください。コンピューター ビジョンのコンテキストで疑似逆数について詳しく知りたい場合は、ComputerVisionが最適な情報源です。第 15 章と付録 C を参照してください。

ポイントを追加する方法がまだ不明な場合は、以下のコードを参照してください。

// extension for n points;
cv::Mat getAffineTransformOverdetermined( const Point2f src[], const Point2f dst[], int n )
{
    Mat M(2, 3, CV_64F), X(6, 1, CV_64F, M.data); // output
    double* a = (double*)malloc(12*n*sizeof(double));
    double* b = (double*)malloc(2*n*sizeof(double));
    Mat A(2*n, 6, CV_64F, a), B(2*n, 1, CV_64F, b); // input

    for( int i = 0; i < n; i++ )
    {
        int j = i*12;   // 2 equations (in x, y) with 6 members: skip 12 elements
        int k = i*12+6; // second equation: skip extra 6 elements
        a[j] = a[k+3] = src[i].x;
        a[j+1] = a[k+4] = src[i].y;
        a[j+2] = a[k+5] = 1;
        a[j+3] = a[j+4] = a[j+5] = 0;
        a[k] = a[k+1] = a[k+2] = 0;
        b[i*2] = dst[i].x;
        b[i*2+1] = dst[i].y;
    }

    solve( A, B, X, DECOMP_SVD );
    delete a;
    delete b;
    return M;
}

// call original transform
vector<Point2f> src(3);
vector<Point2f> dst(3);
src[0] = Point2f(0.0, 0.0);src[1] = Point2f(1.0, 0.0);src[2] = Point2f(0.0, 1.0);
dst[0] = Point2f(0.0, 0.0);dst[1] = Point2f(1.0, 0.0);dst[2] = Point2f(0.0, 1.0);
Mat M = getAffineTransform(Mat(src), Mat(dst));
cout<<M<<endl;
// call new transform
src.resize(4); src[3] = Point2f(22, 2);
dst.resize(4); dst[3] = Point2f(22, 2);
Mat M2 = getAffineTransformOverdetermined(src.data(), dst.data(), src.size());
cout<<M2<<endl;
于 2015-01-16T22:55:11.010 に答える