pkg/images/resize: use golang.org/x/image/draw for YCbCr

Later, we should look into using it for more cases. First, to see if we
can phase "halving in place" out, and also to see the gains with other
image types (non YCbCr).

Change-Id: I4b95e2039407f1a91e04cb502674819f17680e02
This commit is contained in:
mpl 2015-09-05 01:03:09 +02:00
parent 710a4236ee
commit fc890a65cd
3 changed files with 6 additions and 97 deletions

View File

@ -47,16 +47,6 @@ func BenchmarkHalveRGBA(b *testing.B) {
}
func BenchmarkResizeYCrCb(b *testing.B) {
withXDraw = false
m := image.NewYCbCr(orig, image.YCbCrSubsampleRatio422)
b.ResetTimer()
for i := 0; i < b.N; i++ {
resize(m)
}
}
func BenchmarkNewResizeYCrCb(b *testing.B) {
withXDraw = true
m := image.NewYCbCr(orig, image.YCbCrSubsampleRatio422)
b.ResetTimer()
for i := 0; i < b.N; i++ {

View File

@ -116,73 +116,12 @@ func average(sum []uint64, w, h int, n uint64) image.Image {
return ret
}
// TODO(mpl): it will be gone in next commit
// it is just to control whether we use Scale from golang.org/x/image/draw in tests/benchs,
// so we have a good commit history showing it was justified to switch to using it.
var withXDraw = false
// resizeYCbCr returns a scaled copy of the YCbCr image slice r of m.
// The returned image has width w and height h.
func resizeYCbCr(m *image.YCbCr, r image.Rectangle, w, h int) (image.Image, bool) {
if withXDraw {
dst := image.NewRGBA(image.Rect(0, 0, w, h))
xdraw.ApproxBiLinear.Scale(dst, dst.Bounds(), m, m.Bounds(), xdraw.Src, nil)
return dst, true
}
var verticalRes int
switch m.SubsampleRatio {
case image.YCbCrSubsampleRatio420:
verticalRes = 2
case image.YCbCrSubsampleRatio422:
verticalRes = 1
default:
// TODO(wathiede, mpl): add 410 and 411 support ?
return nil, false
}
ww, hh := uint64(w), uint64(h)
dx, dy := uint64(r.Dx()), uint64(r.Dy())
// See comment in Resize.
n, sum := dx*dy, make([]uint64, 4*w*h)
for y := r.Min.Y; y < r.Max.Y; y++ {
Y := m.Y[y*m.YStride:]
Cb := m.Cb[y/verticalRes*m.CStride:]
Cr := m.Cr[y/verticalRes*m.CStride:]
for x := r.Min.X; x < r.Max.X; x++ {
// Get the source pixel.
r8, g8, b8 := color.YCbCrToRGB(Y[x], Cb[x/2], Cr[x/2])
r64 := uint64(r8)
g64 := uint64(g8)
b64 := uint64(b8)
// Spread the source pixel over 1 or more destination rows.
py := uint64(y-r.Min.Y) * hh
for remy := hh; remy > 0; {
qy := dy - (py % dy)
if qy > remy {
qy = remy
}
// Spread the source pixel over 1 or more destination columns.
px := uint64(x-r.Min.X) * ww
index := 4 * ((py/dy)*ww + (px / dx))
for remx := ww; remx > 0; {
qx := dx - (px % dx)
if qx > remx {
qx = remx
}
qxy := qx * qy
sum[index+0] += r64 * qxy
sum[index+1] += g64 * qxy
sum[index+2] += b64 * qxy
sum[index+3] += 0xFFFF * qxy
index += 4
px += qx
remx -= qx
}
py += qy
remy -= qy
}
}
}
return average(sum, w, h, n), true
dst := image.NewRGBA(image.Rect(0, 0, w, h))
xdraw.ApproxBiLinear.Scale(dst, dst.Bounds(), m, m.Bounds(), xdraw.Src, nil)
return dst, true
}
// resizeRGBA returns a scaled copy of the RGBA image slice r of m.

View File

@ -270,41 +270,21 @@ func getFilename(im image.Image, method string) string {
return fmt.Sprintf("%s.%s.png", imgType, method)
}
func TestCompareOldResizeToHalveInplace(t *testing.T) {
if testing.Short() {
t.Skip("Skipping TestCompareOldResizeToHalveInplace in short mode.")
}
testCompareResizeMethods(t, "customResize", "halveInPlace")
}
func TestCompareNewResizeToHalveInplace(t *testing.T) {
func TestCompareResizeToHalveInplace(t *testing.T) {
if testing.Short() {
t.Skip("Skipping TestCompareNewResizeToHalveInplace in short mode.")
}
testCompareResizeMethods(t, "xDraw", "halveInPlace")
}
func TestCompareOldResizeToNewResize(t *testing.T) {
if testing.Short() {
t.Skip("Skipping TestCompareOldResizeToNewResize in short mode.")
}
testCompareResizeMethods(t, "customResize", "xDraw")
testCompareResizeMethods(t, "resize", "halveInPlace")
}
var resizeMethods = map[string]func(image.Image) image.Image{
"customResize": func(im image.Image) image.Image {
withXDraw = false
"resize": func(im image.Image) image.Image {
s := im.Bounds().Size()
return Resize(im, im.Bounds(), s.X/2, s.Y/2)
},
"halveInPlace": func(im image.Image) image.Image {
return HalveInplace(im)
},
"xDraw": func(im image.Image) image.Image {
withXDraw = true
s := im.Bounds().Size()
return Resize(im, im.Bounds(), s.X/2, s.Y/2)
},
}
func testCompareResizeMethods(t *testing.T, method1, method2 string) {