mirror of
https://github.com/esimov/caire.git
synced 2025-10-06 00:57:16 +08:00
Perf improvements on stackblur algorithm
This commit is contained in:
@@ -75,8 +75,6 @@ func (c *Carver) set(x, y int, px float64) {
|
||||
// - the minimum energy level is calculated by summing up the current pixel value
|
||||
// with the minimum pixel value of the neighboring pixels from the previous row.
|
||||
func (c *Carver) ComputeSeams(p *Processor, img *image.NRGBA) (*image.NRGBA, error) {
|
||||
var srcImg *image.NRGBA
|
||||
|
||||
width, height := img.Bounds().Dx(), img.Bounds().Dy()
|
||||
sobel = c.SobelDetector(img, float64(p.SobelThreshold))
|
||||
|
||||
@@ -215,8 +213,13 @@ func (c *Carver) ComputeSeams(p *Processor, img *image.NRGBA) (*image.NRGBA, err
|
||||
}
|
||||
}
|
||||
|
||||
var srcImg *image.NRGBA
|
||||
if p.BlurRadius > 0 {
|
||||
srcImg = c.StackBlur(sobel, uint32(p.BlurRadius))
|
||||
srcImg = image.NewNRGBA(img.Bounds())
|
||||
err := Stackblur(srcImg, sobel, uint32(p.BlurRadius))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error bluring the image: %w", err)
|
||||
}
|
||||
} else {
|
||||
srcImg = sobel
|
||||
}
|
||||
|
@@ -318,7 +318,9 @@ func TestCarver_ShouldNotRemoveFaceZone(t *testing.T) {
|
||||
pixels := rgbToGrayscale(img)
|
||||
|
||||
sobel := c.SobelDetector(img, float64(p.SobelThreshold))
|
||||
img = c.StackBlur(sobel, uint32(p.BlurRadius))
|
||||
|
||||
err = Stackblur(img, sobel, uint32(p.BlurRadius))
|
||||
assert.NoError(t, err)
|
||||
|
||||
cParams := pigo.CascadeParams{
|
||||
MinSize: 100,
|
||||
|
9
go.mod
9
go.mod
@@ -6,9 +6,9 @@ require (
|
||||
gioui.org v0.8.0
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/esimov/pigo v1.4.5
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
golang.org/x/exp v0.0.0-20240707233637-46b078467d37
|
||||
golang.org/x/image v0.18.0
|
||||
golang.org/x/image v0.23.0
|
||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035
|
||||
)
|
||||
|
||||
@@ -18,7 +18,8 @@ require (
|
||||
github.com/go-text/typesetting v0.2.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
31
go.sum
31
go.sum
@@ -5,7 +5,6 @@ gioui.org v0.8.0/go.mod h1:vEMmpxMOd/iwJhXvGVIzWEbxMWhnMQ9aByOGQdlQ8rc=
|
||||
gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
|
||||
gioui.org/shader v1.0.8 h1:6ks0o/A+b0ne7RzEqRZK5f4Gboz2CfG+mVliciy6+qA=
|
||||
gioui.org/shader v1.0.8/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
@@ -18,35 +17,35 @@ github.com/go-text/typesetting v0.2.1/go.mod h1:mTOxEwasOFpAMBjEQDhdWRckoLLeI/+q
|
||||
github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066 h1:qCuYC+94v2xrb1PoS4NIDe7DGYtLnU2wWiQe9a1B1c0=
|
||||
github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w=
|
||||
golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37 h1:SOSg7+sueresE4IbmmGM60GmlIys+zNX63d6/J4CMtU=
|
||||
golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37/go.mod h1:3F+MieQB7dRYLTmnncoFbb1crS5lfQoTfDgQy6K4N0o=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
|
||||
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
|
||||
golang.org/x/image v0.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68=
|
||||
golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc=
|
||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
185
stackblur.go
185
stackblur.go
@@ -1,16 +1,18 @@
|
||||
// Go implementation of StackBlur algorithm described here:
|
||||
// Go implementation of the StackBlur algorithm
|
||||
// http://incubator.quasimondo.com/processing/fast_blur_deluxe.php
|
||||
|
||||
package caire
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"image"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
// blurstack is a linked list containing the color value and a pointer to the next struct.
|
||||
type blurstack struct {
|
||||
// blurStack is a linked list containing the color value and a pointer to the next struct.
|
||||
type blurStack struct {
|
||||
r, g, b, a uint32
|
||||
next *blurstack
|
||||
next *blurStack
|
||||
}
|
||||
|
||||
var mulTable = []uint32{
|
||||
@@ -51,11 +53,86 @@ var shgTable = []uint32{
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
}
|
||||
|
||||
// StackBlur applies a blur filter to the provided image.
|
||||
// The radius defines the bluring average.
|
||||
func (c *Carver) StackBlur(img *image.NRGBA, radius uint32) *image.NRGBA {
|
||||
var stackEnd, stackIn, stackOut *blurstack
|
||||
var width, height = uint32(img.Bounds().Dx()), uint32(img.Bounds().Dy())
|
||||
// Stackblur takes the source image and returns it's blurred version by applying the blur radius defined as parameter. The destination image must be a image.NRGBA.
|
||||
func Stackblur(dst, src image.Image, radius uint32) error {
|
||||
// Limit the maximum blur radius to 255 to avoid overflowing the multable.
|
||||
if int(radius) >= len(mulTable) {
|
||||
radius = uint32(len(mulTable) - 1)
|
||||
}
|
||||
|
||||
if radius < 1 {
|
||||
return errors.New("blur radius must be greater than 0")
|
||||
}
|
||||
|
||||
img, ok := dst.(*image.NRGBA)
|
||||
if !ok {
|
||||
return errors.New("the destination image must be image.NRGBA")
|
||||
}
|
||||
|
||||
process(img, src, radius)
|
||||
return nil
|
||||
}
|
||||
|
||||
func process(dst *image.NRGBA, src image.Image, radius uint32) {
|
||||
srcBounds := src.Bounds()
|
||||
srcMinX := srcBounds.Min.X
|
||||
srcMinY := srcBounds.Min.Y
|
||||
|
||||
dstBounds := srcBounds.Sub(srcBounds.Min)
|
||||
dstW := dstBounds.Dx()
|
||||
dstH := dstBounds.Dy()
|
||||
|
||||
switch src0 := src.(type) {
|
||||
case *image.NRGBA:
|
||||
rowSize := srcBounds.Dx() * 4
|
||||
for dstY := 0; dstY < dstH; dstY++ {
|
||||
di := src0.PixOffset(0, dstY)
|
||||
si := src0.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
copy(dst.Pix[di:di+rowSize], src0.Pix[si:si+rowSize])
|
||||
}
|
||||
}
|
||||
case *image.YCbCr:
|
||||
for dstY := 0; dstY < dstH; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
srcX := srcMinX + dstX
|
||||
srcY := srcMinY + dstY
|
||||
siy := src0.YOffset(srcX, srcY)
|
||||
sic := src0.COffset(srcX, srcY)
|
||||
r, g, b := color.YCbCrToRGB(src0.Y[siy], src0.Cb[sic], src0.Cr[sic])
|
||||
dst.Pix[di+0] = r
|
||||
dst.Pix[di+1] = g
|
||||
dst.Pix[di+2] = b
|
||||
dst.Pix[di+3] = 0xff
|
||||
di += 4
|
||||
}
|
||||
}
|
||||
default:
|
||||
for dstY := 0; dstY < dstH; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
c := color.NRGBAModel.Convert(src.At(srcMinX+dstX, srcMinY+dstY)).(color.NRGBA)
|
||||
dst.Pix[di+0] = c.R
|
||||
dst.Pix[di+1] = c.G
|
||||
dst.Pix[di+2] = c.B
|
||||
dst.Pix[di+3] = c.A
|
||||
di += 4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blurImage(dst, radius)
|
||||
}
|
||||
|
||||
func blurImage(src *image.NRGBA, radius uint32) {
|
||||
var (
|
||||
stackEnd *blurStack
|
||||
stackIn *blurStack
|
||||
stackOut *blurStack
|
||||
)
|
||||
|
||||
var width, height = uint32(src.Bounds().Dx()), uint32(src.Bounds().Dy())
|
||||
var (
|
||||
div, widthMinus1, heightMinus1, radiusPlus1, sumFactor uint32
|
||||
x, y, i, p, yp, yi, yw,
|
||||
@@ -65,26 +142,17 @@ func (c *Carver) StackBlur(img *image.NRGBA, radius uint32) *image.NRGBA {
|
||||
pr, pg, pb, pa uint32
|
||||
)
|
||||
|
||||
// Limit the maximum blur radius to 255, otherwise it overflows the multable length
|
||||
// and will panic with and index out of range error.
|
||||
if int(radius) >= len(mulTable) {
|
||||
radius = uint32(len(mulTable) - 1)
|
||||
}
|
||||
if radius < 1 {
|
||||
radius = 1
|
||||
}
|
||||
|
||||
div = radius + radius + 1
|
||||
widthMinus1 = width - 1
|
||||
heightMinus1 = height - 1
|
||||
radiusPlus1 = radius + 1
|
||||
sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2
|
||||
|
||||
stackStart := new(blurstack)
|
||||
stackStart := new(blurStack)
|
||||
stack := stackStart
|
||||
|
||||
for i = 1; i < div; i++ {
|
||||
stack.next = new(blurstack)
|
||||
stack.next = new(blurStack)
|
||||
stack = stack.next
|
||||
if i == radiusPlus1 {
|
||||
stackEnd = stack
|
||||
@@ -98,10 +166,10 @@ func (c *Carver) StackBlur(img *image.NRGBA, radius uint32) *image.NRGBA {
|
||||
for y = 0; y < height; y++ {
|
||||
rInSum, gInSum, bInSum, aInSum, rSum, gSum, bSum, aSum = 0, 0, 0, 0, 0, 0, 0, 0
|
||||
|
||||
pr = uint32(img.Pix[yi])
|
||||
pg = uint32(img.Pix[yi+1])
|
||||
pb = uint32(img.Pix[yi+2])
|
||||
pa = uint32(img.Pix[yi+3])
|
||||
pr = uint32(src.Pix[yi])
|
||||
pg = uint32(src.Pix[yi+1])
|
||||
pb = uint32(src.Pix[yi+2])
|
||||
pa = uint32(src.Pix[yi+3])
|
||||
|
||||
rOutSum = radiusPlus1 * pr
|
||||
gOutSum = radiusPlus1 * pg
|
||||
@@ -131,10 +199,10 @@ func (c *Carver) StackBlur(img *image.NRGBA, radius uint32) *image.NRGBA {
|
||||
diff = i
|
||||
}
|
||||
p = yi + (diff << 2)
|
||||
pr = uint32(img.Pix[p])
|
||||
pg = uint32(img.Pix[p+1])
|
||||
pb = uint32(img.Pix[p+2])
|
||||
pa = uint32(img.Pix[p+3])
|
||||
pr = uint32(src.Pix[p])
|
||||
pg = uint32(src.Pix[p+1])
|
||||
pb = uint32(src.Pix[p+2])
|
||||
pa = uint32(src.Pix[p+3])
|
||||
|
||||
stack.r = pr
|
||||
stack.g = pg
|
||||
@@ -158,16 +226,16 @@ func (c *Carver) StackBlur(img *image.NRGBA, radius uint32) *image.NRGBA {
|
||||
|
||||
for x = 0; x < width; x++ {
|
||||
pa = (aSum * mulSum) >> shgSum
|
||||
img.Pix[yi+3] = uint8(pa)
|
||||
src.Pix[yi+3] = uint8(pa)
|
||||
|
||||
if pa != 0 {
|
||||
img.Pix[yi] = uint8((rSum * mulSum) >> shgSum)
|
||||
img.Pix[yi+1] = uint8((gSum * mulSum) >> shgSum)
|
||||
img.Pix[yi+2] = uint8((bSum * mulSum) >> shgSum)
|
||||
src.Pix[yi] = uint8((rSum * mulSum) >> shgSum)
|
||||
src.Pix[yi+1] = uint8((gSum * mulSum) >> shgSum)
|
||||
src.Pix[yi+2] = uint8((bSum * mulSum) >> shgSum)
|
||||
} else {
|
||||
img.Pix[yi] = 0
|
||||
img.Pix[yi+1] = 0
|
||||
img.Pix[yi+2] = 0
|
||||
src.Pix[yi] = 0
|
||||
src.Pix[yi+1] = 0
|
||||
src.Pix[yi+2] = 0
|
||||
}
|
||||
|
||||
rSum -= rOutSum
|
||||
@@ -187,10 +255,10 @@ func (c *Carver) StackBlur(img *image.NRGBA, radius uint32) *image.NRGBA {
|
||||
}
|
||||
p = (yw + p) << 2
|
||||
|
||||
stackIn.r = uint32(img.Pix[p])
|
||||
stackIn.g = uint32(img.Pix[p+1])
|
||||
stackIn.b = uint32(img.Pix[p+2])
|
||||
stackIn.a = uint32(img.Pix[p+3])
|
||||
stackIn.r = uint32(src.Pix[p])
|
||||
stackIn.g = uint32(src.Pix[p+1])
|
||||
stackIn.b = uint32(src.Pix[p+2])
|
||||
stackIn.a = uint32(src.Pix[p+3])
|
||||
|
||||
rInSum += stackIn.r
|
||||
gInSum += stackIn.g
|
||||
@@ -230,10 +298,10 @@ func (c *Carver) StackBlur(img *image.NRGBA, radius uint32) *image.NRGBA {
|
||||
rInSum, gInSum, bInSum, aInSum, rSum, gSum, bSum, aSum = 0, 0, 0, 0, 0, 0, 0, 0
|
||||
|
||||
yi = x << 2
|
||||
pr = uint32(img.Pix[yi])
|
||||
pg = uint32(img.Pix[yi+1])
|
||||
pb = uint32(img.Pix[yi+2])
|
||||
pa = uint32(img.Pix[yi+3])
|
||||
pr = uint32(src.Pix[yi])
|
||||
pg = uint32(src.Pix[yi+1])
|
||||
pb = uint32(src.Pix[yi+2])
|
||||
pa = uint32(src.Pix[yi+3])
|
||||
|
||||
rOutSum = radiusPlus1 * pr
|
||||
gOutSum = radiusPlus1 * pg
|
||||
@@ -259,10 +327,10 @@ func (c *Carver) StackBlur(img *image.NRGBA, radius uint32) *image.NRGBA {
|
||||
|
||||
for i = 1; i <= radius; i++ {
|
||||
yi = (yp + x) << 2
|
||||
pr = uint32(img.Pix[yi])
|
||||
pg = uint32(img.Pix[yi+1])
|
||||
pb = uint32(img.Pix[yi+2])
|
||||
pa = uint32(img.Pix[yi+3])
|
||||
pr = uint32(src.Pix[yi])
|
||||
pg = uint32(src.Pix[yi+1])
|
||||
pb = uint32(src.Pix[yi+2])
|
||||
pa = uint32(src.Pix[yi+3])
|
||||
|
||||
stack.r = pr
|
||||
stack.g = pg
|
||||
@@ -293,16 +361,16 @@ func (c *Carver) StackBlur(img *image.NRGBA, radius uint32) *image.NRGBA {
|
||||
for y = 0; y < height; y++ {
|
||||
p = yi << 2
|
||||
pa = (aSum * mulSum) >> shgSum
|
||||
img.Pix[p+3] = uint8(pa)
|
||||
src.Pix[p+3] = uint8(pa)
|
||||
|
||||
if pa > 0 {
|
||||
img.Pix[p] = uint8((rSum * mulSum) >> shgSum)
|
||||
img.Pix[p+1] = uint8((gSum * mulSum) >> shgSum)
|
||||
img.Pix[p+2] = uint8((bSum * mulSum) >> shgSum)
|
||||
src.Pix[p] = uint8((rSum * mulSum) >> shgSum)
|
||||
src.Pix[p+1] = uint8((gSum * mulSum) >> shgSum)
|
||||
src.Pix[p+2] = uint8((bSum * mulSum) >> shgSum)
|
||||
} else {
|
||||
img.Pix[p] = 0
|
||||
img.Pix[p+1] = 0
|
||||
img.Pix[p+2] = 0
|
||||
src.Pix[p] = 0
|
||||
src.Pix[p+1] = 0
|
||||
src.Pix[p+2] = 0
|
||||
}
|
||||
|
||||
rSum -= rOutSum
|
||||
@@ -322,10 +390,10 @@ func (c *Carver) StackBlur(img *image.NRGBA, radius uint32) *image.NRGBA {
|
||||
}
|
||||
p = (x + (p * width)) << 2
|
||||
|
||||
stackIn.r = uint32(img.Pix[p])
|
||||
stackIn.g = uint32(img.Pix[p+1])
|
||||
stackIn.b = uint32(img.Pix[p+2])
|
||||
stackIn.a = uint32(img.Pix[p+3])
|
||||
stackIn.r = uint32(src.Pix[p])
|
||||
stackIn.g = uint32(src.Pix[p+1])
|
||||
stackIn.b = uint32(src.Pix[p+2])
|
||||
stackIn.a = uint32(src.Pix[p+3])
|
||||
|
||||
rInSum += stackIn.r
|
||||
gInSum += stackIn.g
|
||||
@@ -359,5 +427,4 @@ func (c *Carver) StackBlur(img *image.NRGBA, radius uint32) *image.NRGBA {
|
||||
yi += width
|
||||
}
|
||||
}
|
||||
return img
|
||||
}
|
||||
|
Reference in New Issue
Block a user