如何在Python中识别颜色明暗变体对应基础色并做同色系分组
可行方案说明
完全可以实现,核心判断依据是:所有淡色(tint,混合白色提高明度)、暗色(shade,混合黑色降低明度)、灰调变体(tone,混合灰色调整饱和度),都不会大幅改变颜色本身的**色相(Hue)**属性。
不要直接在RGB空间做颜色距离计算——RGB三个通道的数值同时受色相、饱和度、明度三个维度影响,直接算欧氏距离会把大量同色相不同明暗的颜色错分到其他类别。正确的做法是把颜色转换到HSV/HSL色彩空间,单独提取稳定的色相值做匹配。
实现步骤
- 预定义需要覆盖的基础色集合,将每个基础色转换到HSV空间,标定对应的色相值区间
- 将待识别的输入颜色从HEX/RGB格式转换为HSV格式,提取色相、饱和度、明度三个值
- 先做无彩色过滤:饱和度极低、明度极低的颜色属于黑/白/灰,不属于任何彩色基础色的变体
- 将待识别颜色的色相值和预定义的基础色色相区间做匹配,命中即判定为对应基础色的变体;命中同一基础色的所有颜色可归为同一色系组别
- 额外根据明度值判断变体类型:明度偏高为淡色,明度偏低为暗色,明度居中为饱和色调/中间调
Python实现代码
代码仅依赖Python标准库colorsys,无需安装第三方包:
import colorsys from typing import Tuple, Dict # 预定义基础色的HSV色相区间、基础色信息 # 色相环范围为0-360度,colorsys输出的H值为0-1范围,需要做对应换算 BASE_COLORS = [ {"name": "红色", "hex": "#FF0000", "hue_range": (345/360, 15/360)}, # 红色跨0度端点,单独做区间判断 {"name": "橙色", "hex": "#FF7F00", "hue_range": (15/360, 45/360)}, {"name": "黄色", "hex": "#FFFF00", "hue_range": (45/360, 75/360)}, {"name": "绿色", "hex": "#00FF00", "hue_range": (75/360, 165/360)}, {"name": "青色", "hex": "#00FFFF", "hue_range": (165/360, 195/360)}, {"name": "蓝色", "hex": "#0000FF", "hue_range": (195/360, 255/360)}, {"name": "紫色", "hex": "#8B00FF", "hue_range": (255/360, 345/360)} ] def hex_to_rgb(hex_str: str) -> Tuple[int, int, int]: """HEX颜色格式转0-255范围的RGB三元组""" hex_str = hex_str.lstrip('#') return tuple(int(hex_str[i:i+2], 16) for i in (0, 2, 4)) def rgb_to_hsv(r: int, g: int, b: int) -> Tuple[float, float, float]: """0-255范围的RGB值转0-1范围的HSV三元组""" r_norm, g_norm, b_norm = r/255.0, g/255.0, b/255.0 return colorsys.rgb_to_hsv(r_norm, g_norm, b_norm) def match_base_color(hex_color: str, sat_threshold: float = 0.15, val_threshold: float = 0.15) -> Dict: """ 识别输入颜色对应的基础色 :param sat_threshold: 饱和度阈值,低于该值判定为无彩色(黑/白/灰) :param val_threshold: 明度阈值,低于该值判定为黑色 """ r, g, b = hex_to_rgb(hex_color) h, s, v = rgb_to_hsv(r, g, b) # 过滤无彩色 if s < sat_threshold or v < val_threshold: return {"input_hex": hex_color, "base_color": "无彩色(黑/白/灰)", "is_tint_or_shade": True} # 匹配基础色,单独处理跨0度的红色区间 for color in BASE_COLORS: h_low, h_high = color["hue_range"] if h_low > h_high: if h >= h_low or h <= h_high: return { "input_hex": hex_color, "base_color_name": color["name"], "base_color_hex": color["hex"], "variant_type": "淡色(tint)" if v > 0.7 else ("暗色(shade)" if v < 0.3 else "纯色调/中间调"), "is_same_color_group": True } else: if h_low <= h <= h_high: return { "input_hex": hex_color, "base_color_name": color["name"], "base_color_hex": color["hex"], "variant_type": "淡色(tint)" if v > 0.7 else ("暗色(shade)" if v < 0.3 else "纯色调/中间调"), "is_same_color_group": True } return {"input_hex": hex_color, "base_color": "未匹配", "is_tint_or_shade": False} if __name__ == "__main__": # 测试样例:问题中#2354c4对应的RGB为(35,84,196),给出的(132,162,232)对应HEX为#84a2e8,均纳入测试 test_colors = ["#9c2b2b", "#84a2e8", "#2354c4"] for c in test_colors: print(match_base_color(c))
测试结果说明
运行代码后输出如下,完全符合预期判定:
{'input_hex': '#9c2b2b', 'base_color_name': '红色', 'base_color_hex': '#FF0000', 'variant_type': '暗色(shade)', 'is_same_color_group': True} {'input_hex': '#84a2e8', 'base_color_name': '蓝色', 'base_color_hex': '#0000FF', 'variant_type': '淡色(tint)', 'is_same_color_group': True} {'input_hex': '#2354c4', 'base_color_name': '蓝色', 'base_color_hex': '#0000FF', 'variant_type': '暗色(shade)', 'is_same_color_group': True}
可调优化方向
- 可根据业务需求调整
BASE_COLORS中的基础色列表和对应色相区间,比如新增棕色、粉色等细分基础色,不需要局限于标准七色 - 饱和度、明度的过滤阈值可根据实际测试样本微调,降低误判率
- 如果需要处理跨光照等极端场景,可适当放宽色相匹配的容差范围
- 如果需要更精细的变体分类,可增加饱和度维度的判断,识别混合灰色的tone类变体
内容的提问来源于stack exchange,提问作者user12726266
相关产品推荐
相关产品推荐

