vision/color.go

97 lines
2.1 KiB
Go

package vision
import (
"fmt"
"image/color"
"sort"
"github.com/disintegration/imaging"
)
// ColorCount 记录颜色及其出现的频率
type ColorCount struct {
Color color.Color
Hex string
Count int
}
// ExtractPalette 从图像中提取调色板(主要颜色)
// n: 提取的前 n 种颜色
func (c *Canvas) ExtractPalette(n int) []ColorCount {
img := c.dc.Image()
// 为了性能,先缩小图片
resized := imaging.Resize(img, 100, 100, imaging.NearestNeighbor)
bounds := resized.Bounds()
counts := make(map[uint32]int)
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
r, g, b, a := resized.At(x, y).RGBA()
// 忽略透明度较高的像素
if a < 32768 { continue }
// 简单的颜色量化,减少颜色数量
r >>= 12
g >>= 12
b >>= 12
key := (r << 8) | (g << 4) | b
counts[key]++
}
}
palette := make([]ColorCount, 0, len(counts))
for key, count := range counts {
r := uint8((key >> 8) & 0xF) * 17
g := uint8((key >> 4) & 0xF) * 17
b := uint8(key & 0xF) * 17
c := color.RGBA{r, g, b, 255}
palette = append(palette, ColorCount{
Color: c,
Hex: RGBAToHex(c),
Count: count,
})
}
sort.Slice(palette, func(i, j int) bool {
return palette[i].Count > palette[j].Count
})
if len(palette) > n {
palette = palette[:n]
}
return palette
}
// RGBAToHex 将 RGBA 转换为 Hex 字符串
func RGBAToHex(c color.RGBA) string {
return fmt.Sprintf("#%02X%02X%02X", c.R, c.G, c.B)
}
// GetAverageColor 计算画布的平均颜色
func (c *Canvas) GetAverageColor() color.Color {
img := c.dc.Image()
bounds := img.Bounds()
var r, g, b, a uint64
w, h := bounds.Dx(), bounds.Dy()
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
pr, pg, pb, pa := img.At(x, y).RGBA()
r += uint64(pr)
g += uint64(pg)
b += uint64(pb)
a += uint64(pa)
}
}
total := uint64(w * h)
if total == 0 { return color.Transparent }
return color.RGBA64{
R: uint16(r / total),
G: uint16(g / total),
B: uint16(b / total),
A: uint16(a / total),
}
}