资讯详情

资讯详情

亮度与颜色:从人眼感知到Lab空间调色与代码实现

1. 从“亮度与颜色”说起为什么这个基础概念值得单独拎出来讲做图像处理、摄影后期、UI设计甚至视频调色的朋友大概率都遇到过这样的场景明明两个颜色的色相看起来差不多放到一起却一个显得“亮”一个显得“暗”或者调色时把亮度拉高颜色却莫名其妙变“灰”了。这些问题的根源都指向同一个基础但极易被忽视的知识点——亮度与颜色之间的关系。“第一篇 关于亮度与颜色的理解”这个标题乍看像是某个系列笔记的开篇实际上它触及的是色彩科学里最核心的一对概念。不管你是刚接触图像处理的新手还是已经能熟练操作各种调色工具的老手把亮度和颜色的关系彻底理清楚后面很多操作都会变得有据可依而不是靠感觉瞎调。这篇文章适合谁看如果你是摄影爱好者想搞明白为什么同一场景不同曝光下颜色感觉完全不同如果你是前端或UI开发者想弄清楚为什么同一个色值在不同亮度背景下看起来不一样如果你是图像算法工程师想从数学层面理解亮度通道和色度通道为什么要分离——那这篇内容都能给你一个清晰的框架。我会从人眼感知原理讲起一直落到实际调色和代码实现中的具体操作尽量把每个“为什么”都说明白。2. 亮度与颜色的底层逻辑人眼到底是怎么“看”的2.1 亮度不是颜色的附属品而是独立通道很多人初学色彩时习惯把亮度当成颜色三属性色相、饱和度、明度里的一个维度。这个理解不算错但容易让人忽略一个关键事实在人眼的视觉系统中亮度信息的处理优先级远高于颜色信息。从生理结构上说人眼视网膜上的视杆细胞负责感知明暗视锥细胞负责感知颜色。视杆细胞的数量大约有1.2亿个而视锥细胞只有600万到700万个而且视锥细胞主要集中在中央凹区域。这意味着人眼对亮度的敏感度远高于对颜色的敏感度。举个生活中的例子傍晚光线很暗的时候你还能看清物体的轮廓和明暗关系但颜色几乎分辨不出来整个世界像黑白电视一样。这就是因为视杆细胞还在工作而视锥细胞已经基本罢工了。这个生理事实直接影响了图像编码的设计。几乎所有主流的图像和视频编码格式都会把亮度信息Luma和色度信息Chroma分开存储而且色度信息还会被降采样。比如常见的YUV 4:2:0格式亮度通道保留全分辨率两个色度通道各自只保留四分之一的数据量。为什么敢这么干就是因为人眼对色度细节不敏感丢掉一些也看不出来但亮度细节一旦丢失画面立刻就会显得模糊。2.2 亮度与明度两个容易混淆的概念在继续深入之前有必要先把两个词区分清楚亮度Luminance和明度Lightness/Brightness。亮度通常指物理上的光强是一个客观的、可以用仪器测量的量单位是坎德拉每平方米cd/m²。而明度是人眼对亮度的主观感知是一个心理物理量。两者之间不是简单的线性关系而是近似幂函数关系。这就是为什么在暗部调整亮度时人眼感觉变化很明显而在亮部调整同样的物理量感觉却没那么明显。在实际操作中这个区别非常重要。比如你在调色软件里把某个颜色的亮度值从10调到20和从200调到210虽然数值上都增加了10但人眼感知到的变化幅度完全不同。前者看起来变化很大后者几乎看不出来。理解这一点你就能明白为什么很多调色工具在暗部和亮部使用不同的调整曲线而不是简单地把所有像素加同一个值。2.3 颜色模型中的亮度通道HSL、HSV与Lab不同的颜色模型对亮度的定义方式不同这也是很多人在转换颜色空间时感到困惑的原因。HSL模型里的L代表Lightness取值范围是0到100%。当L0时是黑色L100%时是白色L50%时是纯色。这个模型的优点是直观但缺点是它的亮度定义和实际感知亮度不完全一致。比如纯黄色H60S100%L50%和纯蓝色H240S100%L50%在HSL里L值相同但人眼看起来黄色明显比蓝色亮得多。HSV模型里的V代表Value取值范围也是0到100%。V0是黑色V100%是颜色最鲜艳的状态。和HSL的区别在于HSV里的V并不直接对应感知亮度它更像是“颜色有多亮”的一个粗略描述。Lab颜色模型则更接近人眼感知。L通道代表亮度取值范围是0到100a和b通道代表色度。Lab模型的优势在于它的L通道是真正基于人眼感知均匀性设计的两个颜色在Lab空间里的距离和人眼感知到的差异基本成正比。这也是为什么在做颜色差异计算时专业人士更倾向于用Lab而不是RGB或HSL。提示如果你在做UI设计时需要确保两个颜色在视觉上有足够的对比度用Lab空间的L值来判断比用HSL的L值更靠谱。WCAG无障碍标准里的对比度计算本质上也是在模拟人眼对亮度的感知。3. 亮度变化如何影响颜色感知几个必须理解的效应3.1 贝佐尔德-布吕克效应亮度变了色相也会变这个效应名字听起来很学术但现象你肯定见过。简单说就是当光照强度改变时人眼感知到的色相会发生偏移。具体来说短波长的颜色比如蓝色在亮度降低时看起来会更暗更偏黑而长波长的颜色比如红色和黄色在亮度降低时相对保持得更好。这个效应在摄影里非常实用。比如你在傍晚拍日落天空的蓝色会显得特别深而太阳附近的橙红色却依然鲜艳。这不是相机的问题而是人眼在低照度下的自然反应。理解这一点你在后期调色时就不会强行把暗部的蓝色提亮到和白天一样因为那样反而会显得不自然。3.2 同时对比效应同一个颜色放在不同背景上看起来不一样这是最经典的颜色感知现象之一。同一个灰色方块放在黑色背景上看起来比放在白色背景上要亮得多。这不是错觉而是人眼视觉系统在“自动白平衡”——它会根据周围环境的亮度来调整对中心区域亮度的判断。这个效应在实际设计中的应用非常广泛。比如深色模式下的按钮颜色如果直接沿用浅色模式下的色值往往会显得过于刺眼或过于暗淡。因为背景亮度变了人眼对同一个色值的感知也变了。正确的做法是在深色模式下适当降低主色的饱和度或调整亮度让它在深色背景上看起来和谐。3.3 亮度对饱和度感知的影响还有一个容易被忽略的点亮度的变化会影响人眼对饱和度的感知。一般来说当亮度接近极值特别暗或特别亮时颜色的饱和度看起来会降低。这就是为什么在很暗的环境下颜色看起来都灰蒙蒙的而在过曝的照片里颜色也会显得发白。这个原理在调色时非常关键。如果你想让某个颜色看起来更鲜艳不一定非要加饱和度有时候适当调整亮度反而效果更好。反过来如果你发现调完亮度后颜色变灰了也不要急着加饱和度先检查一下是不是亮度调整过度导致颜色进入了感知上的“低饱和区”。4. 实操在常见工具中正确处理亮度与颜色4.1 在图像编辑软件中分离亮度与颜色以常见的图像编辑软件为例很多工具都提供了“明度”调整图层或“亮度/对比度”调整图层。这两者的区别在于明度调整通常是在HSL或Lab空间里只动L通道而亮度/对比度调整则是在RGB空间里做线性或非线性变换。如果你只想改变画面的明暗而不影响颜色优先选择“明度”调整。如果你需要同时调整对比度和亮度用“亮度/对比度”更直接但要注意它可能会让颜色产生轻微偏移。一个实用的技巧是先复制一层原图把混合模式改为“明度”然后在这层上做曲线或色阶调整。这样调整的结果只会影响亮度不会动到色相和饱和度。这个方法在需要精细控制颜色不变的情况下非常有用。4.2 在代码中处理亮度与颜色以Python为例如果你是用代码处理图像理解颜色空间的转换就更为重要。下面是一个简单的示例展示如何在Python中分离亮度通道并单独调整import cv2 import numpy as np # 读取图像 img cv2.imread(input.jpg) # 转换到Lab颜色空间 lab cv2.cvtColor(img, cv2.COLOR_BGR2LAB) # 分离L、a、b通道 l, a, b cv2.split(lab) # 对L通道做亮度调整这里增加20 l_adjusted cv2.add(l, 20) # 合并通道并转回BGR lab_adjusted cv2.merge((l_adjusted, a, b)) result cv2.cvtColor(lab_adjusted, cv2.COLOR_LAB2BGR) cv2.imwrite(output.jpg, result)这段代码的关键在于调整只在L通道上进行a和b通道保持不变。这样处理的结果是画面的明暗变了但颜色的色相和饱和度基本不受影响。如果你直接在RGB通道上加同一个值颜色的色相和饱和度都会发生偏移。注意在Lab空间里调整L通道时要注意数值范围。OpenCV中L通道的范围是0到255但实际有效的感知亮度范围并不是线性的。如果你需要更精细的控制可以先把L通道归一化到0到100调整后再映射回去。4.3 在UI设计中处理亮度与颜色做UI设计时亮度与颜色的关系直接影响可读性和美观度。一个常见的需求是给定一个主色生成一系列不同亮度的变体用于按钮的默认、悬停、按下等状态。如果直接在HSL里调整L值你会发现生成的变体在视觉上并不均匀。比如从L50调到L60和从L80调到L90感知上的变化幅度差别很大。更好的做法是在Lab空间里做等距调整或者使用一些设计系统里推荐的亮度阶梯算法。一个实用的经验法则是对于深色背景上的文字亮度对比度至少要达到4.5:1对于大号文字可以放宽到3:1。这个标准是基于人眼在正常光照条件下的感知能力制定的能保证绝大多数用户都能清晰阅读。5. 常见问题与排查技巧实录5.1 为什么调完亮度后颜色变灰了这是最常见的问题之一。原因通常有两种一是在RGB空间里直接做了线性亮度调整导致颜色的饱和度在感知上被稀释二是调整幅度过大颜色进入了感知上的低饱和区。解决方法优先在Lab或HSL空间里只调整亮度通道如果必须在RGB空间操作调整后适当补充一点饱和度。但要注意补充饱和度时不要过头否则颜色会显得不自然。5.2 为什么同一个色值在不同设备上看起来亮度不同这个问题涉及到设备的色彩管理和屏幕的伽马曲线。不同屏幕的伽马值可能不同导致同一个色值在不同设备上的实际显示亮度有差异。此外屏幕的色域覆盖范围也会影响颜色的感知亮度。解决方法在关键项目中尽量使用经过校准的显示器并且在多个设备上做交叉验证。对于Web项目可以使用CSS的color()函数指定Lab或LCH颜色让浏览器自动做色彩管理。5.3 如何判断两个颜色的亮度差异是否足够一个简单的方法是把两个颜色都转成灰度图然后比较灰度值。如果灰度值差异很小说明亮度对比不足。更精确的方法是计算Lab空间里的L值差异或者直接计算WCAG对比度。下面是一个快速计算对比度的Python函数def relative_luminance(rgb): 计算相对亮度输入为0-255的RGB元组 def adjust(c): c c / 255.0 return c / 12.92 if c 0.03928 else ((c 0.055) / 1.055) ** 2.4 r, g, b rgb return 0.2126 * adjust(r) 0.7152 * adjust(g) 0.0722 * adjust(b) def contrast_ratio(rgb1, rgb2): l1 relative_luminance(rgb1) l2 relative_luminance(rgb2) lighter max(l1, l2) darker min(l1, l2) return (lighter 0.05) / (darker 0.05)这个函数返回的对比度值如果大于4.5说明在正常光照下可读性良好如果小于3就需要调整了。5.4 常见问题速查表问题现象可能原因排查方法解决思路调亮度后颜色变灰RGB空间线性调整导致饱和度感知下降检查调整所在颜色空间改用Lab或HSL只调L通道同一色值不同设备亮度不同屏幕伽马和色域差异多设备交叉验证使用色彩管理指定Lab色值暗部颜色看不清亮度对比不足计算WCAG对比度提高亮度差或调整色相亮部颜色发白亮度接近极值导致饱和度感知降低检查L值是否超过90适当降低亮度或增加饱和度深色模式颜色刺眼背景亮度变化导致感知对比过强在深色背景下重新评估降低主色饱和度或调整亮度6. 几个容易被忽略的实操心得第一个心得在调整亮度时养成先转Lab空间的好习惯。虽然多了一步转换但能避免很多颜色偏移的问题。尤其是在处理肤色时Lab空间的优势非常明显因为肤色对色相和饱和度的变化非常敏感而在Lab里只动L通道基本不会影响肤色的自然感。第二个心得做亮度阶梯时不要等距调整L值。人眼对亮度的感知是非线性的等距调整会导致暗部变化太剧烈、亮部变化太微弱。一个实用的做法是在暗部用较小的步长在亮部用较大的步长。比如从L20到L30算一档从L80到L95算一档。第三个心得测试亮度对比时不要只看数值一定要用眼睛实际看。数值达标不代表视觉上舒适。有时候两个颜色的对比度数值很高但因为色相搭配不当看起来依然很累眼。反过来有些对比度数值不高的组合因为色相和谐反而看起来很舒服。第四个心得在处理视频或动画时亮度变化的速度也会影响感知。快速变化的亮度会让人眼来不及适应产生闪烁感。所以在做亮度渐变时要给足过渡时间避免突变。这个主题往下还可以延伸到很多方向比如HDR视频里的亮度映射、不同色彩空间之间的转换精度、以及亮度对情绪感知的影响等等。但把上面这些基础打牢后面遇到具体问题时就不会慌因为你知道该从哪里入手去分析和解决。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →