-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconvolution.go
More file actions
105 lines (88 loc) · 2.1 KB
/
Copy pathconvolution.go
File metadata and controls
105 lines (88 loc) · 2.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package prism
import (
"image"
"math"
)
// Convolve3x3 applies a 3x3 convolution kernel to the image.
func Convolve3x3(img image.Image, kernel [9]float64, options *ConvolveOptions) *image.NRGBA {
return convolve(img, kernel[:], 3, options)
}
// Convolve5x5 applies a 5x5 convolution kernel to the image.
func Convolve5x5(img image.Image, kernel [25]float64, options *ConvolveOptions) *image.NRGBA {
return convolve(img, kernel[:], 5, options)
}
func convolve(img image.Image, kernel []float64, size int, options *ConvolveOptions) *image.NRGBA {
if options == nil {
options = &ConvolveOptions{}
}
// Normalize kernel if requested.
k := make([]float64, len(kernel))
copy(k, kernel)
if options.Normalize {
var sum float64
for _, v := range k {
sum += v
}
if sum != 0 {
for i := range k {
k[i] /= sum
}
}
}
bounds := img.Bounds()
w := bounds.Dx()
h := bounds.Dy()
dst := image.NewNRGBA(image.Rect(0, 0, w, h))
s := newScanner(img)
// Read entire image into buffer for random access.
src := make([]byte, w*h*4)
for y := 0; y < h; y++ {
s.scan(bounds.Min.X, bounds.Min.Y+y, bounds.Max.X, bounds.Min.Y+y+1, src[y*w*4:(y+1)*w*4])
}
half := size / 2
bias := float64(options.Bias)
parallel(0, h, func(y int) {
dstOff := y * dst.Stride
for x := 0; x < w; x++ {
var r, g, b float64
ki := 0
for ky := -half; ky <= half; ky++ {
for kx := -half; kx <= half; kx++ {
sx := x + kx
sy := y + ky
if sx < 0 {
sx = 0
} else if sx >= w {
sx = w - 1
}
if sy < 0 {
sy = 0
} else if sy >= h {
sy = h - 1
}
si := sy*w*4 + sx*4
wt := k[ki]
r += float64(src[si+0]) * wt
g += float64(src[si+1]) * wt
b += float64(src[si+2]) * wt
ki++
}
}
if options.Abs {
r = math.Abs(r)
g = math.Abs(g)
b = math.Abs(b)
}
r += bias
g += bias
b += bias
// Alpha from center pixel.
centerIdx := y*w*4 + x*4
dst.Pix[dstOff+x*4+0] = clamp(r)
dst.Pix[dstOff+x*4+1] = clamp(g)
dst.Pix[dstOff+x*4+2] = clamp(b)
dst.Pix[dstOff+x*4+3] = src[centerIdx+3]
}
})
return dst
}