如何在 python 中提取图片主题色
前言
在 Groove 音乐中,当我们改变歌曲时,底部播放栏的颜色会随专辑封面而变,比如下图中播放栏的颜色变成了 aiko 衣服的颜色。下面我们会在 python 中实现相同的效果,也就是提取出图片中的主题色。

实现流程
安装依赖
提取主题色有很多方法,比如使用 k-means 聚类,选出 k 个 RGB 坐标的聚类中心,但是速度会差一些,我们这里换成中位切分法。已经有人为我们实现好这个算法了,我们可以拿来就用。
pip install color-thief
提取主题色
color-thief 虽然可以很好地提取出候选的主题色,但还是需要我们亲自挑选出合适的主题色,甚至对主题色做出一些微调。比如上图中的文字是浅色的,如果提取到的主题色也是浅色的,效果就很差了。下面是代码:
# coding: utf-8
from math import floor
import numpy as np
from colorthief import ColorThief
class DominantColor:
    """ 图像主题色类 """
    @classmethod
    def getDominantColor(cls, imagePath: str):
        """ 获取指定图片的主题色
        Parameters
        ----------
        imagePath: str
            图片路径
        Returns
        -------
        r, g, b: int
            主题色各个通道的灰度值
        """
        colorThief = ColorThief(imagePath)
        # 调整图像大小,加快运算速度
        if max(colorThief.image.size) > 400:
            colorThief.image = colorThief.image.resize((400, 400))
        palette = colorThief.get_palette(quality=9)
        # 调整调色板明度
        palette = cls.__adjustPaletteValue(palette)
        for rgb in palette[:]:
            h, s, v = cls.rgb2hsv(rgb)
            if h < 0.02:
                palette.remove(rgb)
                if len(palette) <= 2:
                    break
        # 挑选主题色
        palette = palette[:5]
        palette.sort(key=lambda rgb: cls.colorfulness(*rgb), reverse=True)
        return palette[0]
    @classmethod
    def __adjustPaletteValue(cls, palette: list):
        """ 调整调色板的明度 """
        newPalette = []
        for rgb in palette:
            h, s, v = cls.rgb2hsv(rgb)
            if v > 0.9:
                factor = 0.8
            elif 0.8 < v <= 0.9:
                factor = 0.9
            elif 0.7 < v <= 0.8:
                factor = 0.95
            else:
                factor = 1
            v *= factor
            newPalette.append(cls.hsv2rgb(h, s, v))
        return newPalette
    @staticmethod
    def rgb2hsv(rgb: tuple) -> tuple:
        """ rgb空间变换到hsv空间 """
        r, g, b = [i / 255 for i in rgb]
        mx = max(r, g, b)
        mn = min(r, g, b)
        df = mx - mn
        if mx == mn:
            h = 0
        elif mx == r:
            h = (60 * ((g - b) / df) + 360) % 360
        elif mx == g:
            h = (60 * ((b - r) / df) + 120) % 360
        elif mx == b:
            h = (60 * ((r - g) / df) + 240) % 360
        s = 0 if mx == 0 else df / mx
        v = mx
        return h, s, v
    @staticmethod
    def hsv2rgb(h, s, v) -> tuple:
        """ hsv空间变换到rgb空间 """
        h60 = h / 60.0
        h60f = floor(h60)
        hi = int(h60f) % 6
        f = h60 - h60f
        p = v * (1 - s)
        q = v * (1 - f * s)
        t = v * (1 - (1 - f) * s)
        r, g, b = 0, 0, 0
        if hi == 0:
            r, g, b = v, t, p
        elif hi == 1:
            r, g, b = q, v, p
        elif hi == 2:
            r, g, b = p, v, t
        elif hi == 3:
            r, g, b = p, q, v
        elif hi == 4:
            r, g, b = t, p, v
        elif hi == 5:
            r, g, b = v, p, q
        r, g, b = int(r * 255), int(g * 255), int(b * 255)
        return r, g, b
    @staticmethod
    def colorfulness(r: int, g: int, b: int):
        rg = np.absolute(r - g)
        yb = np.absolute(0.5 * (r + g) - b)
        rg_mean, rg_std = np.mean(rg), np.std(rg)
        yb_mean, yb_std = np.mean(yb), np.std(yb)
        std_root = np.sqrt(rg_std ** 2 + yb_std ** 2)
        mean_root = np.sqrt(rg_mean ** 2 + yb_mean ** 2)
        return std_root + 0.3 * mean_root
测试
下面是一些图片的测试结果,感觉效果还是挺不错的:

如何在 python 中提取图片主题色的更多相关文章
- 小技巧!CSS 提取图片主题色功能探索
		本文将介绍一种利用 CSS 获取图片主题色的小技巧.一起看看~ 背景 起因是微信技术群里有个同学发问,有什么方法能够获取图片的主色呢?有一张图片,获取他的主色调: 利用获取到的这个颜色值,来实现类似这 ... 
- 利用ROS工具从bag文件中提取图片
		bag文件是ROS常用的数据存储格式,因此要从bag文件中提取数据就需要了解一点ROS的背景知识. 1. 什么是ROS及其优势 ROS全称Robot Operating System,是BSD-lic ... 
- 如何在Python中从零开始实现随机森林
		欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 决策树可能会受到高度变异的影响,使得结果对所使用的特定测试数据而言变得脆弱. 根据您的测试数据样本构建多个模型(称为套袋)可以减少这种差异,但是 ... 
- 如何在Python 中使用UTF-8 编码 && Python 使用 注释,Python ,UTF-8 编码 , Python  注释
		如何在Python 中使用UTF-8 编码 && Python 使用 注释,Python ,UTF-8 编码 , Python 注释 PIP $ pip install beauti ... 
- 面试官问我:如何在 Python 中解析和修改 XML
		摘要:我们经常需要解析用不同语言编写的数据.Python提供了许多库来解析或拆分用其他语言编写的数据.在此 Python XML 解析器教程中,您将学习如何使用 Python 解析 XML. 本文分享 ... 
- 如何在Python中加速信号处理
		如何在Python中加速信号处理 This post is the eighth installment of the series of articles on the RAPIDS ecosyst ... 
- c# HTML中提取图片地址
		public class HtmlHelper { /// <summary> /// HTML中提取图片地址 /// </summa ... 
- [Linux] 如何在 Linux 中提取随机数
		如何在 Linux 中提取随机数 一.设备文件 /dev/random & /dev/urandom 字符特殊文件 /dev/random 和 /dev/urandom (存在于Linux 1 ... 
- C#从Gif中提取图片
		C#从Gif中提取图片的代码片段 private void btn_extract_Click(object sender, EventArgs e) { Image imgGif = Image.F ... 
随机推荐
- ios离线打包报错Showing Recent Messages :-1: HBuilder has conflicting provisioning settings. HBuilder is automatically signed for development, but a conflicting code signing identity iPhone Distribution has
			1.解决方案找到项目工程文件右击->显示包内容->双击project.pbxproj->搜索distribution改写成Developer 
- 剖析Defi之Uinswap_1
			学习UniswapERC20,它是交易对的父合约.UniswapV2ERC20 是流动性代币合约,也称为 LP Token.功能主要实习ERC20代币功能以及对线下签名授权. 1 pragma sol ... 
- tcache BUUCTF gyctf_2020_signin
			Ubuntu18.04的题 用到了两个特性: 一个是 calloc 的特点:不会分配 tcache chunk 中的 chunk 另一个是 tcache 的特点:在分配 fastbin 中的 chun ... 
- 使用 DML语句,对 “锦图网” 数据进行操作,聚合函数练习
			查看本章节 查看作业目录 需求说明: 根据客户 ID 统计订单数.订单总金额.最高订单金额.最低订单金额和每份订单平均金额,并按订单总金额升序显示 根据客户统计订单总订购人次数> 5 的统计信息 ... 
- .NET 编码的基础知识
			.NET 编码的一些基本概念和分析 简单的类型概念 Hex (16进制) byte 字节 范围是:0~255,二进制下的范围就是00000000~11111111,相当于1字节. byte[] 字节数 ... 
- .net core的配置介绍(三):Options
			前两篇介绍的都是已IConfiguration为基础的配置,这里在说说.net core提供的一种全新的辅助配置机制:Options. Options,翻译成中文就是选项,可选择的意思,它依赖于.ne ... 
- Hadoop开启Kerberos安全模式
			Hadoop开启Kerberos安全模式, 基于已经安装好的Hadoop的2.7.1环境, 在此基础上开启Kerberos安全模式. 1.安装规划 已经安装好Hadoop的环境 10.43.159.7 ... 
- nginx配置图片路径
			首先, 在linux下创建你存放资源的目录,例如:/data/images:用于存放图片. 下一步,打开default.conf配置文件找到server块下的location添加如下 location ... 
- golang strings.Split函数
			golang strings.Split函数 https://play.studygolang.com/ package main import ( "fmt" "str ... 
- Java 单引号 与 双引号 区别
			双引号,用来引用字符串, 单引号用来表示单个字符. 
