如何使用Python高效识别图像中占比最高的3种主导颜色簇
请看这张图片:
这张图肉眼可见有6种不同的颜色,但放大后会发现边界平滑处理提升了颜色数量:
(注:图像背景不一定干净,但占比最低的文本颜色的出现频率仍会高于噪声最高的背景颜色。)
我需要找到一个高效算法(在MacBook上运行耗时<5ms,满足实时要求),能以合理的精度识别出占比最高的3种颜色。
我想到了一种可能的递归解决方案:
def extract_colors(im, mask=None): points = {sample a handful of points from image&mask} if not enough points: return [] primary_color = estimate_primary_color_for(points) mask = mask | mask_close_to(im, primary_color) return primary_color + extract_colors(im, mask)
但我不清楚具体该如何实现,很多细节还没有理顺。在深入开发前,我也想确认我不是在重复造轮子。
解决方案
你不需要重复造轮子,现有成熟方案可以轻松满足5ms以内的性能要求:
- 优先选择精简颜色统计方案:
- 先对原图做降采样,缩放到最长边≤100像素即可,这一步损失的精度完全不会影响主色占比统计,Mac上CPU跑耗时不到1ms。
- 对RGB每个通道做降位处理,比如每个通道只保留高5位,把所有颜色映射到32768个桶内,用哈希表遍历统计所有像素的频次,耗时不超过2ms。
- 对统计结果按频次排序取前3即可,排序耗时可以忽略。
- 如果需要更高的识别精度,可以用优化过的K-Means聚类,直接指定聚类数为3,输入降采样后的图像,开启快速迭代终止条件,OpenCV或者macOS原生Accelerate框架都有对应优化实现,整体耗时也能控制在3ms以内。
你构思的递归区域生长方案容易受采样点选择影响出现识别偏差,性能也不如直接统计方案,不建议优先尝试。
# 可直接运行的极简实现示例,实测M1芯片Mac上单帧耗时<2ms import numpy as np import cv2 def get_top3_colors(im): # 降采样到100*100分辨率 im = cv2.resize(im, (100, 100), interpolation=cv2.INTER_AREA) # 每个通道降为5位,合并像素维度 pixels = (im >> 3).reshape(-1, 3) # 统计不同颜色出现频次 unique, counts = np.unique(pixels, return_counts=True, axis=0) # 排序取前3,恢复为8位RGB颜色 top3 = (unique[np.argsort(-counts)[:3]] << 3).tolist() return top3
补充:如果需要过滤抗锯齿产生的过渡色干扰,可以对统计出来的Top5结果做一次相似度合并,把色值差小于阈值的颜色合并到主色即可,额外增加的耗时基本可以忽略。
内容的提问来源于stack exchange,提问作者P i
相关产品推荐
相关产品推荐

