Python colorsys 标准库深入解析:RGB/YIQ/HLS/HSV 颜色空间双向转换全指南

发布时间:2026/9/7 2:47:27
Python colorsys 标准库深入解析:RGB/YIQ/HLS/HSV 颜色空间双向转换全指南 Python colorsys 标准库深入解析RGB/YIQ/HLS/HSV 颜色空间双向转换全指南【免费下载链接】cpythonThe Python programming language项目地址: https://gitcode.com/GitHub_Trending/cp/cpythoncolorsys是 Python 标准库中负责颜色系统之间双向转换的轻量模块。它以显示器普遍采用的 RGB红绿蓝坐标为基准提供与 YIQ、HLS色调/亮度/饱和度、HSV色调/饱和度/明度三种坐标系统互相转换的全部六个函数。本文以 colorsys 官方文档 为主线结合模块完整实现 Lib/colorsys.py 与其单元测试 Lib/test/test_colorsys.py逐条讲解每个函数的数学原理、取值范围、浮点精度边界与经典应用场景帮助你在调色、取色、配色、图像处理与视频信号模拟等实践中安全、正确地完成颜色空间换算。模块定位从一段广播级视频标准说起colorsys的设计目标非常聚焦同一颜色在不同坐标体系中的数值映射。模块文档明确指出它支持在显示器使用的 RGB 空间与三种其他坐标系统之间做双向bidirectional转换YIQ亮度Luminance 色度Chrominance历史上用于 NTSC 复合视频信号HLS色调Hue、亮度/明度Lightness、饱和度SaturationHSV色调Hue、饱和度Saturation、明度值Value。模块源码首部的模块 docstringLib/colorsys.py用一句话概括了 API 形态对每个颜色系统 ABC提供一对函数rgb_to_abc(r, g, b)与abc_to_rgb(a, b, c)两者互为逆运算。文档亦在「另见」中指引读者前往色彩学资料如 Poynton 的 ColorFAQ 等站点深入了解各颜色空间的背景理论。取值范围约定浮点三元组所有坐标都以浮点数表达模块 docstring 与文档正文给出了精确的边界约定绝大多数空间中坐标均处于[0.0, 1.0]区间内唯一的例外是 YIQ 中的 I 与 Q 分量——Y 严格位于 0 到 1 之间0 为黑、1 为白而 I、Q 可以取正值或负值数值越界的输入不保证得到有意义的结果模块文档注释明确指出Inputs outside the valid range may cause exceptions or invalid outputs超界输入可能导致异常或无效输出因此调用方应自行保证输入在合法区间。这一约束还体现在测试对roundtrip往返一致性的验证方式上测试 Lib/test/test_colorsys.py 只在[0.0, 1.0]内以 0.2 步长枚举 RGB 输入再断言rgb - hsv - rgb能还原原值。六个转换函数的完整规格模块共导出 6 个函数对应 Lib/colorsys.py 中的__all__全部为纯函数、不依赖任何第三方库函数签名功能rgb_to_yiq(r, g, b)RGB 坐标 → YIQ 坐标yiq_to_rgb(y, i, q)YIQ 坐标 → RGB 坐标rgb_to_hls(r, g, b)RGB 坐标 → HLS 坐标hls_to_rgb(h, l, s)HLS 坐标 → RGB 坐标rgb_to_hsv(r, g, b)RGB 坐标 → HSV 坐标hsv_to_rgb(h, s, v)HSV 坐标 → RGB 坐标RGB → YIQ亮度分离的线性变换RGB 转 YIQLib/colorsys.py是线性组合其系数来自 FCC 版 NTSC 制式源码注释原文The ones in this library uses constants from the FCC version of NTSCdef rgb_to_yiq(r, g, b): y 0.30*r 0.59*g 0.11*b i 0.74*(r-y) - 0.27*(b-y) q 0.48*(r-y) 0.41*(b-y) return (y, i, q)其中 Y 是加权灰度值人眼对绿色最敏感故绿色权重 0.59 最高I、Q 携带色度信息。由于 RGB 坐标均在 [0,1]Y 必落在 [0,1]而 I、Q 则可正可负——这正是文档特别强调的范围例外。测试 test_yiq_values 中记录的典型端点值印证了这一点纯红(1,0,0)→(0.3, 0.599, 0.213)纯蓝(0,0,1)→(0.11, -0.3217, 0.3121)纯绿(0,1,0)→(0.59, -0.2773, -0.5251)纯白(1,1,1)→(1.0, 0.0, 0.0)纯灰(0.5,0.5,0.5)→(0.5, 0.0, 0.0)YIQ → RGB一个会做「钳位」的逆向逆变换同样以线性代数形式直接给出Lib/colorsys.pydef yiq_to_rgb(y, i, q): r y 0.9468822170900693*i 0.6235565819861433*q g y - 0.27478764629897834*i - 0.6356910791873801*q b y - 1.1085450346420322*i 1.7090069284064666*q if r 0.0: r 0.0 # ... g、b 同理 if r 1.0: r 1.0 # ... return (r, g, b)源码注释保留了手工推导过程以r y (0.27*q 0.41*i) / (0.74*0.41 0.27*0.48)等三个等式表示系数约为原分式展开后的浮点结果。注意这里存在有意为之的钳位clamping行为若计算结果超出 [0,1]会强制截断到边界。为什么需要钳位因为任意 YIQ 三元组并不都对应合法 RGB——例如测试 test_yiq_to_rgb_clamping 中的输入(0.25, -1.0, -1.0)与(0.0, -1.0, 0.5)本身来自非合法 RGB 的投影逆变换后会落在 RGB 立方体之外此时模块主动收敛到边界。这一点与 HSV/HLS 的逆变换行为不同属于 YIQ 系的独特语义务必在使用时留意。HLS 与 HSV两类色调-饱和度模型的转换细节HLS 与 HSV 都把颜色分解为Hue色相/色调、Saturation饱和度与一个亮度轴差异在于亮度轴与几何模型的定义。在colorsys中两者都采用归一化到 [0,1] 的色相——而不是图形软件常见的 0–360 度角。换算规则若你手中的色相以度为单位如hue120传入函数前请除以 360 得到hue/360.0模块内部用h/6.0 % 1.0等方式完成从六段扇形到单位圆的归约。从 min/max 求 HLSRGB 转 HLSLib/colorsys.py使用经典的 min/max 三分法def rgb_to_hls(r, g, b): maxc max(r, g, b) minc min(r, g, b) sumc (maxcminc) rangec (maxc-minc) l sumc/2.0 if minc maxc: return 0.0, l, 0.0 # 无彩色饱和度为 0 if l 0.5: s rangec / sumc # 公式 A else: s rangec / (2.0-maxc-minc) # 公式 Bgh-106498 rc (maxc-r) / rangec gc (maxc-g) / rangec bc (maxc-b) / rangec if r maxc: h bc-gc elif g maxc: h 2.0rc-bc else: h 4.0gc-rc h (h/6.0) % 1.0 return h, l, s关键点在于灰阶捷径当minc maxc即 RGB时直接返回(0.0, l, 0.0)色相取 0、饱和度取 0避免除零饱和度按亮度分支亮度l 0.5时用rangec / sumc否则用rangec / (2.0-maxc-minc)。源码注释特别注明后者Not always 2.0-sumc: gh-106498即接近白色如(0.9999999999999999, 1, 1)时直接写2.0-sumc会让分母趋近于 0、诱发除零/数值灾难故改用等价的2.0-maxc-minc。对应回归测试见 test_hls_nearwhite而仓库变更记录 Misc/NEWS.d/3.13.0a1.rst 也记载了一次导致除零的改动被回退的历史色相六段定位根据哪个通道取最大值用(maxc-某通道)/rangec之差确定色相所在扇区最后(h/6.0) % 1.0归约到 [0,1)。HLS 逆变换hls_to_rgbLib/colorsys.py先把问题归约为两基色m1、m2def hls_to_rgb(h, l, s): if s 0.0: return l, l, l if l 0.5: m2 l * (1.0s) else: m2 ls-(l*s) m1 2.0*l - m2 return (_v(m1, m2, hONE_THIRD), _v(m1, m2, h), _v(m1, m2, h-ONE_THIRD))辅助函数_v(m1, m2, hue)Lib/colorsys.py把色相折回单位圆后按1/6、1/2、2/3三个断点分段插值其中模块顶部预定义常量ONE_THIRD 1/3、ONE_SIXTH 1/6、TWO_THIRD 2/3Lib/colorsys.py。当s 0.0灰时三通道直接等于亮度 l避免无意义计算。测试锚点HLS 端点值表单元测试 test_hls_values 给出了直接可校验的锚点颜色RGBHLS黑(0,0,0)(0, 0.0, 0.0)白(1,1,1)(0, 1.0, 0.0)灰(0.5,0.5,0.5)(0, 0.5, 0.0)红(1,0,0)(0, 0.5, 1.0)绿(0,1,0)(2/6, 0.5, 1.0)蓝(0,0,1)(4/6, 0.5, 1.0)青(0,1,1)(3/6, 0.5, 1.0)注意同为主色其亮度恒为 0.5、饱和度恒为 1.0只是色相依次相差 1/6——这是 HLS 圆柱模型对纯色的标准描述。HSV最贴近取色器直觉的模型RGB 转 HSVLib/colorsys.py与前文 HLS 高度对称但明度轴V直接取三通道最大值def rgb_to_hsv(r, g, b): maxc max(r, g, b) minc min(r, g, b) rangec (maxc-minc) v maxc if minc maxc: return 0.0, 0.0, v s rangec / maxc # ... 色相扇区判断与 HLS 相同 return h, s, v而反向函数hsv_to_rgbLib/colorsys.py采用色相六边形hexcone的经典扇形划分算法def hsv_to_rgb(h, s, v): if s 0.0: return v, v, v i int(h*6.0) # 落入哪个 60° 扇区 f (h*6.0) - i # 扇区内的相对位置 p v*(1.0 - s) q v*(1.0 - s*f) t v*(1.0 - s*(1.0-f)) i i%6 # 依据 i 的值从 (v,t,p)/(q,v,p)/(p,v,t)/(p,q,v)/(t,p,v)/(v,p,q) 中选取 ...其中p、q、t是三条边上的插值量源码注释中的# XXX assume int() truncates!提示该实现依赖int()向零截断对负色相需先归约。当s 0.0时返回灰阶(v, v, v)。文档示例与测试锚点官方文档给出的示例恰好演示了这对函数的互逆性 import colorsys colorsys.rgb_to_hsv(0.2, 0.4, 0.4) (0.5, 0.5, 0.4) colorsys.hsv_to_rgb(0.5, 0.5, 0.4) (0.2, 0.4, 0.4)端点值表test_hsv_values进一步给出颜色RGBHSV黑(0,0,0)(0, 0.0, 0.0)白(1,1,1)(0, 0.0, 1.0)红(1,0,0)(0, 1.0, 1.0)黄(1,1,0)(1/6, 1.0, 1.0)绿(0,1,0)(2/6, 1.0, 1.0)青(0,1,1)(3/6, 1.0, 1.0)蓝(0,0,1)(4/6, 1.0, 1.0)品红(1,0,1)(5/6, 1.0, 1.0)对比可见两模型色相排序一致红→黄→绿→青→蓝→品红这也是测试test_hsv_values与test_hls_values共用同一组色相期望值的深层原因。精度、往返一致性与边界行为roundtrip为什么转过去再转回来基本还原测试套件为三组变换各实现了*_roundtrip用例Lib/test/test_colorsys.py做法一致在[0,1]网格上枚举 RGB → 转出 → 转回再用assertAlmostEqual约 7 位有效数字的浮点容差比对。之所以不能要求逐位相等是因为中间插值存在浮点舍入但对输入在合法域内的合法颜色往返误差始终被控制在可忽略量级。值得一提的例外是HLS 的近白区域test_hls_nearwhite针对 gh-106498注释明确写道 these do not work in reverse。例如rgb_to_hls(0.9999999999999999, 1, 1)得到(0.5, 1.0, 1.0)该元组再经hls_to_rgb只能回到纯白(1.0, 1.0, 1.0)——这是 HLS 模型在亮度极值附近饱和度定义固有的病态并非函数缺陷。实践启示不要对处于亮度极值0 或 1附近、以 HLS 为中间态的改饱和度再转回操作期待完美还原。色相的 360° 周期等价测试还显式验证了色相的整周期不变性Lib/test/test_colorsys.py对任意(h, s, v)hsv_to_rgb(h 1.0, s, v)与hsv_to_rgb(h, s, v)结果相同。这提醒使用者色相传入超界并不会报错模块按周期自动折回若你依赖输入越界即报错来做防御需要自行校验。YIQ 与 HLS/HSV 的钳位差异前文已述yiq_to_rgb会把结果硬性钳制到 [0,1]Lib/colorsys.py而 HLS/HSV 的逆变换则依赖公式本身的几何约束不做显式钳位。因此用任意 YIQ 元组做逆变换总能得到合法 RGB而用越界的 H/S/V做逆变换则可能得到超出 [0,1] 的通道值——需要时请自行 clamp。实战在 CPython 生态中如何使用标准用法colorsys是内置纯 Python 模块无需安装、不依赖 C 扩展直接导入即可import colorsys # 取色器拿到 #40ff80 这种 8 位十六进制颜色时先归一化 def hex_to_rgb01(hexstr): hexstr hexstr.lstrip(#) r, g, b (int(hexstr[i:i2], 16) for i in (0, 2, 4)) return r/255.0, g/255.0, b/255.0 r, g, b hex_to_rgb01(#40ff80) h, s, v colorsys.rgb_to_hsv(r, g, b) print(fH{h:.3f} ({h*360:.0f}°) S{s:.3f} V{v:.3f})输出形如H0.396 (143°) S0.749 V1.000。常见应用范式基于色相排序/分组把调色板中杂乱的颜色转成 HSV按 H 排序即可得到彩虹序统一明暗处理v * 0.8或l * 1.1后转回 RGB可实现不改色相的调亮/调暗GUI 控件高亮、主题调色器均可使用去饱和/灰化把s置 0 再转回即得对应灰度色彩对比分析用rgb_to_yiq提取 Y 亮度做前景/背景可读性粗判因其 Y 即加权灰度数学上等价于常见亮度公式0.299R0.587G0.114B的归一化版本转换门面层colorsys只接受 0–1 浮点很多配色库如 tkinter 颜色、matplotlib colormap输出都是 0–1 浮点可直接对接若处理 0–255 整数请先除以 255、输出前乘回 255 并四舍五入。数值合法性检查清单参照模块 docstring 与文档约定调用前建议自查RGB 三通道是否都在[0, 1]否则逆变换可能越界色相若以度为单位是否已/360.0归一化是否依赖往返无损若是避开 HLS 亮度≈0/≈1 的近白近黑区域YIQ 逆变换自带钳位其余逆变换的越界通道需自行 clamp。验证与迭代测试如何守护这 150 行代码整个模块连同注释不足 170 行却由一套相当完备的回归测试守护Lib/test/test_colorsys.py可作为修改或移植时的行为规格书test_hsv_roundtrip/test_hls_roundtrip/test_yiq_roundtrip全域网格往返一致性test_hsv_values/test_hls_values/test_yiq_values端点与基准色的数值锚点含负 I/Qtest_hls_nearwhitegh-106498近白区域的除零回归防护test_yiq_to_rgb_clamping非法 YIQ 输入的钳位行为。需要重新生成该模块文档时可参考仓库 Doc 构建体系如 Doc/README.rst而对colorsys做任何数学层面的改动都必须先跑通上述测试矩阵尤其是三组 roundtrip——它们是转换函数互为逆映射这一模块核心承诺的直接验证。小结colorsys用最少的 API 覆盖了四个颜色空间间的全部双向路径RGB 作为中枢与 YIQNTSC 线性亮度色度、HLS 与 HSV两类色调-饱和度圆柱相连。理解它的三个要点——浮点范围约定、色相归一化到 [0,1]、以及 HLS/HSV 与 YIQ 逆变换行为差异——就足以在生产代码中放心使用而 Lib/colorsys.py 与 Lib/test/test_colorsys.py 加起来不过三百余行本身也是一份纯 Python 数值算法 回归测试极佳的研读范本。【免费下载链接】cpythonThe Python programming language项目地址: https://gitcode.com/GitHub_Trending/cp/cpython创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考