Go语言如何识别图片的主要色值

2022-07-01

go

最近有一个需求,根据图片的主要色值自动设置页面的背景色。我们的服务端是go语言写的,自然先评估一下是否能用go实现这个需求。找了几个方案,其中github.com/cenkalti/dominantcolor的方案最为简单,也最合适。

先看看简单的例子

package main

import (
	"bytes"
	"fmt"
	"image"
	"image/jpeg"
	"io"
	"io/ioutil"
	"net/http"

	"github.com/cenkalti/dominantcolor"
)

func GetImageByUrl(url string) (img image.Image, err error) {
	res, err := http.Get(url)
	if err != nil {
		return
	}

	defer func(body io.ReadCloser) {
		_ = body.Close()
	}(res.Body)

	data, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return
	}

	reader := bytes.NewReader(data)
	img, err = jpeg.Decode(reader)

	return
}

func FindDomiantColor(url string) (c string, err error) {
	img, err := GetImageByUrl(url)
	if err != nil {
		return
	}

	return dominantcolor.Hex(dominantcolor.Find(img)), nil
}

func main() {
	fmt.Println(FindDomiantColor("https://n.sinaimg.cn/news/transform/310/w710h400/20220701/8cd8-e663ace484b6d8dcc548a18691e30c0a.jpg"))
}

这个例子打开一个网络图片,然后获取其主要的颜色,输出是#544F4C,可以看一下背景的效果图:

可以看出背景还是比较匹配的。不过对于某些有多个色块的图片,是拿不到单一的颜色的,例如下面这个例子:

当然,如果只能选一种颜色,并且是自动的,那确实没有太简单的办法。不过如果可以让用户干预,其实还是可以有办法的,因为dominantcolor是可以输出多个颜色的。我们来看一下官方的演示程序:

这个程序也是go写的,基于dominantcolor和fyne.io,有兴趣的可以试试,也很简单:

go install github.com/stuartmscott/dominantcolor
$GOPATH/dominantcolor

上面是运行的界面,可以选一张本地的图片,计算6个使用最多的颜色块。windows下也可以运行,只不过因为需要gl库,看上去依赖gcc编译,所以没有尝试。上图是在wsl下运行的,现在windows的wsl已经支持图形界面的程序运行,还是挺方便的,就是性能看上去一般般。

从代码库的文档看,这个库用的是K聚类算法计算RGBA颜色空间的聚类,源自Chromium的源码:

 
阅读