-
Notifications
You must be signed in to change notification settings - Fork 0
/
avgcolor.go
60 lines (49 loc) · 1.49 KB
/
avgcolor.go
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
package tiles
import (
"image"
"math"
)
// AvgColor is average color of image
type AvgColor [3]float64
// R is red component
func (c AvgColor) R() float64 {
return c[0]
}
// G is green component
func (c AvgColor) G() float64 {
return c[1]
}
// B is blue component
func (c AvgColor) B() float64 {
return c[2]
}
// NewAvgColor returns average color of the img
func NewAvgColor(img image.Image) AvgColor {
bounds := img.Bounds()
r, g, b := 0.0, 0.0, 0.0
for x := bounds.Min.X; x < bounds.Max.X; x++ {
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
r1, g1, b1, _ := img.At(x, y).RGBA()
r, g, b = r+float64(r1), g+float64(g1), b+float64(b1)
}
}
total := float64(bounds.Dx() * bounds.Dy())
return AvgColor{r / total, g / total, b / total}
}
// Color distance calculator
type DistanceCalculator func(AvgColor, AvgColor) float64
var (
ColorDistanceEuclidean DistanceCalculator = euclideanDistance
ColorDistanceRedmean DistanceCalculator = redMeanDistance
)
// euclideanDistance implements euclidean color distance
func euclideanDistance(c1, c2 AvgColor) float64 {
dr, dg, db := c1.R()-c2.R(), c1.G()-c2.G(), c1.B()-c2.B()
return math.Sqrt(dr*dr + dg*dg + db*db)
}
// redmeanDistance implements so called "redmean" approximation https://en.wikipedia.org/wiki/Color_difference#sRGB
func redMeanDistance(c1, c2 AvgColor) float64 {
r := (c1.R() + c2.R()) / 2.0
dr, dg, db := c1.R()-c2.R(), c1.G()-c2.G(), c1.B()-c2.B()
return math.Sqrt((2+r/0x10000)*dr*dr + 4*dg*dg + (2+(0xffff-r)/0x10000)*db*db)
}