Selaa lähdekoodia

performance improvements

Grigory Dryapak 6 vuotta sitten
vanhempi
commit
791d8b4e28
8 muutettua tiedostoa jossa 133 lisäystä ja 119 poistoa
  1. 25 20
      adjust.go
  2. 9 0
      adjust_test.go
  3. 9 7
      convolution.go
  4. 25 29
      effects.go
  5. 4 3
      histogram.go
  6. 15 13
      tools.go
  7. 40 43
      transform.go
  8. 6 4
      utils.go

+ 25 - 20
adjust.go

@@ -15,14 +15,15 @@ func Grayscale(img image.Image) *image.NRGBA {
 			i := y * dst.Stride
 			src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4])
 			for x := 0; x < src.w; x++ {
-				r := dst.Pix[i+0]
-				g := dst.Pix[i+1]
-				b := dst.Pix[i+2]
+				d := dst.Pix[i : i+3 : i+3]
+				r := d[0]
+				g := d[1]
+				b := d[2]
 				f := 0.299*float64(r) + 0.587*float64(g) + 0.114*float64(b)
 				y := uint8(f + 0.5)
-				dst.Pix[i+0] = y
-				dst.Pix[i+1] = y
-				dst.Pix[i+2] = y
+				d[0] = y
+				d[1] = y
+				d[2] = y
 				i += 4
 			}
 		}
@@ -39,9 +40,10 @@ func Invert(img image.Image) *image.NRGBA {
 			i := y * dst.Stride
 			src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4])
 			for x := 0; x < src.w; x++ {
-				dst.Pix[i+0] = 255 - dst.Pix[i+0]
-				dst.Pix[i+1] = 255 - dst.Pix[i+1]
-				dst.Pix[i+2] = 255 - dst.Pix[i+2]
+				d := dst.Pix[i : i+3 : i+3]
+				d[0] = 255 - d[0]
+				d[1] = 255 - d[1]
+				d[2] = 255 - d[2]
 				i += 4
 			}
 		}
@@ -191,14 +193,16 @@ func sigmoid(a, b, x float64) float64 {
 func adjustLUT(img image.Image, lut []uint8) *image.NRGBA {
 	src := newScanner(img)
 	dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
+	lut = lut[0:256]
 	parallel(0, src.h, func(ys <-chan int) {
 		for y := range ys {
 			i := y * dst.Stride
 			src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4])
 			for x := 0; x < src.w; x++ {
-				dst.Pix[i+0] = lut[dst.Pix[i+0]]
-				dst.Pix[i+1] = lut[dst.Pix[i+1]]
-				dst.Pix[i+2] = lut[dst.Pix[i+2]]
+				d := dst.Pix[i : i+3 : i+3]
+				d[0] = lut[d[0]]
+				d[1] = lut[d[1]]
+				d[2] = lut[d[2]]
 				i += 4
 			}
 		}
@@ -230,15 +234,16 @@ func AdjustFunc(img image.Image, fn func(c color.NRGBA) color.NRGBA) *image.NRGB
 			i := y * dst.Stride
 			src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4])
 			for x := 0; x < src.w; x++ {
-				r := dst.Pix[i+0]
-				g := dst.Pix[i+1]
-				b := dst.Pix[i+2]
-				a := dst.Pix[i+3]
+				d := dst.Pix[i : i+4 : i+4]
+				r := d[0]
+				g := d[1]
+				b := d[2]
+				a := d[3]
 				c := fn(color.NRGBA{r, g, b, a})
-				dst.Pix[i+0] = c.R
-				dst.Pix[i+1] = c.G
-				dst.Pix[i+2] = c.B
-				dst.Pix[i+3] = c.A
+				d[0] = c.R
+				d[1] = c.G
+				d[2] = c.B
+				d[3] = c.A
 				i += 4
 			}
 		}

+ 9 - 0
adjust_test.go

@@ -820,3 +820,12 @@ func TestAdjustFunc(t *testing.T) {
 		})
 	}
 }
+
+func BenchmarkAdjustFunc(b *testing.B) {
+	b.ReportAllocs()
+	for i := 0; i < b.N; i++ {
+		AdjustFunc(testdataBranchesJPG, func(c color.NRGBA) color.NRGBA {
+			return color.NRGBA{c.B, c.G, c.R, c.A}
+		})
+	}
+}

+ 9 - 7
convolution.go

@@ -90,9 +90,10 @@ func convolve(img image.Image, kernel []float64, options *ConvolveOptions) *imag
 					}
 
 					off := iy*src.Stride + ix*4
-					r += float64(src.Pix[off+0]) * c.k
-					g += float64(src.Pix[off+1]) * c.k
-					b += float64(src.Pix[off+2]) * c.k
+					s := src.Pix[off : off+3 : off+3]
+					r += float64(s[0]) * c.k
+					g += float64(s[1]) * c.k
+					b += float64(s[2]) * c.k
 				}
 
 				if options.Abs {
@@ -115,10 +116,11 @@ func convolve(img image.Image, kernel []float64, options *ConvolveOptions) *imag
 
 				srcOff := y*src.Stride + x*4
 				dstOff := y*dst.Stride + x*4
-				dst.Pix[dstOff+0] = clamp(r)
-				dst.Pix[dstOff+1] = clamp(g)
-				dst.Pix[dstOff+2] = clamp(b)
-				dst.Pix[dstOff+3] = src.Pix[srcOff+3]
+				d := dst.Pix[dstOff : dstOff+4 : dstOff+4]
+				d[0] = clamp(r)
+				d[1] = clamp(g)
+				d[2] = clamp(b)
+				d[3] = src.Pix[srcOff+3]
 			}
 		}
 	})

+ 25 - 29
effects.go

@@ -44,7 +44,7 @@ func blurHorizontal(img image.Image, kernel []float64) *image.NRGBA {
 			for i, v := range scanLine {
 				scanLineF[i] = float64(v)
 			}
-			for x, idx := 0, 0; x < src.w; x, idx = x+1, idx+4 {
+			for x := 0; x < src.w; x++ {
 				min := x - radius
 				if min < 0 {
 					min = 0
@@ -53,30 +53,28 @@ func blurHorizontal(img image.Image, kernel []float64) *image.NRGBA {
 				if max > src.w-1 {
 					max = src.w - 1
 				}
-
 				var r, g, b, a, wsum float64
 				for ix := min; ix <= max; ix++ {
 					i := ix * 4
 					weight := kernel[absint(x-ix)]
 					wsum += weight
-					wa := scanLineF[i+3] * weight
-					r += scanLineF[i+0] * wa
-					g += scanLineF[i+1] * wa
-					b += scanLineF[i+2] * wa
+					s := scanLineF[i : i+4 : i+4]
+					wa := s[3] * weight
+					r += s[0] * wa
+					g += s[1] * wa
+					b += s[2] * wa
 					a += wa
 				}
 				if a != 0 {
-					r /= a
-					g /= a
-					b /= a
+					aInv := 1 / a
+					j := y*dst.Stride + x*4
+					d := dst.Pix[j : j+4 : j+4]
+					d[0] = clamp(r * aInv)
+					d[1] = clamp(g * aInv)
+					d[2] = clamp(b * aInv)
+					d[3] = clamp(a / wsum)
 				}
-
-				scanLine[idx+0] = clamp(r)
-				scanLine[idx+1] = clamp(g)
-				scanLine[idx+2] = clamp(b)
-				scanLine[idx+3] = clamp(a / wsum)
 			}
-			copy(dst.Pix[y*dst.Stride:], scanLine)
 		}
 	})
 
@@ -105,29 +103,27 @@ func blurVertical(img image.Image, kernel []float64) *image.NRGBA {
 				if max > src.h-1 {
 					max = src.h - 1
 				}
-
 				var r, g, b, a, wsum float64
 				for iy := min; iy <= max; iy++ {
 					i := iy * 4
 					weight := kernel[absint(y-iy)]
 					wsum += weight
-					wa := scanLineF[i+3] * weight
-					r += scanLineF[i+0] * wa
-					g += scanLineF[i+1] * wa
-					b += scanLineF[i+2] * wa
+					s := scanLineF[i : i+4 : i+4]
+					wa := s[3] * weight
+					r += s[0] * wa
+					g += s[1] * wa
+					b += s[2] * wa
 					a += wa
 				}
 				if a != 0 {
-					r /= a
-					g /= a
-					b /= a
+					aInv := 1 / a
+					j := y*dst.Stride + x*4
+					d := dst.Pix[j : j+4 : j+4]
+					d[0] = clamp(r * aInv)
+					d[1] = clamp(g * aInv)
+					d[2] = clamp(b * aInv)
+					d[3] = clamp(a / wsum)
 				}
-
-				j := y*dst.Stride + x*4
-				dst.Pix[j+0] = clamp(r)
-				dst.Pix[j+1] = clamp(g)
-				dst.Pix[j+2] = clamp(b)
-				dst.Pix[j+3] = clamp(a / wsum)
 			}
 		}
 	})

+ 4 - 3
histogram.go

@@ -27,9 +27,10 @@ func Histogram(img image.Image) [256]float64 {
 			src.scan(0, y, src.w, y+1, scanLine)
 			i := 0
 			for x := 0; x < src.w; x++ {
-				r := scanLine[i+0]
-				g := scanLine[i+1]
-				b := scanLine[i+2]
+				s := scanLine[i : i+3 : i+3]
+				r := s[0]
+				g := s[1]
+				b := s[2]
 				y := 0.299*float32(r) + 0.587*float32(g) + 0.114*float32(b)
 				tmpHistogram[int(y+0.5)]++
 				tmpTotal++

+ 15 - 13
tools.go

@@ -198,15 +198,17 @@ func Overlay(background, img image.Image, pos image.Point, opacity float64) *ima
 			i := y*dst.Stride + interRect.Min.X*4
 			j := 0
 			for x := interRect.Min.X; x < interRect.Max.X; x++ {
-				r1 := float64(dst.Pix[i+0])
-				g1 := float64(dst.Pix[i+1])
-				b1 := float64(dst.Pix[i+2])
-				a1 := float64(dst.Pix[i+3])
-
-				r2 := float64(scanLine[j+0])
-				g2 := float64(scanLine[j+1])
-				b2 := float64(scanLine[j+2])
-				a2 := float64(scanLine[j+3])
+				d := dst.Pix[i : i+4 : i+4]
+				r1 := float64(d[0])
+				g1 := float64(d[1])
+				b1 := float64(d[2])
+				a1 := float64(d[3])
+
+				s := scanLine[j : j+4 : j+4]
+				r2 := float64(s[0])
+				g2 := float64(s[1])
+				b2 := float64(s[2])
+				a2 := float64(s[3])
 
 				coef2 := opacity * a2 / 255
 				coef1 := (1 - coef2) * a1 / 255
@@ -214,10 +216,10 @@ func Overlay(background, img image.Image, pos image.Point, opacity float64) *ima
 				coef1 /= coefSum
 				coef2 /= coefSum
 
-				dst.Pix[i+0] = uint8(r1*coef1 + r2*coef2)
-				dst.Pix[i+1] = uint8(g1*coef1 + g2*coef2)
-				dst.Pix[i+2] = uint8(b1*coef1 + b2*coef2)
-				dst.Pix[i+3] = uint8(math.Min(a1+a2*opacity*(255-a1)/255, 255))
+				d[0] = uint8(r1*coef1 + r2*coef2)
+				d[1] = uint8(g1*coef1 + g2*coef2)
+				d[2] = uint8(b1*coef1 + b2*coef2)
+				d[3] = uint8(math.Min(a1+a2*opacity*(255-a1)/255, 255))
 
 				i += 4
 				j += 4

+ 40 - 43
transform.go

@@ -209,63 +209,60 @@ func rotatedSize(w, h int, angle float64) (int, int) {
 }
 
 func interpolatePoint(dst *image.NRGBA, dstX, dstY int, src *image.NRGBA, xf, yf float64, bgColor color.NRGBA) {
-	dstIndex := dstY*dst.Stride + dstX*4
+	j := dstY*dst.Stride + dstX*4
+	d := dst.Pix[j : j+4 : j+4]
 
 	x0 := int(math.Floor(xf))
 	y0 := int(math.Floor(yf))
 	bounds := src.Bounds()
 	if !image.Pt(x0, y0).In(image.Rect(bounds.Min.X-1, bounds.Min.Y-1, bounds.Max.X, bounds.Max.Y)) {
-		dst.Pix[dstIndex+0] = bgColor.R
-		dst.Pix[dstIndex+1] = bgColor.G
-		dst.Pix[dstIndex+2] = bgColor.B
-		dst.Pix[dstIndex+3] = bgColor.A
+		d[0] = bgColor.R
+		d[1] = bgColor.G
+		d[2] = bgColor.B
+		d[3] = bgColor.A
 		return
 	}
 
 	xq := xf - float64(x0)
 	yq := yf - float64(y0)
-
-	var pxs [4]color.NRGBA
-	var cfs [4]float64
-
-	for i := 0; i < 2; i++ {
-		for j := 0; j < 2; j++ {
-			k := i*2 + j
-			pt := image.Pt(x0+j, y0+i)
-			if pt.In(bounds) {
-				l := pt.Y*src.Stride + pt.X*4
-				pxs[k].R = src.Pix[l+0]
-				pxs[k].G = src.Pix[l+1]
-				pxs[k].B = src.Pix[l+2]
-				pxs[k].A = src.Pix[l+3]
-			} else {
-				pxs[k] = bgColor
-			}
-		}
+	points := [4]image.Point{
+		{x0, y0},
+		{x0 + 1, y0},
+		{x0, y0 + 1},
+		{x0 + 1, y0 + 1},
+	}
+	weights := [4]float64{
+		(1 - xq) * (1 - yq),
+		xq * (1 - yq),
+		(1 - xq) * yq,
+		xq * yq,
 	}
-
-	cfs[0] = (1 - xq) * (1 - yq)
-	cfs[1] = xq * (1 - yq)
-	cfs[2] = (1 - xq) * yq
-	cfs[3] = xq * yq
 
 	var r, g, b, a float64
-	for i := range pxs {
-		wa := float64(pxs[i].A) * cfs[i]
-		r += float64(pxs[i].R) * wa
-		g += float64(pxs[i].G) * wa
-		b += float64(pxs[i].B) * wa
-		a += wa
+	for i := 0; i < 4; i++ {
+		p := points[i]
+		w := weights[i]
+		if p.In(bounds) {
+			i := p.Y*src.Stride + p.X*4
+			s := src.Pix[i : i+4 : i+4]
+			wa := float64(s[3]) * w
+			r += float64(s[0]) * wa
+			g += float64(s[1]) * wa
+			b += float64(s[2]) * wa
+			a += wa
+		} else {
+			wa := float64(bgColor.A) * w
+			r += float64(bgColor.R) * wa
+			g += float64(bgColor.G) * wa
+			b += float64(bgColor.B) * wa
+			a += wa
+		}
 	}
-
 	if a != 0 {
-		r /= a
-		g /= a
-		b /= a
+		aInv := 1 / a
+		d[0] = clamp(r * aInv)
+		d[1] = clamp(g * aInv)
+		d[2] = clamp(b * aInv)
+		d[3] = clamp(a)
 	}
-
-	dst.Pix[dstIndex+0] = clamp(r)
-	dst.Pix[dstIndex+1] = clamp(g)
-	dst.Pix[dstIndex+2] = clamp(b)
-	dst.Pix[dstIndex+3] = clamp(a)
 }

+ 6 - 4
utils.go

@@ -63,10 +63,12 @@ func reverse(pix []uint8) {
 	i := 0
 	j := len(pix) - 4
 	for i < j {
-		pix[i+0], pix[j+0] = pix[j+0], pix[i+0]
-		pix[i+1], pix[j+1] = pix[j+1], pix[i+1]
-		pix[i+2], pix[j+2] = pix[j+2], pix[i+2]
-		pix[i+3], pix[j+3] = pix[j+3], pix[i+3]
+		pi := pix[i : i+4 : i+4]
+		pj := pix[j : j+4 : j+4]
+		pi[0], pj[0] = pj[0], pi[0]
+		pi[1], pj[1] = pj[1], pi[1]
+		pi[2], pj[2] = pj[2], pi[2]
+		pi[3], pj[3] = pj[3], pi[3]
 		i += 4
 		j -= 4
 	}