2006 年 3 月 6 日 23 時 57 分

任意角度の回転


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


[写真] [写真]


今日は、任意角度の回転を考える。

回転後と回転前のピクセルが、
どのような位置関係か考えてみよう。
細かい説明をするとややこしいので図を載せておく。
図では、点を回転させるのでなく、座標系を回転させている。

計算には、三角関数のサインやコサインが必要となるが、
計算に必要な関数は言語側に用意されているので、
計算式だけ丸覚えしておけば、特に考える必要はない。

注意となる点は、ほとんどの言語系では、
角度を表すのにラジアンという単位をつかう。
通常、角度といえば「度」と思い浮かべると思うので、
コードで変換しないといけない。
変換は簡単で、ラジアン = 度 * 円周率 / 180 だ。

円周率は、意外にも定数では定義されていないが、
atan2(0, -1) で求めることができる。
(式の意味が気になる方は調べてください)

では、近傍法での補間を入れて実装してみよう。

# floor 関数。
use POSIX;

# 小数演算を有効にする。
no integer;

# 回転角を定義。今回はマイナス 15 度。
my $angle = -15 * (atan2(0, -1)) / 180;

# BMP 読み込み。
my $src = read_bmp;

# 画像の幅と高さを取得。
my $scx = @{$src->[0]};
my $scy = @$src;

# 新しい画像の幅と高さを求める。
my $dcx = $scx;
my $dcy = $scy;

# サインとコサインを求めておく。
my $sin = sin($angle);
my $cos = cos($angle);

# 新しい画像のデータを準備する。
my $dest = [ map { [ (0) x $dcx ] } 1 .. $dcy ];

for (my $dy = 0; $dy < $dcy; ++$dy) {
    for (my $dx = 0; $dx < $dcx; ++$dx) {

        no integer;

        # 新しい要素番号に対応する元の要素番号を求める。
        my $sx = $cos * $dx + $sin * $dy;
        my $sy = $cos * $dy - $sin * $dx;

        # 近傍法なので、最も近い要素位置を求める。
        $sx = floor($sx);
        $sy = floor($sy);

        # 範囲内なら転送する。
        if ($sx >= 0 and $sx < $scx and $sy >= 0 and $sy < $scy) {
            $dest->[$dy][$dx] = $src->[$sy][$sx];
        }

    }
}

# BMP を書き出す。
write_bmp($dest, 24);



Copyright (c) 1994-2007 Project Loafer. All rights reserved.