12

2 つの画像バッファー (サイズが幅 * 高さの int の配列で、各要素が色の値であると仮定します) で、四角形で定義された領域を一方の画像バッファーから他方の (常に正方形の) 画像バッファーにマップするにはどうすればよいですか? これが「射影変換」と呼ばれるものであることがわかりました。

また、「私のためにすべての作業を行う魔法の関数 X」に依存することなく、任意の言語に合理的に適用できるように、これを行う一般的な (言語固有またはライブラリ固有ではない) 方法を探しています。

例: カメラからビデオをキャプチャする処理ライブラリ (processing.org) を使用して Java で短いプログラムを作成しました。最初の「調整」ステップで、キャプチャされたビデオがウィンドウに直接出力されます。次に、ユーザーは 4 つのポイントをクリックして、変換されるビデオの領域を定義し、その後のプログラムの操作中に正方形のウィンドウにマッピングします。カメラの出力で斜めに見えるドアの角を定義する 4 つの点をユーザーがクリックした場合、この変換により、後続のビデオでドアの変換された画像がウィンドウ全体にマッピングされますが、若干歪んでいます。

4

6 に答える 6

8

線形代数を使用することは、すべての幾何学よりもはるかに簡単です! さらに、サイン、コサインなどを使用する必要がないため、各数値を有理分数として格納し、必要に応じて正確な数値結果を得ることができます。

必要なのは、古い (x,y) 座標から新しい (x',y') 座標へのマッピングです。マトリックスでそれを行うことができます。古い座標の P 倍が新しい座標と等しくなるように、2 行 4 列の射影行列 P を見つける必要があります。線を線にマッピングしていると仮定します (たとえば、直線を放物線にマッピングするのではありません)。投影 (平行線は平行にならない) と平行移動 (スライド) があるため、(xy) と (1) の係数も必要です。行列として描画:

          [x  ]
[a b c d]*[y  ] = [x']
[e f g h] [x*y]   [y']
          [1  ]

a から h までを知る必要があるため、次の方程式を解きます。

a*x_0 + b*y_0 + c*x_0*y_0 + d = i_0
a*x_1 + b*y_1 + c*x_1*y_1 + d = i_1
a*x_2 + b*y_2 + c*x_2*y_2 + d = i_2
a*x_3 + b*y_3 + c*x_3*y_3 + d = i_3

e*x_0 + f*y_0 + g*x_0*y_0 + h = j_0
e*x_1 + f*y_1 + g*x_1*y_1 + h = j_1
e*x_2 + f*y_2 + g*x_2*y_2 + h = j_2
e*x_3 + f*y_3 + g*x_3*y_3 + h = j_3

ここでも、線形代数を使用できます。

[x_0 y_0 x_0*y_0 1]   [a e]   [i_0 j_0]
[x_1 y_1 x_1*y_1 1] * [b f] = [i_1 j_1]
[x_2 y_2 x_2*y_2 1]   [c g]   [i_2 j_2]
[x_3 y_3 x_3*y_3 1]   [d h]   [i_3 j_3]

x_n、y_n、i_n、j_n のコーナーを差し込みます。(たとえば、ユーザーのクリックからポイントを選択する場合は、エラーを減らすためにコーナーが離れているため、コーナーが最適に機能します。) 4x4 行列の逆数を取り、方程式の右辺を掛けます。その行列の転置は P です。逆行列を計算し、オンラインで乗算する関数を見つけることができるはずです。

おそらくバグがある場所:

  • 計算するときは、ゼロ除算を忘れずにチェックしてください。これは、マトリックスが可逆でないことを示しています。これは、1 つの (x,y) 座標を 2 つの異なる点にマッピングしようとすると発生する可能性があります。
  • 独自の行列演算を作成する場合、通常、行列は行、列 (垂直、水平) で指定され、画面のグラフィックは x、y (水平、垂直) であることに注意してください。初めて何かを間違えることは間違いありません。
于 2010-03-31T09:29:36.447 に答える
5

編集

以下の角度比の不変性の仮定は正しくありません。代わりに、射影変換は交差比と発生率を保持します。解決策は次のとおりです。

  1. 線分 AD と CP によって定義される線の交点で点 C' を見つけます。
  2. 線分 AD と BP によって定義される線の交点で点 B' を見つけます。
  3. B'DAC' の交差比、つまり r = (BA' * DC') / (DA * B'C') を決定します。
  4. 射影された直線 F'HEG' を作成します。これらのポイントの交差比は r に等しくなります。つまり、r = (F'E * HG') / (HE * F'G') です。
  5. F'F と G'G は射影された点 Q で交差するため、交差比を等しくし、正方形の一辺の長さを知ることで、算術体操で Q の位置を決定できます。

うーん....これを刺してみます。このソリューションは、角度の比率が変換で保持されるという前提に依存しています。ガイダンスについては画像を参照してください (画質が悪くて申し訳ありません...本当に遅いです)。このアルゴリズムは、四角形の点から正方形の点へのマッピングのみを提供します。同じ四角形の点にマッピングされている複数の四角形の点を処理する実装をまだ実装する必要があります。

ABCD を四角形とし、A を左上の頂点、B を右上の頂点、C を右下の頂点、D を左下の頂点とします。ペア (xA, yA) は、頂点 A の x 座標と y 座標を表します。この四角形の点を、辺の長さが m に等しい正方形 EFGH にマッピングします。

代替テキスト

長さ AD、CD、AC、BD、および BC を計算します。

AD = sqrt((xA-xD)^2 + (yA-yD)^2)
CD = sqrt((xC-xD)^2 + (yC-yD)^2)
AC = sqrt((xA-xC)^2 + (yA-yC)^2)
BD = sqrt((xB-xD)^2 + (yB-yD)^2)
BC = sqrt((xB-xC)^2 + (yB-yC)^2)

thetaD を頂点 D での角度、thetaC を頂点 C での角度とします。コサインの法則を使用してこれらの角度を計算します。

thetaD = arccos((AD^2 + CD^2 - AC^2) / (2*AD*CD))
thetaC = arccos((BC^2 + CD^2 - BD^2) / (2*BC*CD))

四角形の各点 P を正方形の点 Q にマッピングします。四角形の各点 P について、次の操作を行います。

  • 距離 DP を求める:

    DP = sqrt((xP-xD)^2 + (yP-yD)^2)
    
  • 距離 CP を求める:

    CP = sqrt((xP-xC)^2 + (yP-yC)^2)
    
  • CD と DP の間の角度 thetaP1 を見つけます。

    thetaP1 = arccos((DP^2 + CD^2 - CP^2) / (2*DP*CD))
    
  • CD と CP の間の角度 thetaP2 を見つけます。

    thetaP2 = arccos((CP^2 + CD^2 - DP^2) / (2*CP*CD))
    
  • thetaP1 と thetaD の比率は、thetaQ1 と 90 の比率である必要があります。したがって、thetaQ1 を計算します。

    thetaQ1 = thetaP1 * 90 / thetaD
    
  • 同様に、thetaQ2 を計算します。

    thetaQ2 = thetaP2 * 90 / thetaC
    
  • 距離 HQ を求める:

    HQ = m * sin(thetaQ2) / sin(180-thetaQ1-thetaQ2)
    
  • 最後に、EFGH の左下隅に対する Q の x および y 位置は次のとおりです。

    x = HQ * cos(thetaQ1)
    y = HQ * sin(thetaQ1)
    

正方形の各ポイントにマップされたカラー値の数を追跡して、それらの各ポイントの平均カラーを計算できるようにする必要があります。

于 2008-10-04T10:59:46.327 に答える
4

あなたが求めているのは平面ホモグラフィだと思います。これらの講義ノートを見てください。

http://www.cs.utoronto.ca/~strider/vis-notes/tutHomography04.pdf

最後までスクロールすると、説明している内容の例が表示されます。Intel OpenCV ライブラリには、まさにこれを行う関数があると思います。

于 2008-10-04T10:02:45.210 に答える
2

この変換の見栄えが良くなければならない場合(ペイントでサイズを変更した場合のビットマップの見た目とは対照的に)、宛先ピクセルをソースピクセルにマップする数式を作成することはできません。デスティネーションバッファの値は、近くのソースピクセルの複雑な平均に基づいている必要があります。そうでない場合、結果は高度にピクセル化されます。

したがって、複雑なコーディングに取り掛かる場合を除いて、smaclとIanが提案しているように、他の誰かの魔法の関数を使用してください。

于 2008-10-04T16:28:46.333 に答える
2

ビットマップの射影変換のソースを含むCodeProjectの C++ プロジェクトがあります。数学はウィキペディアのこちらにあります。私の知る限り、射影変換は任意の四角形を別の四角形にマッピングしませんが、三角形の場合はマッピングします。傾斜変換を検索することもできます。

于 2008-10-04T08:35:54.433 に答える
0

原則としてそれを行う方法は次のとおりです。

  • 変換ベクトルを介して A の原点を B の原点にマッピングしtます。
  • A (1,0) と (0,1) の単位ベクトルを取り、それらが B の単位ベクトルにどのようにマッピングされるかを計算します。
  • これにより、変換行列Mが得られるため、 A のすべてのベクトルがM +aにマップされます。 at
  • 行列を反転し、変換ベクトルを無効にするため、B のすべてのベクトルに対してb逆マッピングb-> M -1 ( b- t)が得られます。
  • この変換が完了したら、B のターゲット領域の各点について、A で対応する点を見つけてコピーします。

このマッピングの利点は、必要なポイントのみを計算することです。つまり、ソースポイントではなく、ターゲットポイントをループします。これは、数年前の「デモコーディング」シーンで広く使用されていた手法でした。

于 2008-10-04T10:45:07.417 に答える