Cache kernel weights for each row.

For each row the convolution kernel is evaluated at fixed positions around "u". By calculating these values once for each row, a huge speedup is achieved.
This commit is contained in:
jst 2014-01-28 18:48:08 +01:00
parent 8f586c4f06
commit 9884534579
2 changed files with 33 additions and 12 deletions

View File

@ -49,23 +49,32 @@ type filterModel struct {
// temporary used by Interpolate // temporary used by Interpolate
tempRow []colorArray tempRow []colorArray
kernelWeight []float32
weightSum float32
} }
func (f *filterModel) convolution1d(x float32, p []colorArray) (c colorArray) { func (f *filterModel) SetKernelWeights(u float32) {
var k float32 uf := int(u) - len(f.tempRow)/2 + 1
var sum float32 = 0 u -= float32(uf)
f.weightSum = 0
for j := range p { for j := range f.tempRow {
k = f.kernel((x - float32(j)) * f.factorInv) f.kernelWeight[j] = f.kernel((u - float32(j)) * f.factorInv)
sum += k f.weightSum += f.kernelWeight[j]
}
}
func (f *filterModel) convolution1d(x float32) (c colorArray) {
for j := range f.tempRow {
for i := range c { for i := range c {
c[i] += p[j][i] * k c[i] += f.tempRow[j][i] * f.kernelWeight[j]
} }
} }
// normalize values // normalize values
for i := range c { for i := range c {
c[i] = c[i] / sum c[i] = c[i] / f.weightSum
} }
return return
@ -79,7 +88,7 @@ func (f *filterModel) Interpolate(u float32, y int) color.RGBA64 {
f.at(uf+i, y, &f.tempRow[i]) f.at(uf+i, y, &f.tempRow[i])
} }
c := f.convolution1d(u, f.tempRow) c := f.convolution1d(u)
return color.RGBA64{ return color.RGBA64{
clampToUint16(c[0]), clampToUint16(c[0]),
clampToUint16(c[1]), clampToUint16(c[1]),
@ -99,36 +108,48 @@ func createFilter(img image.Image, factor float32, size int, kernel func(float32
kernel, 1. / factor, kernel, 1. / factor,
&genericConverter{img}, &genericConverter{img},
make([]colorArray, sizeX), make([]colorArray, sizeX),
make([]float32, sizeX),
0,
} }
case *image.RGBA: case *image.RGBA:
f = &filterModel{ f = &filterModel{
kernel, 1. / factor, kernel, 1. / factor,
&rgbaConverter{img.(*image.RGBA)}, &rgbaConverter{img.(*image.RGBA)},
make([]colorArray, sizeX), make([]colorArray, sizeX),
make([]float32, sizeX),
0,
} }
case *image.RGBA64: case *image.RGBA64:
f = &filterModel{ f = &filterModel{
kernel, 1. / factor, kernel, 1. / factor,
&rgba64Converter{img.(*image.RGBA64)}, &rgba64Converter{img.(*image.RGBA64)},
make([]colorArray, sizeX), make([]colorArray, sizeX),
make([]float32, sizeX),
0,
} }
case *image.Gray: case *image.Gray:
f = &filterModel{ f = &filterModel{
kernel, 1. / factor, kernel, 1. / factor,
&grayConverter{img.(*image.Gray)}, &grayConverter{img.(*image.Gray)},
make([]colorArray, sizeX), make([]colorArray, sizeX),
make([]float32, sizeX),
0,
} }
case *image.Gray16: case *image.Gray16:
f = &filterModel{ f = &filterModel{
kernel, 1. / factor, kernel, 1. / factor,
&gray16Converter{img.(*image.Gray16)}, &gray16Converter{img.(*image.Gray16)},
make([]colorArray, sizeX), make([]colorArray, sizeX),
make([]float32, sizeX),
0,
} }
case *image.YCbCr: case *image.YCbCr:
f = &filterModel{ f = &filterModel{
kernel, 1. / factor, kernel, 1. / factor,
&ycbcrConverter{img.(*image.YCbCr)}, &ycbcrConverter{img.(*image.YCbCr)},
make([]colorArray, sizeX), make([]colorArray, sizeX),
make([]float32, sizeX),
0,
} }
} }

View File

@ -32,6 +32,7 @@ import (
// Filter can interpolate at points (x,y) // Filter can interpolate at points (x,y)
type Filter interface { type Filter interface {
SetKernelWeights(u float32)
Interpolate(u float32, y int) color.RGBA64 Interpolate(u float32, y int) color.RGBA64
} }
@ -87,11 +88,10 @@ func resizeSlice(input image.Image, output *image.RGBA64, interp InterpolationFu
var u float32 var u float32
var color color.RGBA64 var color color.RGBA64
for y := slice.Min.Y; y < slice.Max.Y; y++ { for y := slice.Min.Y; y < slice.Max.Y; y++ {
u = scale*(float32(y)+adjust) + offset
filter.SetKernelWeights(u)
for x := slice.Min.X; x < slice.Max.X; x++ { for x := slice.Min.X; x < slice.Max.X; x++ {
u = scale*(float32(y)+adjust) + offset
color = filter.Interpolate(u, x) color = filter.Interpolate(u, x)
i := output.PixOffset(x, y) i := output.PixOffset(x, y)
output.Pix[i+0] = uint8(color.R >> 8) output.Pix[i+0] = uint8(color.R >> 8)
output.Pix[i+1] = uint8(color.R) output.Pix[i+1] = uint8(color.R)