ここに示すような画像にスキューを実行しようとしています
(ソース:microsoft.com)
。
画像を表すピクセルの配列があり、それらをどう処理するかわからない。
これを行うためのはるかに優れた方法は、逆マッピングによるものです。
基本的に、画像を「ワープ」したいですよね?つまり、ソース画像のすべてのピクセルが事前定義されたポイントに移動します。事前定義は、画像の回転、拡大縮小、変換、せん断などの方法を示す変換行列であり、基本的に(x,y)
画像上で何らかの座標を取り、次のように言います。 「わかりました。このピクセルの新しい位置はです(f(x),g(y))
。
それは本質的に「ワーピング」が行うことです。
次に、画像を10倍のサイズに拡大縮小することを考えてみましょう。つまり、の(1,1)
ピクセルは-のピクセルになり(10,10)
、次のピクセルは新しい画像のピクセルになります。ただし、これを続行すると、ピクセルの値がなくなります。これは、元の画像で定義されておらず、新しい画像に多数の穴があるためです。4つを使用してその値を補間する必要があります。新しい画像の周囲のピクセル、つまり-これは双一次内挿と呼ばれます。(1,2)
(10,20)
(13,13)
(1.3,1.3)
(10,10) , (10,20), (20,10), (200,2)
しかし、別の問題があります。変換が単純なスケーリングではなく、アフィンであったと仮定します(投稿したサンプル画像のように)-その後、(1,1)
次のよう(2.34,4.21)
になり、出力画像でそれらを丸める必要が(2,4)
あります。 d穴を埋めるために、新しい画像に対して双一次内挿を行う必要があります。または、より複雑な内挿を行う必要があります。
現在、補間から抜け出す方法はありませんが、双一次補間を1回だけ実行することで回避できます。どのように?シンプルな逆マッピング。
新しい画像に移動するソース画像として見るのではなく、新しい画像のデータがソース画像のどこから来るかを考えてください。したがって、(1,1)
新しい画像では、たとえば、ソース画像の逆マッピングから(3.4, 2.1)
取得され、ソース画像で双一次補間を実行して、対応する値を計算します。
では、アフィン変換の変換行列をどのように定義しますか?このWebサイトでは、回転、せん断などのさまざまな変換行列を合成する方法を説明しています。
最終的な行列は、各行列を順番に合成し、それを反転して逆マッピングを取得することで実現できます。これを使用して、ソース画像内のピクセルの位置を計算し、補間します。
車輪の再発明をしたくない場合は、OpenCVライブラリをチェックしてください。パースペクティブ変換を含む多くの便利な画像処理機能を実装しています。このタスクを非常に簡単に実行するために使用したcvWarpPerspectiveを確認してください。
KennyTMがコメントしているように、必要なのは、すべてのピクセルに行列Mを乗算し、その結果を平行移動ベクトルVに加算することによって得られる線形マッピングであるアフィン変換です。簡単な数学です
end_pixel_position = M*start_pixel_position + V
ここで、Mは回転やスケーリングなどの単純な変換の合成であり、Vはすべてのピクセルに固定係数を追加することによって画像のすべてのポイントを変換するベクトルです。
たとえば、画像を回転させたい場合は、回転行列を次のように定義できます。
| cos(a) -sin(a) |
M = | |
| sin(a) cos(a) |
a
画像を回転させたい角度はどこですか。
スケーリングでは、次の形式の行列が使用されます。
| s1 0 |
M = | |
| 0 s2 |
ここでs1
、とs2
は両方の軸のスケーリング係数です。
翻訳のためにあなたはただベクトルVを持っています:
| t1 |
V = | |
| t2 |
t1
とt2
をピクセル座標に追加します。
次に、行列を1つの変換に結合します。たとえば、スケーリング、回転、平行移動のいずれかがある場合は、次のようになります。
| x2 | | x1 |
| | = M1 * M2 * | | + T
| y2 | | y1 |
どこ:
x1
とy1
は、変換を適用する前のピクセル座標です。x2
y2
変換後のピクセルであり、M1
とM2
は、スケーリングと回転に使用される行列です(覚えておいてください:行列の構成は可換ではありません!通常M1 * M2 * Vect != M2 * M1 * Vect
)、T
は、すべてのピクセルを平行移動するために使用する平行移動ベクトルです。