画像の回転

Processingって、ちょこっと画像処理の実験とかするのにちょうどよさげ。
ためしに簡単な画像の回転をやってみた。

回転行列

画像の回転の基本は高校の数学で習う回転行列。
え、今は高校で行列習わないの??? それはアカンやろ!

\left (\begin{array}{c}
    x' \\
    y' \\
\end{array} \right)
=
\left( \begin{array}{cc}
    \cos \theta & -\sin \theta \\
    \sin \theta & \cos \theta \\
\end{array} \right)

\left( \begin{array}{c}
    x \\
    y \\
\end{array} \right)

画像を回転するスケッチ(その1)

回転行列を使って画像を回転するスケッチ

PImage img;         // 画像
float x0,y0;        // 画像の中心座標
float X0,Y0;        // 画面の中心座標

void setup()
{
    size(512, 512);
    
    img = loadImage("Lena.png");
    img.loadPixels();
    
    x0 = img.width / 2;
    y0 = img.height / 2;
    X0 = width / 2;
    Y0 = height / 2;
}

void draw()
{
    background(0);
    
    // マウス座標を角度に
    float th = atan2(mouseY-Y0, mouseX-X0);
    
    // 画像を回転
    for(int y=0; y<img.height-1; y++)
    {
        for(int x=0; x<img.width-1; x++)
        {
            // 回転の計算 (x,y) → (X,Y)
            int X = int((x-x0)*cos(th) - (y-y0)*sin(th) + X0);
            int Y = int((x-x0)*sin(th) + (y-y0)*cos(th) + Y0);
            
            set(X, Y, img.pixels[y*img.width+x]);
        }
    }
}
実行結果

f:id:licheng:20181102191538p:plain
たしかに回転はできたけど、画像に細かい穴が開いて透け透けになってしまった。格子点を斜めに回転して格子点に写すとどうしてもこうなってしまう。レナたんが透け透け。これはアカン。

画像を回転するスケッチ(その2)

そこで発想を逆転して、回転後の座標(X,Y)から回転前の座標(x,y)を逆算することにする。

PImage img;         // 画像
float x0,y0;        // 画像の中心座標
float X0,Y0;        // 画面の中心座標

void setup()
{
    size(512, 512);
    
    img = loadImage("Lena.png");
    img.loadPixels();
    
    x0 = img.width / 2;
    y0 = img.height / 2;
    X0 = width / 2;
    Y0 = height / 2;
}

void draw()
{
    background(0);
    
    // マウス座標を角度に
    float th = atan2(mouseY-Y0, mouseX-X0);
    
    // 画像を回転
    for(int Y=0; Y<height-1; Y++)
    {
        for(int X=0; X<width-1; X++)
        {
            // 回転の計算の逆算(=逆回転) (X,Y) → (x,y)
            int x = int((X-X0)*cos(-th) - (Y-Y0)*sin(-th) + x0);
            int y = int((X-X0)*sin(-th) + (Y-Y0)*cos(-th) + y0);
            
            // 範囲チェック
            if((x>=0) && (x<img.width) && (y>=0) && (y<img.height))
            {
                set(X, Y, img.pixels[y*img.width+x]);
            }
        }
    }
}
実行結果

f:id:licheng:20181102191554p:plain
穴がなくなった。成功! ただし、ちょっとギザギザしている。実用的な画像回転処理ではフィルタを施して画像を滑らかにする必要がある。まあ、今回はここまで。

アニメ調のレナたんについて

サンプル画像に使ったアニメ調のレナたんは、下記サイトで画像処理用テスト素材として公開されているものを使わせていただきました。
(今回アニメ調の画像を使ったのは、穴やギザギザが分かりやすいからです。)
tyosm.blogspot.com