55 "image/color"
66 "math"
77 "math/rand"
8+ "runtime"
9+ "sync"
810 "unsafe"
911
1012 "github.com/disintegration/imaging"
@@ -61,15 +63,14 @@ func newKMeansImage(img image.Image, k uint16) kmeansImage {
6163 width := img .Bounds ().Dx ()
6264 height := img .Bounds ().Dy ()
6365 dstw , dsth := width , height
64- ratio := 0.
6566 if dstw > 512 {
6667 dstw = 512
67- ratio = float64 (dstw ) / float64 (width )
68+ ratio : = float64 (dstw ) / float64 (width )
6869 dsth *= int (float64 (height ) * ratio )
6970 }
7071 if dsth > 512 {
7172 dsth = 512
72- ratio = float64 (dsth ) / float64 (height )
73+ ratio : = float64 (dsth ) / float64 (height )
7374 dstw = int (float64 (width ) * ratio )
7475 }
7576 ki .bounds = image .Rect (0 , 0 , dstw , dsth )
@@ -94,7 +95,33 @@ func (ki *kmeansImage) assign() {
9495 ki .gpuDestroy (true )
9596 }
9697
97- for i , pixel := range ki .pixels {
98+ n := runtime .NumCPU ()
99+ batchcnt := len (ki .pixels ) / n
100+ rem := len (ki .pixels ) % n
101+ wg := sync.WaitGroup {}
102+ wg .Add (n )
103+ if rem < 0 {
104+ wg .Add (1 )
105+ }
106+ for batch := range n {
107+ go func (batch int ) {
108+ base := batch * batchcnt
109+ for i , pixel := range ki .pixels [base : base + batchcnt ] {
110+ minDistance := math .MaxFloat64
111+ assign := uint16 (math .MaxUint16 )
112+ for j , cluster := range ki .clusters {
113+ distance := distanceRGBAsq (pixel , cluster )
114+ if distance < minDistance {
115+ minDistance = distance
116+ assign = uint16 (j )
117+ }
118+ }
119+ ki .clusterAssignments [base + i ] = assign
120+ }
121+ }(batch )
122+ }
123+ base := n * batchcnt
124+ for i , pixel := range ki .pixels [n * batchcnt :] {
98125 minDistance := math .MaxFloat64
99126 assign := uint16 (math .MaxUint16 )
100127 for j , cluster := range ki .clusters {
@@ -104,7 +131,7 @@ func (ki *kmeansImage) assign() {
104131 assign = uint16 (j )
105132 }
106133 }
107- ki .clusterAssignments [i ] = assign
134+ ki .clusterAssignments [base + i ] = assign
108135 }
109136}
110137
0 commit comments