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

Use Kernel normalization for more accurate Lanczos resampling. Lanczos2 filter added

jst 13 лет назад
Родитель
Сommit
d93161631c
2 измененных файлов с 53 добавлено и 11 удалено
  1. 5 3
      README.md
  2. 48 8
      filters.go

+ 5 - 3
README.md

@@ -33,6 +33,7 @@ The provided interpolation functions are
 - `NearestNeighbor`: [Nearest-neighbor interpolation](http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation)
 - `Bilinear`: [Bilinear interpolation](http://en.wikipedia.org/wiki/Bilinear_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
 
 Sample usage:
@@ -43,6 +44,7 @@ package main
 import (
 	"github.com/nfnt/resize"
 	"image/jpeg"
+	"log"
 	"os"
 )
 
@@ -50,13 +52,13 @@ func main() {
 	// open "test.jpg"
 	file, err := os.Open("test.jpg")
 	if err != nil {
-		return
+		log.Fatal(err)
 	}
 
 	// decode jpeg into image.Image
 	img, err := jpeg.Decode(file)
 	if err != nil {
-		return
+		log.Fatal(err)
 	}
 	file.Close()
 
@@ -66,7 +68,7 @@ func main() {
 
 	out, err := os.Create("test_resized.jpg")
 	if err != nil {
-		return
+		log.Fatal(err)
 	}
 	defer out.Close()
 

+ 48 - 8
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]}
 }
 
+// 1-d convolution with windowed sinc for a=2.
+func lanczos2_x(x float32, p *[4]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-1)))) * float32(Sinc(float64((x-float32(j-1))/2.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
+}
+
+// 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 lanczos_x(x float32, p *[6]RGBA) (c RGBA) {
+func lanczos3_x(x float32, p *[6]RGBA) (c RGBA) {
 	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}
+
 	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-2)))) * float32(Sinc(float64((x-float32(j-2))/3.0)))
+		sum += kernel
 		for i := range c {
-			l[i] += float32(p[j][i]) * v
+			l[i] += float32(p[j][i]) * kernel
 		}
 	}
 	for i := range c {
-		c[i] = clampToUint16(l[i])
+		c[i] = clampToUint16(l[i] / sum)
 	}
 	return
 }
@@ -120,11 +160,11 @@ func Lanczos3(x, y float32, img image.Image) color.RGBA64 {
 
 	var row [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))}
-		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]}
 }