分割图像各颜色像素总数统计的代码问题与优化方案咨询

现有代码问题
- 逐像素调用
getpixel遍历效率极低,且PIL的该接口在批量处理时容易出现性能瓶颈,同时默认的convert('RGB')处理带透明通道的PNG时,透明像素转换规则未显式指定,可能生成意料之外的RGB值 - 严格匹配RGB元组的计数逻辑不兼容有压缩杂色、抗锯齿边缘的图像,你预期的三类颜色会被拆分成多个近似色的零散计数,无法得到三类的总和
- 图例生成逻辑写死了
arialbd.ttf字体路径,在Linux、macOS等无该字体的系统会直接报错 ignore_color参数用literal_eval解析,用户输入格式不匹配时会直接抛出未捕获的异常,容错性差
替代实现方案
直接基于numpy实现,效率是逐像素遍历的数百倍,支持可选的颜色聚类功能,适配存在杂色的分割图场景:
import numpy as np from PIL import Image import webcolors def count_color_pixels(img_path, target_colors=None): """ 统计图像各颜色像素数 :param img_path: 待处理图像路径 :param target_colors: 可选,要统计的目标颜色列表,格式为[(R,G,B),...],传入后会将所有近似色自动归类到最近的目标色 :return: 颜色计数字典,key为RGB元组,value为对应像素数 """ # 读取图像转RGB格式 img = Image.open(img_path).convert('RGB') # 转numpy数组后拉平为像素列表 pixel_arr = np.array(img).reshape(-1, 3) # 统计所有唯一颜色和对应计数 unique_rgb, counts = np.unique(pixel_arr, axis=0, return_counts=True) count_res = {} if target_colors is None: # 无目标色时直接返回所有唯一颜色的计数 for rgb, cnt in zip(unique_rgb, counts): count_res[tuple(rgb)] = cnt else: # 有目标色时做颜色聚类 for color in target_colors: count_res[color] = 0 for rgb, cnt in zip(unique_rgb, counts): # 计算到所有目标色的欧氏距离,取最近的归类 dist_list = [np.linalg.norm(rgb - np.array(t)) for t in target_colors] nearest_color = target_colors[np.argmin(dist_list)] count_res[nearest_color] += cnt return count_res # 调用示例,针对你提供的分割图预设黑、红、黄三个目标色 if __name__ == "__main__": target = [(0,0,0), (255,0,0), (255,255,0)] res = count_color_pixels("UMN9c.png", target_colors=target) print("像素计数结果:") for rgb, cnt in res.items(): try: color_name = webcolors.rgb_to_name(rgb) except ValueError: color_name = str(rgb) print(f"{color_name}: {cnt}") # 校验总像素数是否等于图像宽高乘积 w, h = Image.open("UMN9c.png").size print(f"总像素数校验:统计总和{sum(res.values())},图像实际总像素{w*h}")
如果你的图像确实是纯三色无杂色,不传入target_colors参数也能得到准确计数,总像素数校验一致即代表统计结果正确。
内容的提问来源于stack exchange,提问作者DevanDev
相关产品推荐
相关产品推荐

