Python图像颜色量化实战:从提取到可视化

月亮慢半拍
月亮慢半拍
发布时间:2026-10-15 | 4人浏览过
原创

本文介绍如何使用Python进行图像颜色量化。通过调整图像尺寸优化处理速度,利用extcolors库提取主色并设置容差与数量限制,再将RGB转换为HEX代码。最终通过Matplotlib生成饼图与色板,直观展示图像中的主要色彩分布及占比。

一、选择图片

首先确定需要处理的图像素材。这里以一张包含海水与椰子树的风景照作为示例进行演示。

二、创建脚本

1、导入相关库

随后导入所需的Python库。主要使用extcolors库来获取图像的RGB颜色值,并配合rgb2hex库将这些RGB值转换为标准的HEX颜色代码。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.image as mpimg
 
from PIL import Image
from matplotlib.offsetbox import OffsetImage, AnnotationBbox

若在导入上述库时遇到报错,可能需要安装相关的依赖包以确保功能正常运行。具体的依赖安装命令见下方代码。请取消代码中!pip前的#号注释符后运行安装脚本。注意,版本号前的#号仅作为注释保留,切勿删除。

#!pip install easydev                 #version 0.12.0
#!pip install colormap                #version 1.0.4
#!pip install opencv-python           #version 4.5.5.64
#!pip install colorgram.py            #version 1.2.0
#!pip install extcolors               #version 1.0.0
import cv2
import extcolors
from colormap import rgb2hex

2、创建方法

接下来逐步解析构建颜色提取函数的具体逻辑。若希望直接获取完整函数定义,请对函数定义部分进行评分或关注。

调整图像大小

处理流程始于对输入图像的预处理。现代数码相机或智能手机拍摄的照片分辨率极高,部分甚至超过50兆像素,而4K显示器的有效显示像素仅约8.3兆。若直接处理如此庞大的图像数据,计算耗时将显著增加。

因此,首要步骤是对图像进行缩放处理。下方代码展示了将图片宽度调整为900像素的方法。若原图尺寸较小或计算机CPU性能强劲,可跳过此步,或适当提高输出分辨率数值。需注意,调整大小后的新图像将保存至本地,以便后续步骤读取。

input_name = '<photo location/name>'
output_width = 900                   #set the output size
img = Image.open(input_name)
wpercent = (output_width/float(img.size[0]))
hsize = int((float(img.size[1])*float(wpercent)))
img = img.resize((output_width,hsize), Image.ANTIALIAS)
 
#save
resize_name = 'resize_' + input_name  #the resized image name
img.save(resize_name)                 #output location can be specified before resize_name
 
#read
plt.figure(figsize=(9, 9))
img_url = resize_name
img = plt.imread(img_url)
plt.imshow(img)
plt.axis('off')
plt.show()

颜色提取

利用extcolors库执行颜色提取操作。在此过程中,需配置以下关键参数:

容差(tolerance):用于对相似颜色进行分组,从而限制输出数量并优化视觉效果。该参数取值范围为0至100,其中0表示不进行任何颜色分组,而100表示将所有颜色合并为单一类别。

限制(limit):设定输出结果中保留的提取颜色数量的上限。

在示例代码中,将容差值设定为12,并将输出的颜色代码数量限制为11种(此处limit参数设为12,实际输出11种颜色)。这些数值可根据实际需求灵活调整。最终获取的结果将包含RGB颜色代码及其在图像中出现的频率。

colors_x = extcolors.extract_from_path(img_url, tolerance = 12, limit = 12)
colors_x

接着使用rgb2hex库定义一个转换函数,将RGB代码转换为HEX颜色代码,并构建DataFrame数据结构以存储结果。

def color_to_df(input):
    colors_pre_list = str(input).replace('([(','').split(', (')[0:-1]
    df_rgb = [i.split('), ')[0] + ')' for i in colors_pre_list]
    df_percent = [i.split('), ')[1].replace(')','') for i in colors_pre_list]
    
    #convert RGB to HEX code
    df_color_up = [rgb2hex(int(i.split(", ")[0].replace("(","")),
                          int(i.split(", ")[1]),
                          int(i.split(", ")[2].replace(")",""))) for i in df_rgb]
    
    df = pd.DataFrame(zip(df_color_up, df_percent), columns = ['c_code','occurence'])
    return df
 
df_color = color_to_df(colors_x)
df_color

绘制图标

list_color = list(df_color['c_code'])
list_precent = [int(i) for i in list(df_color['occurence'])]
text_c = [c + ' ' + str(round(p*100/sum(list_precent),1)) +'%' for c, p in zip(list_color,
                                                                               list_precent)]
fig, ax = plt.subplots(figsize=(90,90),dpi=10)
wedges, text = ax.pie(list_precent,
                      labels= text_c,
                      labeldistance= 1.05,
                      colors = list_color,
                      textprops={'fontsize': 120, 'color':'black'}
                     )
plt.setp(wedges, width=0.3)
 
#create space in the center
plt.setp(wedges, width=0.36)
 
ax.set_aspect("equal")
fig.set_facecolor('white')
plt.show()

#create background color
fig, ax = plt.subplots(figsize=(192,108),dpi=10)
fig.set_facecolor('white')
plt.savefig('bg.png')
plt.close(fig)
 
#create color palette
bg = plt.imread('bg.png')
fig = plt.figure(figsize=(90, 90), dpi = 10)
ax = fig.add_subplot(1,1,1)
 
x_posi, y_posi, y_posi2 = 320, 25, 25
for c in list_color:
    if  list_color.index(c) <= 5:
        y_posi += 125
        rect = patches.Rectangle((x_posi, y_posi), 290, 115, facecolor = c)
        ax.add_patch(rect)
        ax.text(x = x_posi+360, y = y_posi+80, s = c, fontdict={'fontsize': 150})
    else:
        y_posi2 += 125
        rect = patches.Rectangle((x_posi + 800, y_posi2), 290, 115, facecolor = c)
        ax.add_artist(rect)
        ax.text(x = x_posi+1160, y = y_posi2+80, s = c, fontdict={'fontsize': 150})
        
ax.axis('off')
plt.imshow(bg)
plt.tight_layout()

三、完整代码

为简化操作流程,resize路径已硬编码在程序中,请根据实际文件路径进行修改。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.image as mpimg
 
from PIL import Image
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
 
import cv2
import extcolors
 
from colormap import rgb2hex
 
def color_to_df(input):
    colors_pre_list = str(input).replace('([(', '').split(', (')[0:-1]
    df_rgb = [i.split('), ')[0] + ')' for i in colors_pre_list]
    df_percent = [i.split('), ')[1].replace(')', '') for i in colors_pre_list]
 
    # convert RGB to HEX code
    df_color_up = [rgb2hex(int(i.split(", ")[0].replace("(", "")),
                           int(i.split(", ")[1]),
                           int(i.split(", ")[2].replace(")", ""))) for i in df_rgb]
 
    df = pd.DataFrame(zip(df_color_up, df_percent), columns=['c_code', 'occurence'])
    return df
 
 
def exact_color(input_image, resize, tolerance, zoom):
    # background
    bg = 'bg.png'
    fig, ax = plt.subplots(figsize=(192, 108), dpi=10)
    fig.set_facecolor('white')
    plt.savefig(bg)
    plt.close(fig)
 
    # resize
    output_width = resize
    img = Image.open(input_image)
    if img.size[0] >= resize:
        wpercent = (output_width / float(img.size[0]))
        hsize = int((float(img.size[1]) * float(wpercent)))
        img = img.resize((output_width, hsize), Image.ANTIALIAS)
        resize_name = 'C:/Users/zyh/Desktop/resize_456.jpg'
        img.save(resize_name)
    else:
        resize_name = input_image
 
    # crate dataframe
    img_url = resize_name
    colors_x = extcolors.extract_from_path(img_url, tolerance=tolerance, limit=13)
    df_color = color_to_df(colors_x)
 
    # annotate text
    list_color = list(df_color['c_code'])
    list_precent = [int(i) for i in list(df_color['occurence'])]
    text_c = [c + ' ' + str(round(p * 100 / sum(list_precent), 1)) + '%' for c, p in zip(list_color, list_precent)]
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(160, 120), dpi=10)
 
    # donut plot
    wedges, text = ax1.pie(list_precent,
                           labels=text_c,
                           labeldistance=1.05,
                           colors=list_color,
                           textprops={'fontsize': 150, 'color': 'black'})
    plt.setp(wedges, width=0.3)
 
    # add image in the center of donut plot
    img = mpimg.imread(resize_name)
    imagebox = OffsetImage(img, zoom=zoom)
    ab = AnnotationBbox(imagebox, (0, 0))
    ax1.add_artist(ab)
 
    # color palette
    x_posi, y_posi, y_posi2 = 160, -170, -170
    for c in list_color:
        if list_color.index(c) <= 5:
            y_posi += 180
            rect = patches.Rectangle((x_posi, y_posi), 360, 160, facecolor=c)
            ax2.add_patch(rect)
            ax2.text(x=x_posi + 400, y=y_posi + 100, s=c, fontdict={'fontsize': 190})
        else:
            y_posi2 += 180
            rect = patches.Rectangle((x_posi + 1000, y_posi2), 360, 160, facecolor=c)
            ax2.add_artist(rect)
            ax2.text(x=x_posi + 1400, y=y_posi2 + 100, s=c, fontdict={'fontsize': 190})
 
    fig.set_facecolor('white')
    ax2.axis('off')
    bg = plt.imread('bg.png')
    plt.imshow(bg)
    plt.tight_layout()
    return plt.show()
exact_color('C:/Users/zyh/Desktop/456.jpg', 900, 12, 2.5)

运行结果如下

至此,关于使用Python进行图像颜色量化的介绍完毕。如需了解更多Python图像颜色量化相关内容,请查阅本站过往文章或继续浏览后续教程,感谢支持!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表