performance improvements

This commit is contained in:
Grigory Dryapak
2019-01-20 17:42:36 +03:00
parent b5a2b9828d
commit 791d8b4e28
8 changed files with 132 additions and 118 deletions

View File

@@ -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
}
}

View File

@@ -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}
})
}
}

View File

@@ -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]
}
}
})

View File

@@ -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)
}
}
})

View File

@@ -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++

View File

@@ -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])
d := dst.Pix[i : i+4 : i+4]
r1 := float64(d[0])
g1 := float64(d[1])
b1 := float64(d[2])
a1 := float64(d[3])
r2 := float64(scanLine[j+0])
g2 := float64(scanLine[j+1])
b2 := float64(scanLine[j+2])
a2 := float64(scanLine[j+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

View File

@@ -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)
}

View File

@@ -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
}