2006 年 2 月 28 日 23 時 41 分

近傍法による画像の拡大・改


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


[写真] [写真] [写真]


昨日の考察を踏まえて、ピクセルを領域として考えてみよう。

領域と捉えた場合は、ピクセルは正方形の範囲となり、
左上のピクセルは、(0, 0) - (1, 1) の座標で表現される。

以前の場合と異なり、ピクセルの座標が点で定まらないので、
これに直接近傍法を適用するのは難しい。
そこで、範囲から代表となる点を選ぶことにしよう。

正方形の範囲から、それを代表する点を考える場合、
正方形の中央の点を使うのが自然な考え方だ。
そうすると、左上のピクセルの代表的な座標は、
(0, 0) - (1, 1) の中心である、(0.5, 0.5) と決められる。

実装を基準に考えてみよう。

プログラミング上では、画像を配列として扱うため、
先頭の要素番号(添字)は 0 となる。
つまり「要素番号」に 0.5 を足せば「座標」が求まるのだ。

その上で、従来のように座標変換を行うと、
元の画像上での「座標」が求まる。
最終的に、その「座標」を「要素番号」に戻してやれば、
最も近くにある元のピクセルが求まることになる。

ではやってみよう。

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

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

# 新しい画像の幅と高さを決める。
my $dcx = 105;
my $dcy = 90;

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

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

        no integer;

        # 新しい座標に対応する元の座標を求める。

        # 要素番号に 0.5 を足せば座標が求まる。
        #
        # my $px = $dx + 0.5;
        # my $py = $dy + 0.5;
        #
        # ピクセルを領域と考えた場合は、
        # サイズに合った自然な変換式となる。
        #
        # my $sx = $px / $dcx * $scx;
        # my $sy = $py / $dcy * $scy;
        #
        # 座標から 0.5 を引くと要素番号が求まる。
        #
        # $sx -= 0.5;
        # $sy -= 0.5;
        #
        # 要素番号を四捨五入して最も近い位置を得る。
        #
        # $sx = int($sx + 0.5);
        # $sy = int($sy + 0.5);
        #

        # 上の式をまとめると以下のようになる。
        # 近傍検索のための四捨五入と、
        # 座標⇔添字変換で 0.5 の加算と減算が相殺され、
        # 意外に単純な計算式となるのだ。

        my $sx = int(($dx + 0.5) / $dcx * $scx);
        my $sy = int(($dy + 0.5) / $dcy * $scy);

        $dest->[$dy][$dx] = $src->[$sy][$sx];
    }
}

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

どうだろう、ピクセルの重み的には自然な拡大となってるはずだ。

参考に、アイコンの拡大も乗せておくが、
以前の近傍法と比較して、周辺の枠が
心なし太くなった気がするかもしれない。



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