choose interpolation algorithm

This commit is contained in:
Laurent Le Goff 2011-04-14 12:17:11 +02:00
parent c391300572
commit 71da9797fd
7 changed files with 105 additions and 53 deletions

View File

@ -17,19 +17,19 @@ func saveToPngFile(filePath string, m image.Image) {
f, err := os.Open(filePath, os.O_CREAT|os.O_WRONLY, 0600)
if err != nil {
log.Println(err)
os.Exit(1)
return
}
defer f.Close()
b := bufio.NewWriter(f)
err = png.Encode(b, m)
if err != nil {
log.Println(err)
os.Exit(1)
return
}
err = b.Flush()
if err != nil {
log.Println(err)
os.Exit(1)
return
}
fmt.Printf("Wrote %s OK.\n", filePath)
}
@ -52,29 +52,20 @@ func loadFromPngFile(filePath string) image.Image {
}
func testBubble(gc draw2d.GraphicContext) {
gc.BeginPath()
gc.MoveTo(75, 25)
gc.QuadCurveTo(25, 25, 25, 62.5)
gc.QuadCurveTo(25, 100, 50, 100)
gc.QuadCurveTo(50, 120, 30, 125)
gc.QuadCurveTo(60, 120, 65, 100)
gc.QuadCurveTo(125, 100, 125, 62.5)
gc.QuadCurveTo(125, 25, 75, 25)
gc.Stroke()
}
func main() {
source := loadFromPngFile("../resource/image/Varna_Railway_Station_HDR.png")
source := loadFromPngFile("../resource/image/TestAndroid.png")
i := image.NewRGBA(1024, 768)
gc := draw2d.NewImageGraphicContext(i)
gc.Scale(2, 0.5)
//gc.Translate(75, 25)
// gc.Scale(2, 0.5)
gc.Translate(float64(source.Bounds().Dx()/2), float64(source.Bounds().Dy()/2))
gc.Rotate(30 * math.Pi / 180)
gc.Translate(float64(-source.Bounds().Dx()/2), float64(-source.Bounds().Dy()/2))
gc.Translate(75, 25)
lastTime := time.Nanoseconds()
gc.DrawImage(source)
dt := time.Nanoseconds() - lastTime
fmt.Printf("Draw image: %f ms\n", float64(dt)*1e-6)
saveToPngFile("../resource/result/TestDrawImage.png", i)
}

View File

@ -200,7 +200,7 @@ func (gc *ImageGraphicContext) Restore() {
}
func (gc *ImageGraphicContext) DrawImage(img image.Image) {
DrawImage(img, gc.img, gc.current.tr, draw.Over, linearFilter)
DrawImage(img, gc.img, gc.current.tr, draw.Over, BilinearFilter)
}
func (gc *ImageGraphicContext) BeginPath() {

View File

@ -21,3 +21,31 @@ func squareDistance(x1, y1, x2, y2 float64) float64 {
dy := y2 - y1
return dx*dx + dy*dy
}
func min(x, y float64) float64 {
if x < y {
return x
}
return y
}
func max(x, y float64) float64 {
if x > y {
return x
}
return y
}
func minMax(x, y float64) (min, max float64) {
if x > y {
return y, x
}
return x, y
}
func minUint32(a, b uint32) uint32 {
if a < b {
return a
}
return b
}

View File

@ -19,13 +19,6 @@ type NRGBAPainter struct {
cr, cg, cb, ca uint32
}
func min(a, b uint32) uint32 {
if a < b {
return a
}
return b
}
// Paint satisfies the Painter interface by painting ss onto an image.RGBA.
func (r *NRGBAPainter) Paint(ss []raster.Span, done bool) {
b := r.Image.Bounds()
@ -57,9 +50,9 @@ func (r *NRGBAPainter) Paint(ss []raster.Span, done bool) {
a := M - (r.ca*ma)/M
da = (da*a + r.ca*ma) / M
if da != 0 {
dr = min(M, (dr*a+r.cr*ma)/da)
dg = min(M, (dg*a+r.cg*ma)/da)
db = min(M, (db*a+r.cb*ma)/da)
dr = minUint32(M, (dr*a+r.cr*ma)/da)
dg = minUint32(M, (dg*a+r.cg*ma)/da)
db = minUint32(M, (db*a+r.cb*ma)/da)
} else {
dr, dg, db = 0, 0, 0
}
@ -71,9 +64,9 @@ func (r *NRGBAPainter) Paint(ss []raster.Span, done bool) {
a := M - ma
da = (da*a + r.ca*ma) / M
if da != 0 {
dr = min(M, (dr*a+r.cr*ma)/da)
dg = min(M, (dg*a+r.cg*ma)/da)
db = min(M, (db*a+r.cb*ma)/da)
dr = minUint32(M, (dr*a+r.cr*ma)/da)
dg = minUint32(M, (dg*a+r.cg*ma)/da)
db = minUint32(M, (db*a+r.cb*ma)/da)
} else {
dr, dg, db = 0, 0, 0
}

View File

@ -5,12 +5,13 @@ import (
"image"
"math"
)
type ImageFilter int
const (
linearFilter ImageFilter = iota
bilinearFilter
bicubicFilter
LinearFilter ImageFilter = iota
BilinearFilter
BicubicFilter
)
//see http://pippin.gimp.org/image_processing/chap_resampling.html
@ -59,8 +60,8 @@ func getColorCubicRow(img image.Image, x, y, offset float64) image.Color {
r1, g1, b1, a1 := c1.RGBA()
r2, g2, b2, a2 := c2.RGBA()
r3, g3, b3, a3 := c3.RGBA()
r, g, b, a := cubic(offset,float64(r0),float64(r1),float64(r2),float64(r3)), cubic(offset,float64(g0),float64(g1),float64(g2),float64(g3)), cubic(offset,float64(b0),float64(b1),float64(b2),float64(b3)), cubic(offset,float64(a0),float64(a1),float64(a2),float64(a3))
return image.RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
r, g, b, a := cubic(offset, float64(r0), float64(r1), float64(r2), float64(r3)), cubic(offset, float64(g0), float64(g1), float64(g2), float64(g3)), cubic(offset, float64(b0), float64(b1), float64(b2), float64(b3)), cubic(offset, float64(a0), float64(a1), float64(a2), float64(a3))
return image.RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
}
func getColorBicubic(img image.Image, x, y float64) image.Color {
@ -77,15 +78,15 @@ func getColorBicubic(img image.Image, x, y float64) image.Color {
r1, g1, b1, a1 := c1.RGBA()
r2, g2, b2, a2 := c2.RGBA()
r3, g3, b3, a3 := c3.RGBA()
r, g, b, a := cubic(dy,float64(r0),float64(r1),float64(r2),float64(r3)), cubic(dy,float64(g0),float64(g1),float64(g2),float64(g3)), cubic(dy,float64(b0),float64(b1),float64(b2),float64(b3)), cubic(dy,float64(a0),float64(a1),float64(a2),float64(a3))
r, g, b, a := cubic(dy, float64(r0), float64(r1), float64(r2), float64(r3)), cubic(dy, float64(g0), float64(g1), float64(g2), float64(g3)), cubic(dy, float64(b0), float64(b1), float64(b2), float64(b3)), cubic(dy, float64(a0), float64(a1), float64(a2), float64(a3))
return image.RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
}
func cubic(offset,v0,v1,v2,v3 float64) uint32{
// offset is the offset of the sampled value between v1 and v2
return uint32((((( -7 * v0 + 21 * v1 - 21 * v2 + 7 * v3 ) * offset +
( 15 * v0 - 36 * v1 + 27 * v2 - 6 * v3 ) ) * offset +
( -9 * v0 + 9 * v2 ) ) * offset + (v0 + 16 * v1 + v2) ) / 18.0);
func cubic(offset, v0, v1, v2, v3 float64) uint32 {
// offset is the offset of the sampled value between v1 and v2
return uint32(((((-7*v0+21*v1-21*v2+7*v3)*offset+
(15*v0-36*v1+27*v2-6*v3))*offset+
(-9*v0+9*v2))*offset + (v0 + 16*v1 + v2)) / 18.0)
}
func compose(c1, c2 image.Color) image.Color {
@ -99,20 +100,42 @@ func compose(c1, c2 image.Color) image.Color {
return image.RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
}
func DrawImage(src image.Image, dest draw.Image, tr MatrixTransform, op draw.Op, filter ImageFilter) {
//width := float64(src.Bounds().Dx())
//height := float64(src.Bounds().Dy())
//tr.InverseTransform(&width, &height)
// TODO: find a x0, y0, x1, y1 that fits into dest 0, width, 0, height is too large
width := float64(dest.Bounds().Dx())
height:= float64(dest.Bounds().Dy())
b := src.Bounds()
x0, y0, x1, y1 := float64(b.Min.X), float64(b.Min.Y), float64(b.Max.X), float64(b.Max.Y)
tr.TransformRectangle(&x0, &y0, &x1, &y1)
var x, y, u, v float64
for x = 0; x < width; x++ {
for y = 0; y < height; y++ {
for x = x0; x < x1; x++ {
for y = y0; y < y1; y++ {
u = x
v = y
tr.InverseTransform(&u, &v)
dest.Set(int(x), int(y), compose(dest.At(int(x), int(y)), getColorLinear(src, u, v)))
c1 := dest.At(int(x), int(y))
var c2 image.Color
switch filter {
case LinearFilter:
c2 = getColorLinear(src, u, v)
case BilinearFilter:
c2 = getColorBilinear(src, u, v)
case BicubicFilter:
c2 = getColorBicubic(src, u, v)
}
var cr image.Color
switch op {
case draw.Over:
r1, g1, b1, a1 := c1.RGBA()
r2, g2, b2, a2 := c2.RGBA()
ia := M - a2
r := ((r1 * ia) / M) + r2
g := ((g1 * ia) / M) + g2
b := ((b1 * ia) / M) + b2
a := ((a1 * ia) / M) + a2
cr = image.RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
default:
cr = c2
}
dest.Set(int(x), int(y), cr)
}
}
}

View File

@ -26,6 +26,23 @@ func (tr MatrixTransform) Transform(points ...*float64) {
}
}
func (tr MatrixTransform) TransformRectangle(x0, y0, x2, y2*float64) {
x1 := *x2
y1 := *y0
x3 := *x0
y3 := *y2
tr.Transform(x0, y0, &x1, &y1, x2, y2, &x3, &y3)
*x0, x1 = minMax(*x0, x1)
*x2, x3 = minMax(*x2, x3)
*y0, y1 = minMax(*y0, y1)
*y2, y3 = minMax(*y2, y3)
*x0 = min(*x0, *x2)
*y0 = min(*y0, *y2)
*x2 = max(x1, x3)
*y2 = max(y1, y3)
}
func (tr MatrixTransform) TransformRasterPoint(points ...*raster.Point) {
for _, point := range points {
x := float64(point.X) / 256

Binary file not shown.

Before

Width:  |  Height:  |  Size: 346 KiB

After

Width:  |  Height:  |  Size: 23 KiB