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 }