From c1b8c4986eed0c971827101d686b03d4e00e8024 Mon Sep 17 00:00:00 2001 From: Geoff Adams Date: Thu, 4 Jul 2013 02:28:43 -0700 Subject: [PATCH] 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. --- filters.go | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/filters.go b/filters.go index 3bf29d2..27b57ec 100644 --- a/filters.go +++ b/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)) }