Use Kernel normalization for more accurate Lanczos resampling. Lanczos2 filter added
This commit is contained in:
parent
339b8fd43a
commit
d93161631c
|
@ -33,6 +33,7 @@ The provided interpolation functions are
|
||||||
- `NearestNeighbor`: [Nearest-neighbor interpolation](http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation)
|
- `NearestNeighbor`: [Nearest-neighbor interpolation](http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation)
|
||||||
- `Bilinear`: [Bilinear interpolation](http://en.wikipedia.org/wiki/Bilinear_interpolation)
|
- `Bilinear`: [Bilinear interpolation](http://en.wikipedia.org/wiki/Bilinear_interpolation)
|
||||||
- `Bicubic`: [Bicubic interpolation](http://en.wikipedia.org/wiki/Bicubic_interpolation)
|
- `Bicubic`: [Bicubic interpolation](http://en.wikipedia.org/wiki/Bicubic_interpolation)
|
||||||
|
- `Lanczos2`: [Lanczos resampling](http://en.wikipedia.org/wiki/Lanczos_resampling) with a=2
|
||||||
- `Lanczos3`: [Lanczos resampling](http://en.wikipedia.org/wiki/Lanczos_resampling) with a=3
|
- `Lanczos3`: [Lanczos resampling](http://en.wikipedia.org/wiki/Lanczos_resampling) with a=3
|
||||||
|
|
||||||
Sample usage:
|
Sample usage:
|
||||||
|
@ -43,6 +44,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"github.com/nfnt/resize"
|
"github.com/nfnt/resize"
|
||||||
"image/jpeg"
|
"image/jpeg"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -50,13 +52,13 @@ func main() {
|
||||||
// open "test.jpg"
|
// open "test.jpg"
|
||||||
file, err := os.Open("test.jpg")
|
file, err := os.Open("test.jpg")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// decode jpeg into image.Image
|
// decode jpeg into image.Image
|
||||||
img, err := jpeg.Decode(file)
|
img, err := jpeg.Decode(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
file.Close()
|
file.Close()
|
||||||
|
|
||||||
|
@ -66,7 +68,7 @@ func main() {
|
||||||
|
|
||||||
out, err := os.Create("test_resized.jpg")
|
out, err := os.Create("test_resized.jpg")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
defer out.Close()
|
defer out.Close()
|
||||||
|
|
||||||
|
|
58
filters.go
58
filters.go
|
@ -97,19 +97,59 @@ func Bicubic(x, y float32, img image.Image) color.RGBA64 {
|
||||||
return color.RGBA64{c[0], c[1], c[2], c[3]}
|
return color.RGBA64{c[0], c[1], c[2], c[3]}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1-d convolution with windowed sinc for a=3.
|
// 1-d convolution with windowed sinc for a=2.
|
||||||
func lanczos_x(x float32, p *[6]RGBA) (c RGBA) {
|
func lanczos2_x(x float32, p *[4]RGBA) (c RGBA) {
|
||||||
x -= float32(math.Floor(float64(x)))
|
x -= float32(math.Floor(float64(x)))
|
||||||
var v float32
|
|
||||||
|
var kernel float32
|
||||||
|
var sum float32 = 0 // for kernel normalization
|
||||||
l := [4]float32{0.0, 0.0, 0.0, 0.0}
|
l := [4]float32{0.0, 0.0, 0.0, 0.0}
|
||||||
|
|
||||||
for j := range p {
|
for j := range p {
|
||||||
v = float32(Sinc(float64(x-float32(j-2)))) * float32(Sinc(float64((x-float32(j-2))/3.0)))
|
kernel = float32(Sinc(float64(x-float32(j-1)))) * float32(Sinc(float64((x-float32(j-1))/2.0)))
|
||||||
|
sum += kernel
|
||||||
for i := range c {
|
for i := range c {
|
||||||
l[i] += float32(p[j][i]) * v
|
l[i] += float32(p[j][i]) * kernel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := range c {
|
for i := range c {
|
||||||
c[i] = clampToUint16(l[i])
|
c[i] = clampToUint16(l[i] / sum)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lanczos interpolation (a=2).
|
||||||
|
func Lanczos2(x, y float32, img image.Image) color.RGBA64 {
|
||||||
|
xf, yf := int(math.Floor(float64(x))), int(math.Floor(float64(y)))
|
||||||
|
|
||||||
|
var row [4]RGBA
|
||||||
|
var col [4]RGBA
|
||||||
|
for i := range row {
|
||||||
|
row = [4]RGBA{toRGBA(img.At(xf-1, yf+i-1)), toRGBA(img.At(xf, yf+i-1)), toRGBA(img.At(xf+1, yf+i-1)), toRGBA(img.At(xf+2, yf+i-1))}
|
||||||
|
col[i] = lanczos2_x(x, &row)
|
||||||
|
}
|
||||||
|
|
||||||
|
c := lanczos2_x(y, &col)
|
||||||
|
return color.RGBA64{c[0], c[1], c[2], c[3]}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1-d convolution with windowed sinc for a=3.
|
||||||
|
func lanczos3_x(x float32, p *[6]RGBA) (c RGBA) {
|
||||||
|
x -= float32(math.Floor(float64(x)))
|
||||||
|
|
||||||
|
var kernel float32
|
||||||
|
var sum float32 = 0 // for kernel normalization
|
||||||
|
l := [4]float32{0.0, 0.0, 0.0, 0.0}
|
||||||
|
|
||||||
|
for j := range p {
|
||||||
|
kernel = float32(Sinc(float64(x-float32(j-2)))) * float32(Sinc(float64((x-float32(j-2))/3.0)))
|
||||||
|
sum += kernel
|
||||||
|
for i := range c {
|
||||||
|
l[i] += float32(p[j][i]) * kernel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := range c {
|
||||||
|
c[i] = clampToUint16(l[i] / sum)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -120,11 +160,11 @@ func Lanczos3(x, y float32, img image.Image) color.RGBA64 {
|
||||||
|
|
||||||
var row [6]RGBA
|
var row [6]RGBA
|
||||||
var col [6]RGBA
|
var col [6]RGBA
|
||||||
for i := 0; i < 6; i++ {
|
for i := range row {
|
||||||
row = [6]RGBA{toRGBA(img.At(xf-2, yf+i-2)), toRGBA(img.At(xf-1, yf+i-2)), toRGBA(img.At(xf, yf+i-2)), toRGBA(img.At(xf+1, yf+i-2)), toRGBA(img.At(xf+2, yf+i-2)), toRGBA(img.At(xf+3, yf+i-2))}
|
row = [6]RGBA{toRGBA(img.At(xf-2, yf+i-2)), toRGBA(img.At(xf-1, yf+i-2)), toRGBA(img.At(xf, yf+i-2)), toRGBA(img.At(xf+1, yf+i-2)), toRGBA(img.At(xf+2, yf+i-2)), toRGBA(img.At(xf+3, yf+i-2))}
|
||||||
col[i] = lanczos_x(x, &row)
|
col[i] = lanczos3_x(x, &row)
|
||||||
}
|
}
|
||||||
|
|
||||||
c := lanczos_x(y, &col)
|
c := lanczos3_x(y, &col)
|
||||||
return color.RGBA64{c[0], c[1], c[2], c[3]}
|
return color.RGBA64{c[0], c[1], c[2], c[3]}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user