このアーカイブは同期化されません。 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);