モザイク処理
画像にモザイクをかけてみます。モザイクをかけるには、画像の解像度を落として色を変えれば良いので、画像処理としてはそれほど難しくありません。
モザイク処理のアルゴリズム
画像の詳細を隠すモザイクは、「解像度を落とす」画像処理で実現できます。
解像度を落とすには、ビットマップのピクセルをいくつか合わせて「ブロック」を作り、そのブロックごとに色を付けてやれば良いでしょう。これで、絵が文字通りモザイク状に「粗く」なります(例えば、ブロックが4×4の大きさなら、ビットマップは16倍「粗く」なる)。各ブロックの色は、ブロック内の各ピクセルの色を平均すれば良いですね。
ビットマップの大きさをxSize×ySizeピクセル、各ブロックの大きさをs×sピクセルとすると、モザイク処理のプログラムは以下のような感じになるでしょう。このプログラムでは、ビットマップの大きさが縦横sの倍数ピクセルになっている必要があるので注意してください。
for (i=0;i<ySize/s;i++) // 各ブロックにモザイク処理
for (j=0;j<xSize/s;j++) {
rr=0;
gg=0;
bb=0;
for (k=0;k<s;k++)// ブロック内ピクセルのRGB成分合計
for (l=0;l<s;l++) {
bb+=lpBMP[(j*s+l+(i*s+k)*xSize)*3];
gg+=lpBMP[(j*s+l+(i*s+k)*xSize)*3+1];
rr+=lpBMP[(j*s+l+(i*s+k)*xSize)*3+2];
}
r=(BYTE)(rr/(s*s)); // ブロックのRGB成分計算
g=(BYTE)(gg/(s*s));
b=(BYTE)(bb/(s*s));
for (k=0;k<s;k++) // ブロック内ピクセルに色を付ける
for (l=0;l<s;l++) {
lpBMP[(j*s+l+(i*s+k)*xSize)*3]=b;
lpBMP[(j*s+l+(i*s+k)*xSize)*3+1]=g;
lpBMP[(j*s+l+(i*s+k)*xSize)*3+2]=r;
}
}
上のプログラムは、ビットマップをs×sピクセルのブロック単位に分割しています。ブロックに分割したら、ブロック内の全ピクセルのRGB成分を平均して、それをブロックの色にするわけです。この処理を行うと、ビットマップは全体に「粗く」なります。
大きなビットマップの画像処理には時間がかかるので、大きな画像をモザイク化する際はAPIやGPGPUなどを活用して「縮小画像」を作成し、それを単純に拡大する手もあります。ハード支援で処理時間を短縮するわけですね。
これだけでもsが大きければモザイクにみえるのですが、よりモザイクらしく見せる(元画像の詳細を判別させないようにする)ために、各ブロックの色に乱数を加えて絵の「原形」を崩してやりましょう。そのためには、ブロックの色を計算する部分を以下のように書き換えます。
rr=rr/(s*s)+(rand() % 96)-48; // // 各ピクセルの色を平均し-48~48の乱数加算 gg=gg/(s*s)+(rand() % 96)-48; bb=bb/(s*s)+(rand() % 96)-48; if (rr>255) rr=255; else if (rr<0) rr=0; if (gg>255) gg=255; else if (gg<0) gg=0; if (bb>255) bb=255; else if (bb<0) bb=0; r=(BYTE)rr; // ブロックの色計算 g=(BYTE)gg; b=(BYTE)bb;
乱数を加えるだけでなく近くのブロックと位置を交換する処理も加えると、クイズ番組風のモザイクになります。
モザイク処理のプログラム
今回のプログラムは、読み込んだビットマップ全体にモザイクをかける画像処理を行います。Loadボタンあるいはドラッグ&ドロップでビットマップを読み込んだら、2 Pixel、4 Pixel、8 Pixelの各ボタンでビットマップを粗くして見てください。2 Pixel だとブロックの大きさが2×2、4 Pixelでは4×4になります。
ビットマップが粗くなるのを確認したら、次はブロックの色を単に各ピクセルの色を平均して求めるのではなく乱数を加えてモザイク処理をかけてみます。これには、Rand ボタンをチェックしてからボタンをクリックしてください。
今回のプログラムで処理できるビットマップは、24ビット/縦横が8の倍数ピクセルのbmpファイルです。