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.
This commit is contained in:
Geoff Adams 2013-07-04 02:28:43 -07:00
parent 33204d8746
commit c1b8c4986e

View File

@ -142,6 +142,35 @@ func createFilter(img image.Image, factor [2]float32, size int, kernel func(floa
return 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 // Nearest-neighbor interpolation
func NearestNeighbor(img image.Image, factor [2]float32) Filter { func NearestNeighbor(img image.Image, factor [2]float32) Filter {
return createFilter(img, factor, 2, func(x float32) (y float32) { 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) // Lanczos interpolation (a=2)
func Lanczos2(img image.Image, factor [2]float32) Filter { 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) // Lanczos interpolation (a=3)
func Lanczos3(img image.Image, factor [2]float32) Filter { 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))
} }