使用Pillow Image.get_colors()提取图像常见颜色结果异常问题
图像Top10常见颜色提取结果差异问题分析
问题背景
我用PIL编写了提取图像Top10常见颜色的代码,通过获取图像所有颜色后筛选出现次数最多的10种,但结果与在线工具完全不同,想排查是PIL颜色处理方式差异还是代码逻辑问题。
我的代码
from PIL import Image img = Image.open(image_url) all_colors = img.getcolors(maxcolors=100000) # 获取图像所有颜色 top_10_colors = all_colors[:10] # 取前10个作为初始列表 for color in all_colors[9:]: amount = color[0] top_indexes = [] for top_color in top_10_colors: top_index = top_color[0] top_indexes.append(top_index) if amount > min(top_indexes): index = top_indexes.index(min(top_indexes)) top_10_colors[index] = color sorted_top_colors = sorted(top_10_colors, key=lambda x: x[0], reverse=True) print(sorted_top_colors) print(top_10_colors)
在线工具结果(从多到少排序)
rgb(49,49,49) rgb(211,211,211) rgb(67,67,67) rgb(71,71,71) rgb(61,61,61) rgb(79,79,79) rgb(166,82,19) rgb(70,70,70) rgb(65,65,65) rgb(29,28,28)
我的结果(从多到少排序)
[(35, 35, 35), (41, 41, 41), (36, 36, 36), (34, 34, 34), (44, 44, 44), (33, 33, 33), (31, 31, 31), (42, 42, 42), (50, 50, 50), (32, 32, 32)]
示例图像

问题原因
getcolors()返回顺序不按计数排序:你直接取all_colors[:10]作为初始Top10列表是错误的,这个方法返回的(计数, 颜色)元组按图像像素扫描顺序排列,而非计数从高到低排序,导致初始列表都是随机的低计数颜色。- 在线工具做了颜色聚类:在线工具返回的是合并相似颜色后的结果(比如把相近灰度色归为一类),而你的代码统计的是原始图像中每个精确RGB值的单独出现次数,这是结果差异的核心原因之一。
- 筛选逻辑依赖错误初始值:即使后续循环试图替换低计数颜色,由于初始列表本身就不具备参考性,最终结果无法反映真实的高频颜色。
修正方案
方案1:统计精确高频颜色
直接对getcolors()结果按计数降序排序后取前10,无需复杂循环:
from PIL import Image img = Image.open(image_url) # 用图像总像素数设置maxcolors,避免颜色截断 total_pixels = img.width * img.height all_colors = img.getcolors(maxcolors=total_pixels) # 按出现次数降序排序 sorted_colors = sorted(all_colors, key=lambda x: x[0], reverse=True) # 获取Top10颜色(包含计数) top_10_with_count = sorted_colors[:10] # 仅提取RGB值 top_10_rgb = [color[1] for color in top_10_with_count] print("Top10颜色(含计数):", top_10_with_count) print("Top10RGB值:", top_10_rgb)
方案2:颜色聚类(贴近在线工具结果)
如果想和在线工具结果一致,需要对像素颜色做聚类,合并相似颜色:
from PIL import Image import numpy as np from sklearn.cluster import KMeans img = Image.open(image_url) # 转换为像素数组 pixels = np.array(img).reshape(-1, 3) # K-means聚类成10类 kmeans = KMeans(n_clusters=10, random_state=42) kmeans.fit(pixels) # 获取聚类中心(合并后的颜色) cluster_colors = kmeans.cluster_centers_.astype(int) # 统计每类像素数量 counts = np.bincount(kmeans.labels_) # 按数量降序排序 sorted_clusters = sorted(zip(counts, cluster_colors), key=lambda x: x[0], reverse=True) # 输出结果 for count, color in sorted_clusters: print(f"rgb{tuple(color)}: {count}次")
内容的提问来源于stack exchange,提问作者Aadvik
相关产品推荐
相关产品推荐

