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), } }