積和演算について
今までの作成したものは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}
}
}
出力結果

ノイズの多いサンプル画像ないと効果があんまりわからんとですね。その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]}
}

ノイズの多いサンプル画像ないと効果があんまりわからんとですね。その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ピクセル縦に動く間にでどれだけ変化しますか?
変化が多いほど濃度は濃くなるといったカラクリですね。
出力画像
モノクロにするとよりわかるんですけどね。まフィルタを↓のにすると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}
$
