読者です 読者をやめる 読者になる 読者になる

人工知能作っちゃう?

画像処理を中心に人工知能を作っていきます。

ガウシアンフィルタ

ガウシアンフィルタとは簡単に言えばぼかす技術です。画像中のノイズを除去するために用いられます。
f:id:manato2cc:20161015225405p:plain
ガウシアンフィルタを通していないニ値化トランプ
f:id:manato2cc:20161015225359p:plain
ガウシアンフィルタを通したにちとら

上記からわかるようにガウシアンフィルタを通すとノイズを除去することができます。ガウシアンフィルタを通さないとノイズが残り満足な輪郭追跡などができません。

概要

まず式をごらんください。
f:id:manato2cc:20161015231619g:plain
正直説明するレベルの数学力はないです。(現在高校数学を勉強中です...)ですので良く使われているというカーネルを用意しました。f:id:manato2cc:20161015234107p:plain
例えば
f:id:manato2cc:20161015234943p:plain
この場合、
f(x,y)=120*(1/16)+140*(2/16)+120*(1/16)+140*(2/16)+160*(4/16)+140*(2/16)+120*(1/16)+140*(2/16)+120*(1/16)
となってf(x,y)=140となります。
このように繰り返し計算を行うことでぼかしていきます。
ではコードを

//Imany/util/algorithm/Gaussian.java
package Imany.util.algorithm;

import java.awt.image.BufferedImage;

public class Gaussian extends Algorithm
{
	//5*5のカーネル
	private static final double[][] GAUSSIAN_5 = 
			{
				{1/256.0,  4/256.0,  6/256.0,  4/256.0, 1/256.0},
				{4/256.0, 16/256.0, 24/256.0, 16/256.0, 4/256.0},
				{6/256.0, 24/256.0, 36/256.0, 24/256.0, 6/256.0},
				{4/256.0, 16/256.0, 24/256.0, 16/256.0, 4/256.0},
				{1/256.0,  4/256.0,  6/256.0,  4/256.0, 1/256.0}
			};
	//3*3のカーネル
	private static final double[][] GAUSSIAN_3 = 
			{
				{1/16, 2/16, 1/16},
				{2/16, 4/16, 2/16},
				{1/16, 2/16, 1/16}
			};
	public static BufferedImage algorithm(BufferedImage img, boolean grayscale)
	{
		if(grayscale) img = Grayscale.algorithm(img);//グレースケール化
		BufferedImage re = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
		re.setData(img.getData());
		for (int x = 1; x < img.getWidth() - 2; x++) {//端はできない
			for (int y = 1; y < img.getHeight() - 2; y++) {//端はできない
				if(x == 1 || x == img.getWidth() -2)
				{
					re.setRGB(x, y, toGaussian(img, x, y, GAUSSIAN_3, 1));
					continue;
				}
				if(y == 1 || y == img.getHeight())
				{
					re.setRGB(x, y, toGaussian(img, x, y, GAUSSIAN_3, 1));
					continue;
				}

				re.setRGB(x, y, toGaussian(img, x, y, GAUSSIAN_5, 2));
			}
		}
		return re;
	}

	private static int toGaussian(BufferedImage img, int x, int y, double[][] filter, int count)
	{
		double r = 0.0, g = 0.0, b = 0.0;
		int rgb = 0;
		for (int i = -count; i <= count; i++) {
			for (int j = -count; j <= count; j++) {
				int rgb1 = img.getRGB(x+i, y+j);
				b += (rgb1 & 0xff) * filter[i+count][j+count];
				g += ((rgb1 & 0xff00) >> 8) * filter[i+count][j+count];
				r += ((rgb1 & 0xff0000) >> 16) * filter[i+count][j+count];
			}
		}
		rgb = ((int) r << 16) | ((int) g << 8) | ((int)b);
		return rgb;
	}
}

特に説明する部分はないですね。カラー画像もできるように各色素ごとに計算を行なっています。countは3*3の場合1で5*5の場合2です。

結果

f:id:manato2cc:20161016000622p:plainf:id:manato2cc:20161016000627p:plain
ちょっと分かりづらいかも?