github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/image/draw/draw_pyrdown_average.go (about)

     1  // Copyright 2014 <chaishushan{AT}gmail.com>. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package draw
     6  
     7  import (
     8  	"image"
     9  	"image/color"
    10  	"image/draw"
    11  	"reflect"
    12  
    13  	"github.com/chai2010/gopkg/builtin"
    14  	image_ext "github.com/chai2010/gopkg/image"
    15  	color_ext "github.com/chai2010/gopkg/image/color"
    16  )
    17  
    18  func drawPyrDownGray_Average(dst *image.Gray, r image.Rectangle, src image.Image, sp image.Point) {
    19  	switch src := src.(type) {
    20  	case *image.Gray:
    21  		// 64 is a magic, see go test -bench=.
    22  		if r.Dx() >= 64 && r.In(dst.Bounds()) && image.Rect(sp.X, sp.Y, sp.X+r.Dx()*2, sp.Y+r.Dy()*2).In(src.Bounds()) {
    23  			drawPyrDownGray_Average_fast(dst, r, src, sp)
    24  			return
    25  		}
    26  		drawPyrDownGray_Average_slow(dst, r, src, sp)
    27  		return
    28  	default:
    29  		drawPyrDown_Average(dst, r, src, sp)
    30  	}
    31  }
    32  
    33  func drawPyrDownGray_Average_slow(dst *image.Gray, r image.Rectangle, src *image.Gray, sp image.Point) {
    34  	for y := r.Min.Y; y < r.Max.Y; y++ {
    35  		for x := r.Min.X; x < r.Max.X; x++ {
    36  			x0 := (x-r.Min.X)*2 + sp.X
    37  			y0 := (y-r.Min.Y)*2 + sp.Y
    38  
    39  			y00 := uint16(src.GrayAt(x0+0, y0+0).Y)
    40  			y01 := uint16(src.GrayAt(x0+0, y0+1).Y)
    41  			y11 := uint16(src.GrayAt(x0+1, y0+1).Y)
    42  			y10 := uint16(src.GrayAt(x0+1, y0+0).Y)
    43  
    44  			dst.SetGray(x, y, color.Gray{
    45  				Y: uint8((y00 + y01 + y11 + y10) / 4),
    46  			})
    47  		}
    48  	}
    49  }
    50  
    51  func drawPyrDownGray_Average_fast(dst *image.Gray, r image.Rectangle, src *image.Gray, sp image.Point) {
    52  	off0 := dst.PixOffset(r.Min.X, r.Min.Y)
    53  	off1 := src.PixOffset(sp.X, sp.Y)
    54  	off2 := off1 + src.Stride
    55  
    56  	if padding := r.Dx() % 4; padding != 0 {
    57  		for y := r.Min.Y; y < r.Max.Y; y++ {
    58  			dstLineX := builtin.Slice(dst.Pix[off0:][:r.Dx()*1], reflect.TypeOf([]uint32(nil))).([]uint32)
    59  			srcLine0 := builtin.Slice(src.Pix[off1:][:r.Dx()*2], reflect.TypeOf([]uint32(nil))).([]uint32)
    60  			srcLine1 := builtin.Slice(src.Pix[off2:][:r.Dx()*2], reflect.TypeOf([]uint32(nil))).([]uint32)
    61  
    62  			i, j := 0, 0
    63  			for ; i < len(dstLineX); i++ {
    64  				dstLineX[i] = mergeRgbaFast(
    65  					mergeRgbaFast(srcLine0[j+0], srcLine0[j+1]),
    66  					mergeRgbaFast(srcLine1[j+0], srcLine1[j+1]),
    67  				)
    68  				j += 2
    69  			}
    70  			for k := 0; k < padding; k++ {
    71  				y00 := uint16(src.Pix[off1:][j*4+k*2+0])
    72  				y01 := uint16(src.Pix[off1:][j*4+k*2+1])
    73  				y11 := uint16(src.Pix[off2:][j*4+k*2+1])
    74  				y10 := uint16(src.Pix[off2:][j*4+k*2+0])
    75  				dst.Pix[off0:][i*4+k] = uint8((y00 + y01 + y11 + y10) / 4)
    76  			}
    77  			off0 += dst.Stride * 1
    78  			off1 += src.Stride * 2
    79  			off2 += src.Stride * 2
    80  		}
    81  	} else {
    82  		for y := r.Min.Y; y < r.Max.Y; y++ {
    83  			dstLineX := builtin.Slice(dst.Pix[off0:][:r.Dx()*1], reflect.TypeOf([]uint32(nil))).([]uint32)
    84  			srcLine0 := builtin.Slice(src.Pix[off1:][:r.Dx()*2], reflect.TypeOf([]uint32(nil))).([]uint32)
    85  			srcLine1 := builtin.Slice(src.Pix[off2:][:r.Dx()*2], reflect.TypeOf([]uint32(nil))).([]uint32)
    86  
    87  			for i, j := 0, 0; i < len(dstLineX); i, j = i+1, j+2 {
    88  				dstLineX[i] = mergeRgbaFast(
    89  					mergeRgbaFast(srcLine0[j+0], srcLine0[j+1]),
    90  					mergeRgbaFast(srcLine1[j+0], srcLine1[j+1]),
    91  				)
    92  			}
    93  			off0 += dst.Stride * 1
    94  			off1 += src.Stride * 2
    95  			off2 += src.Stride * 2
    96  		}
    97  	}
    98  }
    99  
   100  func drawPyrDownGray16_Average(dst *image.Gray16, r image.Rectangle, src image.Image, sp image.Point) {
   101  	switch src := src.(type) {
   102  	case *image.Gray16:
   103  		for y := r.Min.Y; y < r.Max.Y; y++ {
   104  			for x := r.Min.X; x < r.Max.X; x++ {
   105  				x0 := (x-r.Min.X)*2 + sp.X
   106  				y0 := (y-r.Min.Y)*2 + sp.Y
   107  
   108  				y00 := uint32(src.Gray16At(x0+0, y0+0).Y)
   109  				y01 := uint32(src.Gray16At(x0+0, y0+1).Y)
   110  				y11 := uint32(src.Gray16At(x0+1, y0+1).Y)
   111  				y10 := uint32(src.Gray16At(x0+1, y0+0).Y)
   112  
   113  				dst.SetGray16(x, y, color.Gray16{
   114  					Y: uint16((y00 + y01 + y11 + y10) / 4),
   115  				})
   116  			}
   117  		}
   118  	default:
   119  		drawPyrDown_Average(dst, r, src, sp)
   120  	}
   121  }
   122  
   123  func drawPyrDownGray32f_Average(dst *image_ext.Gray32f, r image.Rectangle, src image.Image, sp image.Point) {
   124  	switch src := src.(type) {
   125  	case *image_ext.Gray32f:
   126  		for y := r.Min.Y; y < r.Max.Y; y++ {
   127  			for x := r.Min.X; x < r.Max.X; x++ {
   128  				x0 := (x-r.Min.X)*2 + sp.X
   129  				y0 := (y-r.Min.Y)*2 + sp.Y
   130  
   131  				y00 := src.Gray32fAt(x0+0, y0+0).Y
   132  				y01 := src.Gray32fAt(x0+0, y0+1).Y
   133  				y11 := src.Gray32fAt(x0+1, y0+1).Y
   134  				y10 := src.Gray32fAt(x0+1, y0+0).Y
   135  
   136  				dst.SetGray32f(x, y, color_ext.Gray32f{
   137  					Y: (y00 + y01 + y11 + y10) / 4,
   138  				})
   139  			}
   140  		}
   141  	default:
   142  		drawPyrDown_Average(dst, r, src, sp)
   143  	}
   144  }
   145  
   146  func drawPyrDownRGB_Average(dst *image_ext.RGB, r image.Rectangle, src image.Image, sp image.Point) {
   147  	switch src := src.(type) {
   148  	case *image_ext.RGB:
   149  		for y := r.Min.Y; y < r.Max.Y; y++ {
   150  			for x := r.Min.X; x < r.Max.X; x++ {
   151  				x0 := (x-r.Min.X)*2 + sp.X
   152  				y0 := (y-r.Min.Y)*2 + sp.Y
   153  
   154  				rgb00 := src.RGBAt(x0+0, y0+0)
   155  				rgb01 := src.RGBAt(x0+0, y0+1)
   156  				rgb11 := src.RGBAt(x0+1, y0+1)
   157  				rgb10 := src.RGBAt(x0+1, y0+0)
   158  
   159  				dst.SetRGB(x, y, color_ext.RGB{
   160  					R: uint8((uint16(rgb00.R) + uint16(rgb01.R) + uint16(rgb11.R) + uint16(rgb10.R)) / 4),
   161  					G: uint8((uint16(rgb00.G) + uint16(rgb01.G) + uint16(rgb11.G) + uint16(rgb10.G)) / 4),
   162  					B: uint8((uint16(rgb00.B) + uint16(rgb01.B) + uint16(rgb11.B) + uint16(rgb10.B)) / 4),
   163  				})
   164  			}
   165  		}
   166  		return
   167  	default:
   168  		drawPyrDown_Average(dst, r, src, sp)
   169  		return
   170  	}
   171  }
   172  
   173  func drawPyrDownRGB48_Average(dst *image_ext.RGB48, r image.Rectangle, src image.Image, sp image.Point) {
   174  	switch src := src.(type) {
   175  	case *image_ext.RGB48:
   176  		for y := r.Min.Y; y < r.Max.Y; y++ {
   177  			for x := r.Min.X; x < r.Max.X; x++ {
   178  				x0 := (x-r.Min.X)*2 + sp.X
   179  				y0 := (y-r.Min.Y)*2 + sp.Y
   180  
   181  				rgb00 := src.RGB48At(x0+0, y0+0)
   182  				rgb01 := src.RGB48At(x0+0, y0+1)
   183  				rgb11 := src.RGB48At(x0+1, y0+1)
   184  				rgb10 := src.RGB48At(x0+1, y0+0)
   185  
   186  				dst.SetRGB48(x, y, color_ext.RGB48{
   187  					R: uint16((uint32(rgb00.R) + uint32(rgb01.R) + uint32(rgb11.R) + uint32(rgb10.R)) / 4),
   188  					G: uint16((uint32(rgb00.G) + uint32(rgb01.G) + uint32(rgb11.G) + uint32(rgb10.G)) / 4),
   189  					B: uint16((uint32(rgb00.B) + uint32(rgb01.B) + uint32(rgb11.B) + uint32(rgb10.B)) / 4),
   190  				})
   191  			}
   192  		}
   193  	default:
   194  		drawPyrDown_Average(dst, r, src, sp)
   195  	}
   196  }
   197  
   198  func drawPyrDownRGB96f_Average(dst *image_ext.RGB96f, r image.Rectangle, src image.Image, sp image.Point) {
   199  	switch src := src.(type) {
   200  	case *image_ext.RGB96f:
   201  		for y := r.Min.Y; y < r.Max.Y; y++ {
   202  			for x := r.Min.X; x < r.Max.X; x++ {
   203  				x0 := (x-r.Min.X)*2 + sp.X
   204  				y0 := (y-r.Min.Y)*2 + sp.Y
   205  
   206  				rgb00 := src.RGB96fAt(x0+0, y0+0)
   207  				rgb01 := src.RGB96fAt(x0+0, y0+1)
   208  				rgb11 := src.RGB96fAt(x0+1, y0+1)
   209  				rgb10 := src.RGB96fAt(x0+1, y0+0)
   210  
   211  				dst.SetRGB96f(x, y, color_ext.RGB96f{
   212  					R: (rgb00.R + rgb01.R + rgb11.R + rgb10.R) / 4,
   213  					G: (rgb00.G + rgb01.G + rgb11.G + rgb10.G) / 4,
   214  					B: (rgb00.B + rgb01.B + rgb11.B + rgb10.B) / 4,
   215  				})
   216  			}
   217  		}
   218  	default:
   219  		drawPyrDown_Average(dst, r, src, sp)
   220  	}
   221  }
   222  
   223  func drawPyrDownRGBA_Average(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Point) {
   224  	switch src := src.(type) {
   225  	case *image.RGBA:
   226  		// 32 is a magic, see go test -bench=.
   227  		if r.Dx() >= 32 && r.In(dst.Bounds()) && image.Rect(sp.X, sp.Y, sp.X+r.Dx()*2, sp.Y+r.Dy()*2).In(src.Bounds()) {
   228  			drawPyrDownRGBA_Average_fast(dst, r, src, sp)
   229  			return
   230  		}
   231  		drawPyrDownRGBA_Average_slow(dst, r, src, sp)
   232  		return
   233  	default:
   234  		drawPyrDown_Average(dst, r, src, sp)
   235  		return
   236  	}
   237  }
   238  
   239  func drawPyrDownRGBA_Average_slow(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
   240  	for y := r.Min.Y; y < r.Max.Y; y++ {
   241  		for x := r.Min.X; x < r.Max.X; x++ {
   242  			x0 := (x-r.Min.X)*2 + sp.X
   243  			y0 := (y-r.Min.Y)*2 + sp.Y
   244  
   245  			rgba00 := src.RGBAAt(x0+0, y0+0)
   246  			rgba01 := src.RGBAAt(x0+0, y0+1)
   247  			rgba11 := src.RGBAAt(x0+1, y0+1)
   248  			rgba10 := src.RGBAAt(x0+1, y0+0)
   249  
   250  			dst.SetRGBA(x, y, color.RGBA{
   251  				R: uint8((uint16(rgba00.R) + uint16(rgba01.R) + uint16(rgba11.R) + uint16(rgba10.R)) / 4),
   252  				G: uint8((uint16(rgba00.G) + uint16(rgba01.G) + uint16(rgba11.G) + uint16(rgba10.G)) / 4),
   253  				B: uint8((uint16(rgba00.B) + uint16(rgba01.B) + uint16(rgba11.B) + uint16(rgba10.B)) / 4),
   254  				A: uint8((uint16(rgba00.A) + uint16(rgba01.A) + uint16(rgba11.A) + uint16(rgba10.A)) / 4),
   255  			})
   256  		}
   257  	}
   258  }
   259  
   260  func drawPyrDownRGBA_Average_fast(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
   261  	off0 := dst.PixOffset(r.Min.X, r.Min.Y)
   262  	off1 := src.PixOffset(sp.X, sp.Y)
   263  	off2 := off1 + src.Stride
   264  
   265  	for y := r.Min.Y; y < r.Max.Y; y++ {
   266  		dstLineX := builtin.Slice(dst.Pix[off0:][:r.Dx()*4], reflect.TypeOf([]uint32(nil))).([]uint32)
   267  		srcLine0 := builtin.Slice(src.Pix[off1:][:r.Dx()*8], reflect.TypeOf([]uint32(nil))).([]uint32)
   268  		srcLine1 := builtin.Slice(src.Pix[off2:][:r.Dx()*8], reflect.TypeOf([]uint32(nil))).([]uint32)
   269  
   270  		for i, j := 0, 0; i < len(dstLineX); i, j = i+1, j+2 {
   271  			dstLineX[i] = mergeRgbaFast(
   272  				mergeRgbaFast(srcLine0[j+0], srcLine0[j+1]),
   273  				mergeRgbaFast(srcLine1[j+0], srcLine1[j+1]),
   274  			)
   275  		}
   276  		off0 += dst.Stride * 1
   277  		off1 += src.Stride * 2
   278  		off2 += src.Stride * 2
   279  	}
   280  }
   281  
   282  func drawPyrDownRGBA64_Average(dst *image.RGBA64, r image.Rectangle, src image.Image, sp image.Point) {
   283  	switch src := src.(type) {
   284  	case *image.RGBA64:
   285  		for y := r.Min.Y; y < r.Max.Y; y++ {
   286  			for x := r.Min.X; x < r.Max.X; x++ {
   287  				x0 := (x-r.Min.X)*2 + sp.X
   288  				y0 := (y-r.Min.Y)*2 + sp.Y
   289  
   290  				rgba00 := src.RGBA64At(x0+0, y0+0)
   291  				rgba01 := src.RGBA64At(x0+0, y0+1)
   292  				rgba11 := src.RGBA64At(x0+1, y0+1)
   293  				rgba10 := src.RGBA64At(x0+1, y0+0)
   294  
   295  				dst.SetRGBA64(x, y, color.RGBA64{
   296  					R: uint16((uint32(rgba00.R) + uint32(rgba01.R) + uint32(rgba11.R) + uint32(rgba10.R)) / 4),
   297  					G: uint16((uint32(rgba00.G) + uint32(rgba01.G) + uint32(rgba11.G) + uint32(rgba10.G)) / 4),
   298  					B: uint16((uint32(rgba00.B) + uint32(rgba01.B) + uint32(rgba11.B) + uint32(rgba10.B)) / 4),
   299  					A: uint16((uint32(rgba00.A) + uint32(rgba01.A) + uint32(rgba11.A) + uint32(rgba10.A)) / 4),
   300  				})
   301  			}
   302  		}
   303  	default:
   304  		drawPyrDown_Average(dst, r, src, sp)
   305  	}
   306  }
   307  
   308  func drawPyrDownRGBA128f_Average(dst *image_ext.RGBA128f, r image.Rectangle, src image.Image, sp image.Point) {
   309  	switch src := src.(type) {
   310  	case *image_ext.RGBA128f:
   311  		for y := r.Min.Y; y < r.Max.Y; y++ {
   312  			for x := r.Min.X; x < r.Max.X; x++ {
   313  				x0 := (x-r.Min.X)*2 + sp.X
   314  				y0 := (y-r.Min.Y)*2 + sp.Y
   315  
   316  				rgba00 := src.RGBA128fAt(x0+0, y0+0)
   317  				rgba01 := src.RGBA128fAt(x0+0, y0+1)
   318  				rgba11 := src.RGBA128fAt(x0+1, y0+1)
   319  				rgba10 := src.RGBA128fAt(x0+1, y0+0)
   320  
   321  				dst.SetRGBA128f(x, y, color_ext.RGBA128f{
   322  					R: (rgba00.R + rgba01.R + rgba11.R + rgba10.R) / 4,
   323  					G: (rgba00.G + rgba01.G + rgba11.G + rgba10.G) / 4,
   324  					B: (rgba00.B + rgba01.B + rgba11.B + rgba10.B) / 4,
   325  					A: (rgba00.A + rgba01.A + rgba11.A + rgba10.A) / 4,
   326  				})
   327  			}
   328  		}
   329  	default:
   330  		drawPyrDown_Average(dst, r, src, sp)
   331  	}
   332  }
   333  
   334  func drawPyrDownYCbCr_Average(dst *yCbCr, r image.Rectangle, src image.Image, sp image.Point) {
   335  	drawPyrDown_Average(dst, r, src, sp)
   336  }
   337  
   338  func drawPyrDown_Average(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
   339  	for y := r.Min.Y; y < r.Max.Y; y++ {
   340  		for x := r.Min.X; x < r.Max.X; x++ {
   341  			x0 := (x-r.Min.X)*2 + sp.X
   342  			y0 := (y-r.Min.Y)*2 + sp.Y
   343  
   344  			r00, g00, b00, a00 := src.At(x0+0, y0+0).RGBA()
   345  			r01, g01, b01, a01 := src.At(x0+0, y0+1).RGBA()
   346  			r11, g11, b11, a11 := src.At(x0+1, y0+1).RGBA()
   347  			r10, g10, b10, a10 := src.At(x0+1, y0+0).RGBA()
   348  
   349  			dst.Set(x, y, color.RGBA64{
   350  				R: uint16((r00 + r01 + r11 + r10) / 4),
   351  				G: uint16((g00 + g01 + g11 + g10) / 4),
   352  				B: uint16((b00 + b01 + b11 + b10) / 4),
   353  				A: uint16((a00 + a01 + a11 + a10) / 4),
   354  			})
   355  		}
   356  	}
   357  }