ひきぷろのプログラミング日記

プログラミングの日記です。

(C#) グレースケールフィルタを実装してみた

C# でグレースケールフィルタを実装してみました。
処理内容は、次のサイトを参考にさせて頂きました。

2.9 演習問題 (2-4) グレースケール変換プログラム - PS3 Linux Information Site / Cell/B.E.のパワーを体験しよう

グレースケールフィルタクラスの実装
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

class GrayScaleFilter {
	// 引数で渡されたビットマップ画像を、グレースケールに変換します
	public static Bitmap Apply(Bitmap source) {
		// ピクセルフォーマットは今のところ 24 bit RGB で固定
		PixelFormat pixelFormat = PixelFormat.Format24bppRgb;

		// ビットマップ画像から全てのピクセルを抜き出して、バイト配列形式にする
		byte[] bytes = _GetPixels(source, pixelFormat);

		// 全てのピクセルをグレースケールに変換する
		// (ピクセルフォーマットが変わると、ここの処理内容を変更する必要がある)
		for (int i = 0; i < bytes.Length; ) {
			byte color = (byte)(
				0.29891f * bytes[i + 0] +
				0.58661f * bytes[i + 1] +
				0.11448f * bytes[i + 2]
			);
			bytes[i++] = color;
			bytes[i++] = color;
			bytes[i++] = color;
		}
		
		// 新しいビットマップ画像を作成して、ピクセルをセットする
		Bitmap bitmap = new Bitmap(source);
		_SetPixels(bitmap, pixelFormat, bytes);

		return bitmap;
	}

	// ビットマップから全てのピクセルをコピーする
	private static byte[] _GetPixels(Bitmap bitmap, PixelFormat pixelFormat) {
		Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
		BitmapData data = bitmap.LockBits(rect, ImageLockMode.ReadOnly, pixelFormat);
		byte[] bytes = new byte[data.Stride * bitmap.Height];
		Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
		bitmap.UnlockBits(data);

		return bytes;
	}

	// ビットマップへピクセルデータを適用する
	private static void _SetPixels(Bitmap bitmap, PixelFormat pixelFormat, byte[] bytes) {
		Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
		BitmapData data = bitmap.LockBits(rect, ImageLockMode.WriteOnly, pixelFormat);
		Marshal.Copy(bytes, 0, data.Scan0, bytes.Length);
		bitmap.UnlockBits(data);
	}
}
使い方
// PictureBox に設定された画像を、グレースケールに変換する場合
Bitmap bitmap = new Bitmap(pictureBox1.Image);
bitmap = GrayScaleFilter.Apply(bitmap);
pictureBox1.Image = bitmap;