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

Use a lookup table to speed up the Lanczos kernel

Profiling the resize operation using Lanczos kernels showed that most of
the time was spent in the Sin function, which is called twice per
evaluation of the Lanczos kernel. Generating a lookup table and doing a
linear interpolation between table entries speeds up the resize by a
factor of 4.
Geoff Adams 13 лет назад
Родитель
Сommit
c1b8c4986e
1 измененных файлов с 35 добавлено и 2 удалено
  1. 35 2
      filters.go

+ 35 - 2
filters.go

@@ -142,6 +142,35 @@ func createFilter(img image.Image, factor [2]float32, size int, kernel func(floa
 	return
 }
 
+// Return a filter kernel that performs nearly identically to the provided
+// kernel, but generates and uses a precomputed table rather than executing
+// the kernel for each evaluation. The table is generated with tableSize
+// values that cover the kernal domain from -maxX to +maxX. The input kernel
+// is assumed to be symmetrical around 0, so the table only includes values
+// from 0 to maxX.
+func tableKernel(kernel func(float32) float32, tableSize int,
+	maxX float32) func(float32) float32 {
+
+	// precompute an array of filter coefficients
+	weights := make([]float32, tableSize+1)
+	for i := range weights {
+		weights[i] = kernel(maxX * float32(i) / float32(tableSize))
+	}
+	weights[tableSize] = 0.0
+
+	return func(x float32) float32 {
+		if x < 0.0 {
+			x = -x
+		}
+		indf := x / maxX * float32(tableSize)
+		ind := int(indf)
+		if ind >= tableSize {
+			return 0.0
+		}
+		return weights[ind] + (weights[ind+1]-weights[ind])*(indf-float32(ind))
+	}
+}
+
 // Nearest-neighbor interpolation
 func NearestNeighbor(img image.Image, factor [2]float32) Filter {
 	return createFilter(img, factor, 2, func(x float32) (y float32) {
@@ -213,12 +242,16 @@ func lanczosKernel(a uint) func(float32) float32 {
 	}
 }
 
+const lanczosTableSize = 300
+
 // Lanczos interpolation (a=2)
 func Lanczos2(img image.Image, factor [2]float32) Filter {
-	return createFilter(img, factor, 4, lanczosKernel(2))
+	return createFilter(img, factor, 4,
+		tableKernel(lanczosKernel(2), lanczosTableSize, 2.0))
 }
 
 // Lanczos interpolation (a=3)
 func Lanczos3(img image.Image, factor [2]float32) Filter {
-	return createFilter(img, factor, 6, lanczosKernel(3))
+	return createFilter(img, factor, 6,
+		tableKernel(lanczosKernel(3), lanczosTableSize, 3.0))
 }