このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
さて、昨日の考察を元に、減色をしてみよう。
適当なカラーテーブルが必要なので、某ペイントソフトで、
256 カラーテーブルを出力してみた。
テーブルの色配置は、今回の画像に合っているとは言えないが、
テストとして丁度いいので使ってみよう。
# 適当なカラーテーブルを準備する。
my $colors = [
00000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080,
0x008080, 0x808080, 0xc0dcc0, 0xa6caf0, 0x2a3faa, 0x2a3fff,
0x2a5f00, 0x2a5f55, 0x2a5faa, 0x2a5fff, 0x2a7f00, 0x2a7f55,
0x2a7faa, 0x2a7fff, 0x2a9f00, 0x2a9f55, 0x2a9faa, 0x2a9fff,
0x2abf00, 0x2abf55, 0x2abfaa, 0x2abfff, 0x2adf00, 0x2adf55,
0x2adfaa, 0x2adfff, 0x2aff00, 0x2aff55, 0x2affaa, 0x2affff,
0x550000, 0x550055, 0x5500aa, 0x5500ff, 0x551f00, 0x551f55,
0x551faa, 0x551fff, 0x553f00, 0x553f55, 0x553faa, 0x553fff,
0x555f00, 0x555f55, 0x555faa, 0x555fff, 0x557f00, 0x557f55,
0x557faa, 0x557fff, 0x559f00, 0x559f55, 0x559faa, 0x559fff,
0x55bf00, 0x55bf55, 0x55bfaa, 0x55bfff, 0x55df00, 0x55df55,
0x55dfaa, 0x55dfff, 0x55ff00, 0x55ff55, 0x55ffaa, 0x55ffff,
0x7f0000, 0x7f0055, 0x7f00aa, 0x7f00ff, 0x7f1f00, 0x7f1f55,
0x7f1faa, 0x7f1fff, 0x7f3f00, 0x7f3f55, 0x7f3faa, 0x7f3fff,
0x7f5f00, 0x7f5f55, 0x7f5faa, 0x7f5fff, 0x7f7f00, 0x7f7f55,
0x7f7faa, 0x7f7fff, 0x7f9f00, 0x7f9f55, 0x7f9faa, 0x7f9fff,
0x7fbf00, 0x7fbf55, 0x7fbfaa, 0x7fbfff, 0x7fdf00, 0x7fdf55,
0x7fdfaa, 0x7fdfff, 0x7fff00, 0x7fff55, 0x7fffaa, 0x7fffff,
0xaa0000, 0xaa0055, 0xaa00aa, 0xaa00ff, 0xaa1f00, 0xaa1f55,
0xaa1faa, 0xaa1fff, 0xaa3f00, 0xaa3f55, 0xaa3faa, 0xaa3fff,
0xaa5f00, 0xaa5f55, 0xaa5faa, 0xaa5fff, 0xaa7f00, 0xaa7f55,
0xaa7faa, 0xaa7fff, 0xaa9f00, 0xaa9f55, 0xaa9faa, 0xaa9fff,
0xaabf00, 0xaabf55, 0xaabfaa, 0xaabfff, 0xaadf00, 0xaadf55,
0xaadfaa, 0xaadfff, 0xaaff00, 0xaaff55, 0xaaffaa, 0xaaffff,
0xd40000, 0xd40055, 0xd400aa, 0xd400ff, 0xd41f00, 0xd41f55,
0xd41faa, 0xd41fff, 0xd43f00, 0xd43f55, 0xd43faa, 0xd43fff,
0xd45f00, 0xd45f55, 0xd45faa, 0xd45fff, 0xd47f00, 0xd47f55,
0xd47faa, 0xd47fff, 0xd49f00, 0xd49f55, 0xd49faa, 0xd49fff,
0xd4bf00, 0xd4bf55, 0xd4bfaa, 0xd4bfff, 0xd4df00, 0xd4df55,
0xd4dfaa, 0xd4dfff, 0xd4ff00, 0xd4ff55, 0xd4ffaa, 0xd4ffff,
0xff0055, 0xff00aa, 0xff1f00, 0xff1f55, 0xff1faa, 0xff1fff,
0xff3f00, 0xff3f55, 0xff3faa, 0xff3fff, 0xff5f00, 0xff5f55,
0xff5faa, 0xff5fff, 0xff7f00, 0xff7f55, 0xff7faa, 0xff7fff,
0xff9f00, 0xff9f55, 0xff9faa, 0xff9fff, 0xffbf00, 0xffbf55,
0xffbfaa, 0xffbfff, 0xffdf00, 0xffdf55, 0xffdfaa, 0xffdfff,
0xffff55, 0xffffaa, 0xccccff, 0xffccff, 0x33ffff, 0x66ffff,
0x99ffff, 0xccffff, 0x007f00, 0x007f55, 0x007faa, 0x007fff,
0x009f00, 0x009f55, 0x009faa, 0x009fff, 0x00bf00, 0x00bf55,
0x00bfaa, 0x00bfff, 0x00df00, 0x00df55, 0x00dfaa, 0x00dfff,
0x00ff55, 0x00ffaa, 0x2a0000, 0x2a0055, 0x2a00aa, 0x2a00ff,
0x2a1f00, 0x2a1f55, 0x2a1faa, 0x2a1fff, 0x2a3f00, 0x2a3f55,
0xfffbf0, 0xa0a0a4, 0x808080, 0xff0000, 0x00ff00, 0xffff00,
0x0000ff, 0xff00ff, 0x00ffff, 0xffffff,
];
# 近さを求める。大小の比較だけにしか使わないので、
# 距離の計算の平方根処理を行わない。整数演算で高速化できる。
sub get_nearness ($$) {
my ($pp, $qq) = @_;
($pp->[0] - $qq->[0]) ** 2
+ ($pp->[1] - $qq->[1]) ** 2
+ ($pp->[2] - $qq->[2]) ** 2;
}
# BMP 読み込み。
my $data = read_bmp;
# 32 ビット整数値から RGB 配列に分解しておく。
foreach my $line (@$data) {
foreach my $pixel (@$line) {
$pixel = [ unpack_rgb($pixel) ];
}
}
# カラーテーブルも RGB 配列に分解しておく。
my $colors_rgb = [ map { [ unpack_rgb($_) ] } @$colors ];
# 高さと幅を取得。
my $height = @$data;
my $width = @{$data->[0]};
# 行ごとの処理。
for (my $yy = 0; $yy < $height; ++$yy) {
# ピクセルごとの処理。
for (my $xx = 0; $xx < $width; ++$xx) {
# ピクセルの RGB 値配列を得る。
my $rgb = $data->[$yy][$xx];
# 最も近い色を探す。
# まずは 0 番と仮定しておき、
my $index = 0;
my $best = get_nearness($rgb, $colors_rgb->[0]);
# 最適なものを検索する。
foreach (1 .. $#$colors) {
my $nn = get_nearness($rgb, $colors_rgb->[$_]);
if ($nn < $best) {
$best = $nn;
$index = $_;
}
}
# 誤差分散処理。
foreach (0 .. 2) {
# 本来の値との不足分を求め、
my $diff = $rgb->[$_] - $colors_rgb->[$index][$_];
# 右、左下、下、右下のピクセルに責任転嫁する。
# Floyd & Steinberg による誤差配列。
# - - -
# - x 7
# 3 5 1
$data->[$yy][$xx + 1][$_] += $diff * 7 / 16
if $xx + 1 < $width;
$data->[$yy + 1][$xx - 1][$_] += $diff * 3 / 16
if $yy + 1 < $height and $xx - 1 >= 0;
$data->[$yy + 1][$xx][$_] += $diff * 5 / 16
if $yy + 1 < $height;
$data->[$yy + 1][$xx + 1][$_] += $diff * 1 / 16
if $yy + 1 < $height and $xx + 1 < $width;
}
# カラーテーブルの番号に置き換える。
$data->[$yy][$xx] = $index;
}
}
# 8 ビットの BMP を書き出す。
write_bmp($data, 8, $colors);
さすがに計算量が多いため、 Perl では厳しくなってきた。
Web セーフカラーのときと比較して写真を見ると、
地面は悪くなっているが、台座の部分は良くなっている。
つまり、パレットによる差が出ているということだ。