Просмотр исходного кода

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.
jst 12 лет назад
Родитель
Сommit
9884534579
2 измененных файлов с 33 добавлено и 12 удалено
  1. 30 9
      filters.go
  2. 3 3
      resize.go

+ 30 - 9
filters.go

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

+ 3 - 3
resize.go

@@ -32,6 +32,7 @@ import (
 
 // Filter can interpolate at points (x,y)
 type Filter interface {
+	SetKernelWeights(u float32)
 	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 color color.RGBA64
 	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++ {
-			u = scale*(float32(y)+adjust) + offset
-
 			color = filter.Interpolate(u, x)
-
 			i := output.PixOffset(x, y)
 			output.Pix[i+0] = uint8(color.R >> 8)
 			output.Pix[i+1] = uint8(color.R)