github.com/dolotech/hongbao@v0.0.0-20191130105438-fd59d7a5dda5/src/utils/imgo/util.go (about)

     1  //package imgo is a golang image process lib
     2  package imgo
     3  
     4  import (
     5  	"bytes"
     6  	"errors"
     7  	"math"
     8  	"image"
     9  	"runtime"
    10  )
    11  
    12  type resamplingFilter struct {
    13  	Support float64
    14  	Kernel  func(float64) float64
    15  }
    16  
    17  
    18  func ResizeForMatrixBytes(filepath []byte, width int, height int)(imgMatrix [][][]uint8 , err error){
    19  	reader:=bytes.NewReader(filepath)
    20  	img, _, err := image.Decode(reader)
    21  	if err != nil {
    22  		return nil,err
    23  	}
    24  
    25  	nrgba:=convertToNRGBA(img)
    26  	src:=Resize(nrgba,width,height)
    27  
    28  	imgMatrix = NewRGBAMatrix(height,width)
    29  
    30  
    31  	for i:=0;i<height;i++{
    32  		for j:=0;j<width;j++{
    33  			c:=src.At(j,i)
    34  			r,g,b,a:=c.RGBA()
    35  			imgMatrix[i][j][0]=uint8(r)
    36  			imgMatrix[i][j][1]=uint8(g)
    37  			imgMatrix[i][j][2]=uint8(b)
    38  			imgMatrix[i][j][3]=uint8(a)
    39  
    40  		}
    41  	}
    42  
    43  	return
    44  }
    45  
    46  func ResizeForMatrix(filepath string, width int, height int)(imgMatrix [][][]uint8 , err error){
    47  	img,err1:=DecodeImage(filepath)
    48  	
    49  	if err1 != nil {
    50  		err = err1
    51  		return
    52  	}
    53  	
    54  	nrgba:=convertToNRGBA(img)
    55  	src:=Resize(nrgba,width,height)
    56  	
    57  	imgMatrix = NewRGBAMatrix(height,width)
    58  	
    59  	
    60  	for i:=0;i<height;i++{
    61  		for j:=0;j<width;j++{
    62  			c:=src.At(j,i)
    63  			r,g,b,a:=c.RGBA()
    64  			imgMatrix[i][j][0]=uint8(r)
    65  			imgMatrix[i][j][1]=uint8(g)
    66  			imgMatrix[i][j][2]=uint8(b)
    67  			imgMatrix[i][j][3]=uint8(a)
    68  			
    69  		}
    70  	}
    71  	
    72  	return
    73  }
    74  
    75  // resize size of image
    76  func Resize(src *image.NRGBA,width int, height int) *image.NRGBA {
    77  	dstW, dstH := width, height
    78  
    79  	if dstW < 0 || dstH < 0 {
    80  		return src
    81  	}
    82  	if dstW == 0 && dstH == 0 {
    83  		return src
    84  	}
    85  
    86  	srcW := src.Rect.Max.X
    87  	srcH := src.Rect.Max.Y
    88  
    89  	if srcW <= 0 || srcH <= 0 {
    90  		return src
    91  	}
    92  
    93  	// if new width or height is 0 then preserve aspect ratio, minimum 1px
    94  	if dstW == 0 {
    95  		tmpW := float64(dstH) * float64(srcW) / float64(srcH)
    96  		dstW = int(math.Max(1.0, math.Floor(tmpW+0.5)))
    97  	}
    98  	if dstH == 0 {
    99  		tmpH := float64(dstW) * float64(srcH) / float64(srcW)
   100  		dstH = int(math.Max(1.0, math.Floor(tmpH+0.5)))
   101  	}
   102  
   103  	var dst *image.NRGBA
   104  	
   105  	var sinc = func(x float64) float64 {
   106  		if x == 0 {
   107  			return 1
   108  		}
   109  		return math.Sin(math.Pi*x) / (math.Pi * x)
   110  	}
   111  	
   112  	var filter resamplingFilter = resamplingFilter{
   113  		Support: 3.0,
   114  		Kernel: func(x float64) float64 {
   115  			x = math.Abs(x)
   116  			if x < 3.0 {
   117  				return sinc(x) * sinc(x/3.0)
   118  			}
   119  			return 0
   120  		},
   121  	}
   122  
   123  	if filter.Support <= 0.0 {
   124  		// nearest-neighbor special case
   125  		dst = resizeNearest(src, dstW, dstH)
   126  
   127  	} else {
   128  		// two-pass resize
   129  		if srcW != dstW {
   130  			dst = resizeHorizontal(src, dstW, filter)
   131  		} else {
   132  			dst = src
   133  		}
   134  
   135  		if srcH != dstH {
   136  			dst = resizeVertical(dst, dstH, filter)
   137  		}
   138  	}
   139  
   140  	return dst
   141  }
   142  
   143  
   144  
   145  
   146  func resizeHorizontal(src *image.NRGBA, width int, filter resamplingFilter) *image.NRGBA {
   147  	srcBounds := src.Bounds()
   148  	srcW := srcBounds.Dx()
   149  	srcH := srcBounds.Dy()
   150  	srcMinX := srcBounds.Min.X
   151  	srcMinY := srcBounds.Min.Y
   152  	srcMaxX := srcBounds.Max.X
   153  
   154  	dstW := width
   155  	dstH := srcH
   156  
   157  	dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
   158  
   159  	dX := float64(srcW) / float64(dstW)
   160  	scaleX := math.Max(dX, 1.0)
   161  	rX := math.Ceil(scaleX * filter.Support)
   162  
   163  	// divide image to parts for parallel processing
   164  	numGoroutines := runtime.NumCPU()
   165  	goMaxProcs := runtime.GOMAXPROCS(0)
   166  	if numGoroutines > goMaxProcs {
   167  		numGoroutines = goMaxProcs
   168  	}
   169  	if numGoroutines > dstW {
   170  		numGoroutines = dstW
   171  	}
   172  	partSize := dstW / numGoroutines
   173  
   174  	doneChan := make(chan bool, numGoroutines)
   175  
   176  	for part := 0; part < numGoroutines; part++ {
   177  		partStart := part * partSize
   178  		partEnd := (part + 1) * partSize
   179  		if part == numGoroutines-1 {
   180  			partEnd = dstW
   181  		}
   182  
   183  		go func(partStart, partEnd int) {
   184  
   185  			for dstX := partStart; dstX < partEnd; dstX++ {
   186  				fX := float64(srcMinX) + (float64(dstX)+0.5)*dX - 0.5
   187  
   188  				startX := int(math.Ceil(fX - rX))
   189  				if startX < srcMinX {
   190  					startX = srcMinX
   191  				}
   192  				endX := int(math.Floor(fX + rX))
   193  				if endX > srcMaxX-1 {
   194  					endX = srcMaxX - 1
   195  				}
   196  
   197  				// cache weights
   198  				weightSum := 0.0
   199  				weights := make([]float64, int(rX+2)*2)
   200  				for x := startX; x <= endX; x++ {
   201  					w := filter.Kernel((float64(x) - fX) / scaleX)
   202  					weightSum += w
   203  					weights[x-startX] = w
   204  				}
   205  
   206  				for dstY := 0; dstY < dstH; dstY++ {
   207  					srcY := srcMinY + dstY
   208  
   209  					r, g, b, a := 0.0, 0.0, 0.0, 0.0
   210  					for x := startX; x <= endX; x++ {
   211  						weight := weights[x-startX]
   212  						i := src.PixOffset(x, srcY)
   213  						r += float64(src.Pix[i+0]) * weight
   214  						g += float64(src.Pix[i+1]) * weight
   215  						b += float64(src.Pix[i+2]) * weight
   216  						a += float64(src.Pix[i+3]) * weight
   217  					}
   218  
   219  					r = math.Min(math.Max(r/weightSum, 0.0), 255.0)
   220  					g = math.Min(math.Max(g/weightSum, 0.0), 255.0)
   221  					b = math.Min(math.Max(b/weightSum, 0.0), 255.0)
   222  					a = math.Min(math.Max(a/weightSum, 0.0), 255.0)
   223  
   224  					j := dst.PixOffset(dstX, dstY)
   225  					dst.Pix[j+0] = uint8(r + 0.5)
   226  					dst.Pix[j+1] = uint8(g + 0.5)
   227  					dst.Pix[j+2] = uint8(b + 0.5)
   228  					dst.Pix[j+3] = uint8(a + 0.5)
   229  				}
   230  			}
   231  
   232  			doneChan <- true
   233  		}(partStart, partEnd)
   234  
   235  	}
   236  
   237  	// wait for goroutines to finish
   238  	for part := 0; part < numGoroutines; part++ {
   239  		<-doneChan
   240  	}
   241  
   242  	return dst
   243  }
   244  
   245  func resizeVertical(src *image.NRGBA, height int, filter resamplingFilter) *image.NRGBA {
   246  	srcBounds := src.Bounds()
   247  	srcW := srcBounds.Dx()
   248  	srcH := srcBounds.Dy()
   249  	srcMinX := srcBounds.Min.X
   250  	srcMinY := srcBounds.Min.Y
   251  	srcMaxY := srcBounds.Max.Y
   252  
   253  	dstW := srcW
   254  	dstH := height
   255  
   256  	dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
   257  
   258  	dY := float64(srcH) / float64(dstH)
   259  	scaleY := math.Max(dY, 1.0)
   260  	rY := math.Ceil(scaleY * filter.Support)
   261  
   262  	// divide image to parts for parallel processing
   263  	numGoroutines := runtime.NumCPU()
   264  	goMaxProcs := runtime.GOMAXPROCS(0)
   265  	if numGoroutines > goMaxProcs {
   266  		numGoroutines = goMaxProcs
   267  	}
   268  	if numGoroutines > dstH {
   269  		numGoroutines = dstH
   270  	}
   271  	partSize := dstH / numGoroutines
   272  
   273  	doneChan := make(chan bool, numGoroutines)
   274  
   275  	for part := 0; part < numGoroutines; part++ {
   276  		partStart := part * partSize
   277  		partEnd := (part + 1) * partSize
   278  		if part == numGoroutines-1 {
   279  			partEnd = dstH
   280  		}
   281  
   282  		go func(partStart, partEnd int) {
   283  
   284  			for dstY := partStart; dstY < partEnd; dstY++ {
   285  				fY := float64(srcMinY) + (float64(dstY)+0.5)*dY - 0.5
   286  
   287  				startY := int(math.Ceil(fY - rY))
   288  				if startY < srcMinY {
   289  					startY = srcMinY
   290  				}
   291  				endY := int(math.Floor(fY + rY))
   292  				if endY > srcMaxY-1 {
   293  					endY = srcMaxY - 1
   294  				}
   295  
   296  				// cache weights
   297  				weightSum := 0.0
   298  				weights := make([]float64, int(rY+2)*2)
   299  				for y := startY; y <= endY; y++ {
   300  					w := filter.Kernel((float64(y) - fY) / scaleY)
   301  					weightSum += w
   302  					weights[y-startY] = w
   303  				}
   304  
   305  				for dstX := 0; dstX < dstW; dstX++ {
   306  					srcX := srcMinX + dstX
   307  
   308  					r, g, b, a := 0.0, 0.0, 0.0, 0.0
   309  					for y := startY; y <= endY; y++ {
   310  						weight := weights[y-startY]
   311  						i := src.PixOffset(srcX, y)
   312  						r += float64(src.Pix[i+0]) * weight
   313  						g += float64(src.Pix[i+1]) * weight
   314  						b += float64(src.Pix[i+2]) * weight
   315  						a += float64(src.Pix[i+3]) * weight
   316  					}
   317  
   318  					r = math.Min(math.Max(r/weightSum, 0.0), 255.0)
   319  					g = math.Min(math.Max(g/weightSum, 0.0), 255.0)
   320  					b = math.Min(math.Max(b/weightSum, 0.0), 255.0)
   321  					a = math.Min(math.Max(a/weightSum, 0.0), 255.0)
   322  
   323  					j := dst.PixOffset(dstX, dstY)
   324  					dst.Pix[j+0] = uint8(r + 0.5)
   325  					dst.Pix[j+1] = uint8(g + 0.5)
   326  					dst.Pix[j+2] = uint8(b + 0.5)
   327  					dst.Pix[j+3] = uint8(a + 0.5)
   328  				}
   329  			}
   330  
   331  			doneChan <- true
   332  		}(partStart, partEnd)
   333  
   334  	}
   335  
   336  	// wait for goroutines to finish
   337  	for part := 0; part < numGoroutines; part++ {
   338  		<-doneChan
   339  	}
   340  
   341  	return dst
   342  }
   343  
   344  // fast nearest-neighbor resize, no filtering
   345  func resizeNearest(src *image.NRGBA, width, height int) *image.NRGBA {
   346  	dstW, dstH := width, height
   347  
   348  	srcBounds := src.Bounds()
   349  	srcW := srcBounds.Dx()
   350  	srcH := srcBounds.Dy()
   351  	srcMinX := srcBounds.Min.X
   352  	srcMinY := srcBounds.Min.Y
   353  	srcMaxX := srcBounds.Max.X
   354  	srcMaxY := srcBounds.Max.Y
   355  
   356  	dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
   357  
   358  	dx := float64(srcW) / float64(dstW)
   359  	dy := float64(srcH) / float64(dstH)
   360  
   361  	// divide image to parts for parallel processing
   362  	numGoroutines := runtime.NumCPU()
   363  	goMaxProcs := runtime.GOMAXPROCS(0)
   364  	if numGoroutines > goMaxProcs {
   365  		numGoroutines = goMaxProcs
   366  	}
   367  	if numGoroutines > dstH {
   368  		numGoroutines = dstH
   369  	}
   370  	partSize := dstH / numGoroutines
   371  
   372  	doneChan := make(chan bool, numGoroutines)
   373  
   374  	for part := 0; part < numGoroutines; part++ {
   375  		partStart := part * partSize
   376  		partEnd := (part + 1) * partSize
   377  		if part == numGoroutines-1 {
   378  			partEnd = dstH
   379  		}
   380  
   381  		go func(partStart, partEnd int) {
   382  
   383  			for dstY := partStart; dstY < partEnd; dstY++ {
   384  				fy := float64(srcMinY) + (float64(dstY)+0.5)*dy - 0.5
   385  
   386  				for dstX := 0; dstX < dstW; dstX++ {
   387  					fx := float64(srcMinX) + (float64(dstX)+0.5)*dx - 0.5
   388  
   389  					srcX := int(math.Min(math.Max(math.Floor(fx+0.5), float64(srcMinX)), float64(srcMaxX)))
   390  					srcY := int(math.Min(math.Max(math.Floor(fy+0.5), float64(srcMinY)), float64(srcMaxY)))
   391  
   392  					srcOffset := src.PixOffset(srcX, srcY)
   393  					dstOffset := dst.PixOffset(dstX, dstY)
   394  
   395  					dst.Pix[dstOffset+0] = src.Pix[srcOffset+0]
   396  					dst.Pix[dstOffset+1] = src.Pix[srcOffset+1]
   397  					dst.Pix[dstOffset+2] = src.Pix[srcOffset+2]
   398  					dst.Pix[dstOffset+3] = src.Pix[srcOffset+3]
   399  				}
   400  			}
   401  
   402  			doneChan <- true
   403  		}(partStart, partEnd)
   404  	}
   405  
   406  	// wait for goroutines to finish
   407  	for part := 0; part < numGoroutines; part++ {
   408  		<-doneChan
   409  	}
   410  
   411  	return dst
   412  }
   413  
   414  // create a three dimenson slice
   415  func New3DSlice(x int , y int , z int)(theSlice [][][]uint8){
   416  	theSlice = make([][][]uint8,x,x)
   417  	for i := 0; i < x; i++ {
   418          s2 := make([][]uint8, y, y) 
   419          for j:=0 ; j < y; j++ {
   420  			s3 := make([]uint8,z,z)
   421  			s2[j] = s3 
   422  		}
   423  		theSlice[i] = s2  
   424      }
   425  	return 
   426  }
   427  
   428  // create a new rgba matrix
   429  func NewRGBAMatrix(height int,width int)(rgbaMatrix [][][]uint8){
   430  	rgbaMatrix = New3DSlice(height,width,4)
   431  	return
   432  }
   433  
   434  func Matrix2Vector(imgMatrix [][][]uint8)(vector []uint8){
   435  	h:=len(imgMatrix)
   436  	w:=len(imgMatrix[0])
   437  	r:=len(imgMatrix[0][0])
   438  	length:=h*w*r
   439  	
   440  	vector = make([]uint8,length)
   441  	
   442  	for i:=0; i<h; i++ {
   443  		for j:=0; j<w; j++ {
   444  			for k:=0; k<r-1; k++ {
   445  				vector = append(vector,imgMatrix[i][j][k])
   446  			}
   447  		}
   448  	}
   449  	return
   450  }
   451  
   452  func Dot(x []uint8, y []uint8) float64 {
   453  	xlen:=len(x)
   454  	
   455  	var sum float64 = 0
   456  	for i:=0; i<xlen; i++ {
   457  			sum = sum + float64(x[i])*float64(y[i])
   458  			
   459  	}
   460  	return sum
   461  }
   462  
   463  type IterFunc func(i int, j int, k int, src [][][]uint8)[][][]uint8
   464  
   465  func Iterator(filepath string, iter IterFunc)(imgMatrix [][][]uint8, err error ){
   466  	imgMatrix,err = Read(filepath)
   467  	if err != nil {
   468  		return 
   469  	}
   470  	
   471  	height:=len(imgMatrix)
   472  	width:=len(imgMatrix[0])
   473  	pix:=len(imgMatrix[0][0])
   474  	if height == 0 || width == 0 {
   475  		err = errors.New("The input of matrix is illegal!")
   476  		return
   477  	}
   478  	
   479  	for i:=0; i<height; i++ {
   480  		for j:=0; j<width; j++ {
   481  			for k:=0; k<pix; k++ {
   482  				imgMatrix = iter(i,j,k,imgMatrix)
   483  			}
   484  		}
   485  	}
   486  	return
   487  }