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

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

(C#) ガウシアンフィルタを実装してみた

using System;
using System.Drawing;

class GaussianBlurFilter {
	// 引数で渡されたビットマップ画像にガウシアンフィルタを適用します
	public static Bitmap Apply(Bitmap source, int size = 3) {
		// ビットマップ画像から全てのピクセルを抜き出す
		PixelManipulator s = PixelManipulator.LoadBitmap(source);
		PixelManipulator d = s.Clone();

		// 範囲チェック
		if (size < 3) {
			size = 3;
		}
		if (size > 15) {
			size = 15;
		}
		size--;
		size /= 2;

		// カーネルを作成する
		float[] kernel = _CreateGaussianKernel(size);

		// 全てのピクセルを巡回する
		s.EachPixel((x, y) => {
			byte r = _GaussianBlur(kernel, s.RangeR(x, y, size));
			byte g = _GaussianBlur(kernel, s.RangeG(x, y, size));
			byte b = _GaussianBlur(kernel, s.RangeB(x, y, size));
			d.SetPixel(x, y, r, g, b);
		});

		// 新しいビットマップ画像を作成して、ピクセルをセットする
		return d.CreateBitmap();
	}

	// カーネルを作成する
	private static float[] _CreateGaussianKernel(int size) {
		float sigma = 0.215f * ((size - 1f) * 0.5f - 1f) + 0.81f;
		float[] kernel = new float[(size * 2 + 1) * (size * 2 + 1)];
		float total = 0;
		int count = 0;
		for (int y = -size; y <= size; y++) {
			for (int x = -size; x <= size; x++) {
				kernel[count] = _GaussianF(x, y, sigma);
				total += kernel[count];
				count++;
			}
		}
		return kernel;
	}

	// ガウス分布のメソッド
	private static float _GaussianF(float x, float y, float sigma) {
		float pi = (float)Math.PI;
		float sigma2 = sigma * sigma;
		return (1f / (2f * pi * sigma2)) * (float)Math.Exp(-(x * x + y * y) / (2f * sigma2));
	}

	// ガウシアンフィルタを適用する
	private static byte _GaussianBlur(float[] kernel, byte[,] pixels) {
		float color = 0;
		int size = pixels.GetLength(0);
		for (int y = 0; y < size; y++) {
			for (int x = 0; x < size; x++) {
				float c = pixels[x, y];
				c *= kernel[x + y * size];
				color += c;
			}
		}
		return (byte)color;
	}
}

PixelManipulator クラスは、前の記事で作成しました。
次のリンク先を確認してみてください。

hikipuro.hatenadiary.jp

メインの部分は移動平均フィルタとほぼ同じような処理になっています。ガウシアンフィルタの処理では普通にピクセルの平均値を出すのではなく、真ん中のピクセルが一番重みがあって、遠くに行くにしたがって適用度合いが薄くなるようなコードになっています。

ピクセルの適用度合いのリストは _CreateGaussianKernel() で作成しています。

使い方
// PictureBox に設定された画像へフィルタを適用する場合
Bitmap bitmap = new Bitmap(pictureBox1.Image);
bitmap = GaussianBlurFilter.Apply(bitmap);
pictureBox1.Image = bitmap;