1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

golangで空間フィルタをかけて行く1

Last updated at Posted at 2017-01-05

積和演算について

今までの作成したものはxとyの画素に対してのようなものですが、ここからは1つのXY画素に対して周りの情報から何かしらの情報を作成するようになる。
という具合だと思う。

平坦化フィルタ

平均値フィルタ

XYの箇所とその近傍9点を採取して、その平均の値を採用する。(場合によっては中央の値に重みをつける。)

ソースコード

centerWeightが中央の重みとして、カリー化するようなイメージで共通化を図った。
最初のif文は恥のところは9点取れないから、そのままとるってな話。

func AverageFunc(centerWeight float64) icom.EffectFunc {
	return func(img image.Image, x, y int) color.RGBA64 {
		if x == 0 || y == 0 || x == img.Bounds().Size().X || y == img.Bounds().Size().Y {
			r, g, b, a := img.At(x, y).RGBA()
			return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
		}
		var sumR, sumG, sumB uint32
		var valA uint16
		//3*3のサイズを全部足す
		for pX := x - 1; pX <= x+1; pX++ {
			for pY := y - 1; pY <= y+1; pY++ {
				r, g, b, a := img.At(pX, pY).RGBA()
				weight := 1.0
				if pX == x && pY == y {
					valA = uint16(a)
					weight = centerWeight
				}
				sumR += uint32(float64(r) * weight)
				sumG += uint32(float64(g) * weight)
				sumB += uint32(float64(b) * weight)
			}
		}
		valR := uint16(float64(sumR) / (8 + centerWeight))
		valG := uint16(float64(sumG) / (8 + centerWeight))
		valB := uint16(float64(sumB) / (8 + centerWeight))
		return color.RGBA64{valR, valG, valB, valA}
	}
}

出力結果

test_avefil.png
ノイズの多いサンプル画像ないと効果があんまりわからんとですね。その1

メディアンフィルタ

XYの箇所とその近傍9点を採取して、その中から5番目の値を採用する。

func MedianFunc(img image.Image, x, y int) color.RGBA64 {
	aryR := make([]uint16, 10)
	aryG := make([]uint16, 10)
	aryB := make([]uint16, 10)
	aryA := make([]uint16, 10)
	count := 0
	//3*3のサイズを全部足す
	for pX := x - 1; pX <= x+1; pX++ {
		for pY := y - 1; pY <= y+1; pY++ {
			r, g, b, a := img.At(pX, pY).RGBA()
			aryR[count] = uint16(r)
			aryG[count] = uint16(g)
			aryB[count] = uint16(b)
			aryA[count] = uint16(a)
			count++
		}
	}
	// ソートする
	sort.Sort(Gasos(aryR))
	sort.Sort(Gasos(aryG))
	sort.Sort(Gasos(aryB))
	sort.Sort(Gasos(aryA))

	return color.RGBA64{aryR[4], aryG[4], aryB[4], aryA[4]}
}

test_media.png
ノイズの多いサンプル画像ないと効果があんまりわからんとですね。その2

Prewittフィルタ

漫画みたいな輪郭ってのは、現実世界には存在しない、つまり境界ってのは色の変化が当然大きくなるから、それを見てみようという話。
前同様で、9点サンプルし下の情報の重みとして合算する。その絶対値が情報の変化量として採用する。

$xFilter = \begin{bmatrix}
1 & 0 & -1 \
1 & 0 & -1 \
1 & 0 & -1
\end{bmatrix}
$

$yFilter = \begin{bmatrix}
1 & 1 & 1 \
0 & 0 & 0 \
-1 & -1 & -1
\end{bmatrix}$

ソースコード

func PrewittFunc(img image.Image, x, y int) color.RGBA64 {
	if isRect(x, y, img) == true {
		r, g, b, a := img.At(x, y).RGBA()
		return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
	}
	// フィルタの情報の重み
	xFilter := [][]int{
		{1, 0, -1},
		{1, 0, -1},
		{1, 0, -1},
	}
	yFilter := [][]int{
		{-1, -1, -1},
		{0, 0, 0},
		{1, 1, 1},
	}
	//情報の集約(フィルタ込み)
	var rMd1, rMd2, gMd1, gMd2, bMd1, bMd2 int = 0, 0, 0, 0, 0, 0
	for pX := 0; pX < 3; pX++ {
		for pY := 0; pY < 3; pY++ {
			r, g, b, _ := img.At(x+(pX-1), y+(pY-1)).RGBA()
			rMd1 += xFilter[pX][pY] * int(r)
			rMd2 += yFilter[pX][pY] * int(r)
			gMd1 += xFilter[pX][pY] * int(g)
			gMd2 += yFilter[pX][pY] * int(r)
			bMd1 += xFilter[pX][pY] * int(b)
			bMd2 += yFilter[pX][pY] * int(r)
		}
	}
	// フィルタの絶対値取得
	getValue := func(md1, md2 int) uint16 {
		gaso := (math.Abs(float64(md1)) + math.Abs(float64(md2)))
		if gaso > ex.ColorWidth {
			gaso = ex.ColorWidth
		} else if gaso < 0 {
			gaso = 0
		}
		return uint16(gaso)
	}
	red := getValue(rMd1, rMd2)
	green := getValue(gMd1, gMd2)
	blue := getValue(bMd1, bMd2)
	_, _, _, a := img.At(x, y).RGBA()
	return color.RGBA64{red, green, blue, uint16(a)}
}

xFilterとyFilterがPrewittフィルタたる所以です。
xFilterは3ピクセル横に動く間にでどれだけ変化しますか?
yFilterは3ピクセル縦に動く間にでどれだけ変化しますか?
変化が多いほど濃度は濃くなるといったカラクリですね。

出力画像

test_prewitt.png

モノクロにするとよりわかるんですけどね。まフィルタを↓のにするとSobelフィルタになる。真ん中は強いということですね。

$xFilter = \begin{bmatrix}
1 & 0 & -1 \\
2 & 0 & -2 \\
1 & 0 & -1
\end{bmatrix}
$

$
yFilter = \begin{bmatrix}
1 & 2 & 1 \\
0 & 0 & 0 \\
-1 & -2 & -1
\end{bmatrix}
$

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?