お題目
- 最近傍法によるサイズ変換
- 線形補間法によるサイズ変換
裏テーマ
1. mainで動かしてたけど、テストで駆動するように変更
2. for文を一箇所にまとめる
最近傍法
要するに、拡大した時に対応するピクセルを比で求めるというだけ。
ソースコード
imageLoopに渡してる、関数の引数xとyが変換後の画像の位置なのですが、それがどこかをdownの関数内で求めてるだけです。
大したことないですな
// 最近傍方
func (ef *effect) ChangeSize() image.Image {
up := func(val int, rat float64) int { return int(float64(val) * rat) }
down := func(val int, rat float64) int { return int(float64(val) / rat) }
// とりあえず正方形にして、0.5倍にする
ratio := 0.5
rect := ef.inputImage.Bounds()
width := up(rect.Size().X, ratio)
height := width
newRect := image.Rect(0, 0, width, height)
yRatio := float64(height) / float64(rect.Size().Y)
return ef.imageLoop(newRect, func(x, y int) color.RGBA64 {
r, g, b, a := ef.inputImage.At(down(x, ratio), down(y, yRatio)).RGBA()
return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
})
}
ちなみに某技術書を見ながらやってるんだけど、テキストのソースコード間違ってますね。
画像
線形補間法
ピクセル間の平均取ればもっといいよねって話
数式は面倒だからwiki参照
数学でやりましたね、この式。なお、テキストはもう少しプログラム寄りに書いてありそうです。
ソースコード
func (ef *effect) senning(x, y int, xRatio, yRatio float64) color.RGBA64 {
// 比較のための4点とその位置の比を求める関数
createParam := func(inSize, outSize int, ratio float64) (int, int, float64) {
v1 := down(outSize, ratio)
v2 := v1 + 1
if v2 > inSize-1 {
v2 = inSize - 1
}
v3 := float64(outSize)/ratio - float64(v1)
return v1, v2, v3
}
// 計測点(パラメータ)を作る
point := ef.inputImage.Bounds().Size()
j1, j2, q := createParam(point.Y, y, yRatio)
i1, i2, p := createParam(point.X, x, xRatio)
positions := [4]struct {
X int
Y int
}{
{i1, j1},
{i2, j1},
{i1, j2},
{i2, j2},
}
// 4点の値を取得する
var valsR, valsG, valsB, valsA [len(positions)]float64
for i, v := range positions {
r, g, b, a := ef.inputImage.At(v.X, v.Y).RGBA()
valsR[i] = float64(r)
valsG[i] = float64(g)
valsB[i] = float64(b)
valsA[i] = float64(a)
}
//各要素の値を求める関数
con := func(val [4]float64) uint16 {
return uint16((1.0-q)*((1.0-p)*val[0]+p*val[1]) + q*((1-p)*val[2]+p*val[3]))
}
return color.RGBA64{con(valsR), con(valsG), con(valsB), con(valsA)}
}
4点の値を取得するあたりはもう少しやりようがある気がする。
思いつきませんでした。
とりあえず、注目すべきは無名関数conの中ですね、。
uint16((1.0-q)*((1.0-p)*val[0]+p*val[1]) + q*((1-p)*val[2]+p*val[3]))
ちょっと理解しやすくしましょう
$$
\biggl( (1-q) \times \bigl((1-p) \times V_{ij} + p \times V_{i+1j} \bigr) \biggr) + \biggl(q \times \bigl((1-p) \times V_{ij+1} + p \times V_{i+1j+1}) \bigr) \biggr)
$$
1ってのが、変化量の比であると気付けば難しい数式ではないですね。