Unify filters and their dependencies

This commit is contained in:
jst 2012-09-15 20:24:14 +02:00
parent 3fc31c95cc
commit e96bbe5547
2 changed files with 62 additions and 62 deletions

View File

@ -41,17 +41,24 @@ func clampToUint16(x float32) (y uint16) {
return return
} }
func convolution1d(x float32, kernel func(float32) float32, p []rgba16) (c rgba16) { type filterModel struct {
x -= float32(int(x)) src image.Image
size int
kernel func(float32) float32
tempRow []rgba16
tempCol []rgba16
}
m := float32(len(p)/2-1) func (f *filterModel) convolution1d(x float32, p []rgba16) (c rgba16) {
x -= float32(int(x))
m := float32(f.size/2 - 1)
var k float32 var k float32
var sum float32 = 0 var sum float32 = 0
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 {
k = kernel(x+m-float32(j)) k = f.kernel(x + m - float32(j))
sum += k sum += k
for i := range c { for i := range c {
l[i] += float32(p[j][i]) * k l[i] += float32(p[j][i]) * k
@ -63,51 +70,43 @@ func convolution1d(x float32, kernel func(float32) float32, p []rgba16) (c rgba1
return return
} }
func filter(x, y float32, img image.Image, n int, kernel func(x float32) float32) color.RGBA64 { func (f *filterModel) Interpolate(x, y float32) color.RGBA64 {
xf, yf := int(x)-n/2+1, int(y)-n/2+1 xf, yf := int(x)-f.size/2+1, int(y)-f.size/2+1
row := make([]rgba16, n) for i := 0; i < f.size; i++ {
col := make([]rgba16, n) for j := 0; j < f.size; j++ {
f.tempRow[j] = toRGBA(f.src.At(xf+j, yf+i))
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
row[j] = toRGBA(img.At(xf+j, yf+i))
} }
col[i] = convolution1d(x, kernel, row) f.tempCol[i] = f.convolution1d(x, f.tempRow)
} }
c := convolution1d(y, kernel, col) c := f.convolution1d(y, f.tempCol)
return color.RGBA64{c[0], c[1], c[2], c[3]} return color.RGBA64{c[0], c[1], c[2], c[3]}
} }
// Nearest-neighbor interpolation. // Nearest-neighbor interpolation.
// Approximates a value by returning the value of the nearest point. // Approximates a value by returning the value of the nearest point.
func NearestNeighbor(x, y float32, img image.Image) color.RGBA64 { func NearestNeighbor(img image.Image) Filter {
n := 2 return &filterModel{img, 2, func(x float32) (y float32) {
kernel := func(x float32) (y float32) {
if x >= -0.5 && x < 0.5 { if x >= -0.5 && x < 0.5 {
y = 1 y = 1
} else { } else {
y = 0 y = 0
} }
return return
} }, make([]rgba16, 2), make([]rgba16, 2)}
return filter(x, y, img, n, kernel)
} }
// Bicubic interpolation // Bicubic interpolation
func Bilinear(x, y float32, img image.Image) color.RGBA64 { func Bilinear(img image.Image) Filter {
n := 2 return &filterModel{img, 2, func(x float32) float32 {
kernel := func(x float32) float32 {
return 1 - float32(math.Abs(float64(x))) return 1 - float32(math.Abs(float64(x)))
} }, make([]rgba16, 2), make([]rgba16, 2)}
return filter(x, y, img, n, kernel)
} }
// Bicubic interpolation // Bicubic interpolation
func Bicubic(x, y float32, img image.Image) color.RGBA64 { func Bicubic(img image.Image) Filter {
n := 4 return &filterModel{img, 4, func(x float32) (y float32) {
kernel := func(x float32) (y float32) {
absX := float32(math.Abs(float64(x))) absX := float32(math.Abs(float64(x)))
if absX <= 1 { if absX <= 1 {
y = absX*absX*(1.5*absX-2.5) + 1 y = absX*absX*(1.5*absX-2.5) + 1
@ -115,24 +114,19 @@ func Bicubic(x, y float32, img image.Image) color.RGBA64 {
y = absX*(absX*(2.5-0.5*absX)-4) + 2 y = absX*(absX*(2.5-0.5*absX)-4) + 2
} }
return return
} }, make([]rgba16, 4), make([]rgba16, 4)}
return filter(x, y, img, n, kernel)
} }
// Lanczos interpolation (a=2). // Lanczos interpolation (a=2).
func Lanczos2(x, y float32, img image.Image) color.RGBA64 { func Lanczos2(img image.Image) Filter {
n := 4 return &filterModel{img, 4, func(x float32) float32 {
kernel := func(x float32) float32 {
return float32(Sinc(float64(x))) * float32(Sinc(float64((x)/float32(2)))) return float32(Sinc(float64(x))) * float32(Sinc(float64((x)/float32(2))))
} }, make([]rgba16, 4), make([]rgba16, 4)}
return filter(x, y, img, n, kernel)
} }
// Lanczos interpolation (a=3). // Lanczos interpolation (a=3).
func Lanczos3(x, y float32, img image.Image) color.RGBA64 { func Lanczos3(img image.Image) Filter {
n := 6 return &filterModel{img, 6, func(x float32) float32 {
kernel := func(x float32) float32 {
return float32(Sinc(float64(x))) * float32(Sinc(float64((x)/float32(3)))) return float32(Sinc(float64(x))) * float32(Sinc(float64((x)/float32(3))))
} }, make([]rgba16, 6), make([]rgba16, 6)}
return filter(x, y, img, n, kernel)
} }

View File

@ -40,30 +40,14 @@ func (t *Trans2) Eval(x, y float32) (u, v float32) {
return return
} }
// Calculate scaling factors using old and new image dimensions. // Filter can interpolate at points (x,y)
func calcFactors(width, height uint, oldWidth, oldHeight float32) (scaleX, scaleY float32) { type Filter interface {
if width == 0 { Interpolate(x, y float32) color.RGBA64
if height == 0 {
scaleX = 1.0
scaleY = 1.0
} else {
scaleY = oldHeight / float32(height)
scaleX = scaleY
}
} else {
scaleX = oldWidth / float32(width)
if height == 0 {
scaleY = scaleX
} else {
scaleY = oldHeight / float32(height)
}
}
return
} }
// InterpolationFunction return a color for an arbitrary point inside // InterpolationFunction return a Filter implementation
// an image // that operates on an image
type InterpolationFunction func(float32, float32, image.Image) color.RGBA64 type InterpolationFunction func(image.Image) Filter
// Resize an image to new width and height using the interpolation function interp. // Resize an image to new width and height using the interpolation function interp.
// A new image with the given dimensions will be returned. // A new image with the given dimensions will be returned.
@ -85,11 +69,12 @@ func Resize(width, height uint, img image.Image, interp InterpolationFunction) i
c := make(chan int, n) c := make(chan int, n)
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
go func(b image.Rectangle, c chan int) { go func(b image.Rectangle, c chan int) {
filter := interp(img)
var u, v float32 var u, v float32
for y := b.Min.Y; y < b.Max.Y; y++ { for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ { for x := b.Min.X; x < b.Max.X; x++ {
u, v = t.Eval(float32(x), float32(y)) u, v = t.Eval(float32(x), float32(y))
resizedImg.SetRGBA64(x, y, interp(u, v, img)) resizedImg.SetRGBA64(x, y, filter.Interpolate(u, v))
} }
} }
c <- 1 c <- 1
@ -103,6 +88,27 @@ func Resize(width, height uint, img image.Image, interp InterpolationFunction) i
return resizedImg return resizedImg
} }
// Calculate scaling factors using old and new image dimensions.
func calcFactors(width, height uint, oldWidth, oldHeight float32) (scaleX, scaleY float32) {
if width == 0 {
if height == 0 {
scaleX = 1.0
scaleY = 1.0
} else {
scaleY = oldHeight / float32(height)
scaleX = scaleY
}
} else {
scaleX = oldWidth / float32(width)
if height == 0 {
scaleY = scaleX
} else {
scaleY = oldHeight / float32(height)
}
}
return
}
// Set number of parallel jobs // Set number of parallel jobs
// but prevent resize from doing too much work // but prevent resize from doing too much work
// if #CPUs > width // if #CPUs > width