C#プログラム画像処理画像処理画像処理アルゴリズム画像処理プログラミング

画像の拡大

例えば、下図のように2x2画素の画像を4x4の画像に拡大する場合、アフィン変換を使えばいいんでしょ!と、安易に考えていると、思わぬ落とし穴があったりもします。

画像の拡大

大事なポイントとして、

●画像の座標の原点は左上の画素の中心が原点(0.0、0.0)となる。(例外もあります)

画像の拡大

●アフィン変換の拡大縮小は原点を基準として拡大縮小される。

 

となります。

これを気にせず、ただ、アフィン変換で画像を2倍に拡大すると、左上の画素の中心を基点に画像が拡大されます。

画像の拡大

これで、一見良さそうにも感じるのですが、拡大後の画像において、画素の中心が原点であることから、4x4画素の領域は下図の四角で示した領域であり、画像全体が左上に0.5画素ズレた状態になっていまいます。

 

画像の拡大

 

アフィン変換で画像を拡大する時の変換前と変換後の状態は、以下のようになるのが正解です。

画像の拡大

 

この変換をアフィン変換で実現するには以下のように行います。

 

変換前の状態

画像の拡大

 

①画像全体を右下に(+0.5,+0.5)画素移動
画像の拡大 $$\begin{pmatrix} 1 & 0 & 0.5 \\ 0 & 1 & 0.5 \\ 0 & 0 & 1 \end{pmatrix}$$
 

②画像を2倍に拡大

画像の拡大 $$\begin{pmatrix} 2 & 0 & 0 \\ 0 & 2 & 0 \\ 0 & 0 & 1 \end{pmatrix}$$
 

③画像全体を左上に(-0.5,-0.5)画素移動

画像の拡大 $$\begin{pmatrix} 1 & 0 & -0.5 \\ 0 & 1 & -0.5 \\ 0 & 0 & 1 \end{pmatrix}$$

 

となります。

この一連の変換をアフィン変換行列であらわすと

$$\begin{pmatrix} { x }^{ ‘ } \\ { y }^{ ‘ } \\ 1 \end{pmatrix}=\begin{pmatrix} 1 & 0 & -0.5 \\ 0 & 1 & -0.5 \\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} 2 & 0 & 0 \\ 0 & 2 & 0 \\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} 1 & 0 & 0.5 \\ 0 & 1 & 0.5 \\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} x \\ y \\ 1 \end{pmatrix}\\ \\ $$

$$\begin{pmatrix} { x }^{ ‘ } \\ { y }^{ ‘ } \\ 1 \end{pmatrix}=\begin{pmatrix} 2 & 0 & 0.5 \\ 0 & 2 & 0.5 \\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} x \\ y \\ 1 \end{pmatrix}\\ \\ $$

 

となり、単に拡大のアフィン変換行列だけを掛ければOKでは無いことが分かります。

 

ちなみに、C#で2x2画素の画像をPictureBoxのSizeModeプロパティをZoomにして、ImageプロパティにBitmapを設定すると、このようになります。

画像の拡大

 

なんとなく、画像が左上にズレているようで、なんか怪しい!!

 

【関連記事】

【C#】画像の座標系
画像を描画するにはDrawImageメソッドを用いますが、DrawImageメソッドはいくつものオバーロードが定義されていますが、画像の拡大縮小を考慮すると、個人的には以下の定義をよく用います。 public void DrawImage(...
アフィン変換(平行移動、拡大縮小、回転、スキュー行列)
画像の拡大縮小、回転、平行移動などを行列を使って座標を変換する事をアフィン変換と呼びます。 X,Y座標の二次元データをアフィン変換するには、変換前の座標を(x, y)、変換後の座標を(x',y')とすると回転や拡大縮小用の2行2列の行列と、...
画素の補間(Nearest neighbor,Bilinear,Bicubic)の計算方法
画像を拡大や回転する場合など、画像の画素と画素の間の輝度値を参照する必要が出てきますが、その参照方法を紹介します。 この画素を画素の間を参照する事を一般に補間や内挿(Interpolation)と言います。 最近傍補間(ニアレストネイバー ...
画像の回転
画像を回転する場合、任意点周りの回転移動でも紹介したように回転行列を使って、例えば、画像の中心周りに画像を回転させると、下図のように回転後の画像が虫食い状態になってしまいます。 → 回転前の画像 回転後の画像 こうならないようにするためには...

 

画像処理のためのC#へ戻る

コメント

  1. poka より:

    間違っていると思います。
    拡大で、原点(0, 0) が (0.5, 0.5) になるはずがありません。
    原点は不動点であるはずです。これでは、座標計算ができません。

    そもそも、画素を「マス目」で考えていることが、間違いのもとだと思います。
    画素は「点」で考えるべきだと思います。

    • dummy_index より:

      横レス失礼します。
      記事は『原点がずれる』とも『マス目の左上角を座標とする』とも『基本演算はこうあるべきである』とも言っていないのですが。
      ・「スケーリング200%ならにじまない」と言っている人がナイーブに想定しているのは『2×2の4画素が1画素として使われる』状況で、記事はこういうニーズを教科書どおりに扱ったらどうなるかを示したものです。
      ・この手順によれば、(0,0)-(1,1)の画像の重心(0.5,0.5)を(0,0)-(3,3)の領域の重心(1.5,1.5)に写すことになるので、その意味で自然な処理であると言えます。この言い方ならマス目が関係ないのは分かりますね?

    • akira より:

      dummy_indexさん。
      補足頂きありがとうございました。

タイトルとURLをコピーしました