123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- package imaging
- import (
- "image"
- "math"
- )
- func gaussianBlurKernel(x, sigma float64) float64 {
- return math.Exp(-(x*x)/(2*sigma*sigma)) / (sigma * math.Sqrt(2*math.Pi))
- }
- // Blur produces a blurred version of the image using a Gaussian function.
- // Sigma parameter must be positive and indicates how much the image will be blurred.
- //
- // Usage example:
- //
- // dstImage := imaging.Blur(srcImage, 3.5)
- //
- func Blur(img image.Image, sigma float64) *image.NRGBA {
- if sigma <= 0 {
- // sigma parameter must be positive!
- return Clone(img)
- }
- src := toNRGBA(img)
- radius := int(math.Ceil(sigma * 3.0))
- kernel := make([]float64, radius+1)
- for i := 0; i <= radius; i++ {
- kernel[i] = gaussianBlurKernel(float64(i), sigma)
- }
- var dst *image.NRGBA
- dst = blurHorizontal(src, kernel)
- dst = blurVertical(dst, kernel)
- return dst
- }
- func blurHorizontal(src *image.NRGBA, kernel []float64) *image.NRGBA {
- radius := len(kernel) - 1
- width := src.Bounds().Max.X
- height := src.Bounds().Max.Y
- dst := image.NewNRGBA(image.Rect(0, 0, width, height))
- parallel(width, func(partStart, partEnd int) {
- for x := partStart; x < partEnd; x++ {
- start := x - radius
- if start < 0 {
- start = 0
- }
- end := x + radius
- if end > width-1 {
- end = width - 1
- }
- weightSum := 0.0
- for ix := start; ix <= end; ix++ {
- weightSum += kernel[absint(x-ix)]
- }
- for y := 0; y < height; y++ {
- r, g, b, a := 0.0, 0.0, 0.0, 0.0
- for ix := start; ix <= end; ix++ {
- weight := kernel[absint(x-ix)]
- i := y*src.Stride + ix*4
- r += float64(src.Pix[i+0]) * weight
- g += float64(src.Pix[i+1]) * weight
- b += float64(src.Pix[i+2]) * weight
- a += float64(src.Pix[i+3]) * weight
- }
- r = math.Min(math.Max(r/weightSum, 0.0), 255.0)
- g = math.Min(math.Max(g/weightSum, 0.0), 255.0)
- b = math.Min(math.Max(b/weightSum, 0.0), 255.0)
- a = math.Min(math.Max(a/weightSum, 0.0), 255.0)
- j := y*dst.Stride + x*4
- dst.Pix[j+0] = uint8(r + 0.5)
- dst.Pix[j+1] = uint8(g + 0.5)
- dst.Pix[j+2] = uint8(b + 0.5)
- dst.Pix[j+3] = uint8(a + 0.5)
- }
- }
- })
- return dst
- }
- func blurVertical(src *image.NRGBA, kernel []float64) *image.NRGBA {
- radius := len(kernel) - 1
- width := src.Bounds().Max.X
- height := src.Bounds().Max.Y
- dst := image.NewNRGBA(image.Rect(0, 0, width, height))
- parallel(height, func(partStart, partEnd int) {
- for y := partStart; y < partEnd; y++ {
- start := y - radius
- if start < 0 {
- start = 0
- }
- end := y + radius
- if end > height-1 {
- end = height - 1
- }
- weightSum := 0.0
- for iy := start; iy <= end; iy++ {
- weightSum += kernel[absint(y-iy)]
- }
- for x := 0; x < width; x++ {
- r, g, b, a := 0.0, 0.0, 0.0, 0.0
- for iy := start; iy <= end; iy++ {
- weight := kernel[absint(y-iy)]
- i := iy*src.Stride + x*4
- r += float64(src.Pix[i+0]) * weight
- g += float64(src.Pix[i+1]) * weight
- b += float64(src.Pix[i+2]) * weight
- a += float64(src.Pix[i+3]) * weight
- }
- r = math.Min(math.Max(r/weightSum, 0.0), 255.0)
- g = math.Min(math.Max(g/weightSum, 0.0), 255.0)
- b = math.Min(math.Max(b/weightSum, 0.0), 255.0)
- a = math.Min(math.Max(a/weightSum, 0.0), 255.0)
- j := y*dst.Stride + x*4
- dst.Pix[j+0] = uint8(r + 0.5)
- dst.Pix[j+1] = uint8(g + 0.5)
- dst.Pix[j+2] = uint8(b + 0.5)
- dst.Pix[j+3] = uint8(a + 0.5)
- }
- }
- })
- return dst
- }
- // Sharpen produces a sharpened version of the image.
- // Sigma parameter must be positive and indicates how much the image will be sharpened.
- //
- // Usage example:
- //
- // dstImage := imaging.Sharpen(srcImage, 3.5)
- //
- func Sharpen(img image.Image, sigma float64) *image.NRGBA {
- if sigma <= 0 {
- // sigma parameter must be positive!
- return Clone(img)
- }
- src := toNRGBA(img)
- blurred := Blur(img, sigma)
- width := src.Bounds().Max.X
- height := src.Bounds().Max.Y
- dst := image.NewNRGBA(image.Rect(0, 0, width, height))
- parallel(height, func(partStart, partEnd int) {
- for y := partStart; y < partEnd; y++ {
- for x := 0; x < width; x++ {
- i := y*src.Stride + x*4
- for j := 0; j < 4; j++ {
- k := i + j
- val := int(src.Pix[k]) + (int(src.Pix[k]) - int(blurred.Pix[k]))
- if val < 0 {
- val = 0
- } else if val > 255 {
- val = 255
- }
- dst.Pix[k] = uint8(val)
- }
- }
- }
- })
- return dst
- }
|