web-dev-qa-db-ja.com

findHomography、getPerspectiveTransform、およびgetAffineTransform

この質問はOpenCV関数findHomographygetPerspectiveTransformgetAffineTransformに関するものです

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

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

ベスト、

28
tetradeca7tope

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

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

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

31
Sam

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

getPerspectiveTransform()およびgetAffineTransform()は、4または3で機能することを意図していますポイント(それぞれ)、つまりが正しい対応であることがわかっている。実際のカメラで撮影された実際の画像では、対応するポイントの自動または手動のマーキングではなく、正確な対応をnever取得できます。

常に異常値があります。 ポイントを介して曲線をフィットしたい場合の単純なケースを見てください(たとえば、ノイズy1 = f(x) = 3.12x + gauss_noiseまたはy2 = g(x) = 0.1x^2 + 3.1x + gauss_noise):優れた線形関数よりも、どちらの場合でも点を推定するための優れた2次関数を見つける方がはるかに簡単です。二次式はやり過ぎかもしれませんが、ほとんどの場合はそうではありません(外れ値を削除した後)。直線を当てはめたい場合は、それが正しいモデルであると確信できます。そうでない場合、使用できない結果が得られます。

とはいえ、アフィン変換が正しいものであると確信している場合、ここに提案があります。

  • [〜#〜] ransac [〜#〜]が機能に組み込まれているfindHomographyを使用して、外れ値と画像変換の初期推定値を取得
  • 3つの正しい一致/対応(選択されたホモグラフィに適合する)を選択するか、3番目の点を最初の画像から2番目の画像に再投影します(ホモグラフィを使用)。
  • getAffineTransform()でこれらの3つの一致(できる限り正確に一致する)を使用します
  • 必要に応じて、これらすべてを独自のfindAffine()でラップしてください。
10
penelope

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

4
Ben

過剰決定方程式のシステムのアフィン変換を見つける簡単なソリューションがあります。

  1. 一般に、アフィン変換では、疑似逆または類似の手法を使用して、線形方程式Ax = Bの過剰決定システムの解を見つけます。

x =(A At-1t B

さらに、これは、solve(A、B、X)を呼び出すだけで、openCVのコア機能で処理されます。

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

    a。入力を再配置してシステム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パラメーターを追加します。トピックに関するPowerPointスライドを表示するには、この link を使用します。コンピュータビジョンのコンテキストで疑似逆行列について詳しく知りたい場合、最適なソースは次のとおりです。 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;
2
Vlad

getAffineTransform:アフィン変換は、平行移動、スケール、シアー、回転の組み合わせです https://www.mathworks.com/discovery/affine-transformation.htmlhttps://www.tutorialspoint .com/computer_graphics/2d_transformation.htm

getPerspectiveTransform:透視変換はプロジェクトマッピングです ここに画像の説明を入力してください

0
silva