年关将至,琐碎的事多了起来,前几天还回了趟温州,继而很是心寒:温州的人际关系实在过于复杂,看了很多所谓的亲朋好友为了点钱勾心斗角争吵不休的事,实在感到悲哀。曾经一度很想回温州工作,不过现在这情况看看觉得还是算了:待在杭州反倒清净一些,少了些无所谓的干扰,只可惜离父母远了些。回来以后一直没找到状态,而手头也没多少事,倒也落得清闲,可惜日报也只能随着清闲了。回来没几天又订了回去的火车票,在雪中排了一个多小时的票才买到,很是折腾。不过毕竟也算了了年底的最后一件大事,接下几天也就只用扫扫闪印和相片管家的尾,也好准备回家过大年了。年前再接再厉更新篇博文,讲讲关于色彩平衡。
什么是色彩平衡(Color Balance)
在图像处理和编辑中,对颜色强度(尤其是红,绿,蓝这种主色)进行全局调整即是色彩平衡。这种调整的一个重要目的是突出显示某种色调—-尤其是中立色。
图像编辑中的色彩平衡调整方法基本是直接操作RGB通道上的像素点,和其他场景下的色彩平衡很不一样。(比如摄影,是通过物理上的方法来实现:使用特殊镜头,特殊滤镜等)基于这个观点,亮度调整一文 中提到的各种方法都是可以来做色彩平衡(PS Tutorial):曲线调整,色阶调整等。只需要将作用通道设置为相应的色彩通道即可。在这里要罗嗦一句:在PS或者是GIMP提供的颜色相关的调整方法中,曲线调整的效果是最好的,因为它的参数完全是自定义的,最精细。
GIMP/PS中色彩平衡
PS和GIMP中都提供了独立色彩平衡功能,其界面和选项基本都是一样,如下图:
单纯从原理上来说,这种色彩平衡的实现也比较简单:
滚动条右边的显示的RGB,而左边显示的是CMYK色彩空间中的Cyan(青),Magenta(洋红),Yellow(黄)。RGB是一种加色模型(所谓的自发光),而CMYK是一种减色模型(吸收光)。其关系如下图所示:
可以看出,RGB的不同相加组合可以产生CMYK中的任意一种,而相应CMYK空间中各种色彩的缺失组合也可以产生RGB色彩空间中任意一种颜色。所以得出一个结论就是:所有加减色操作完全可以直接在RGB空间内完成,而不需要转换到CMYK色彩空间。比如增加红色就必然引起青色的减少。见过很多写法是先从RGB转换到CMYK空间再进行调整,调整完毕后再转换回来,不仅低效而且有画蛇添足之嫌。
然后就是对亮度区域的鉴别:阴影,中间调,高光。这三个概念相对而言比较模糊:并没有明确定义表示亮度超过多少可以认为是高光区,而亮度低于多少是阴影区,只有一个相对模糊的界定。而单个通道上的像素亮度并不能反映这个像素真实的亮度。所以在亮度区域的选择上只是反映了调整力度的大小,而并没有完全真实地反映调整区域范围。(如果进行亮度区域界定并对不同亮度区域进行调整,一来比较耗时间,而来也并不会取得太好的效果)
最下面的选项:保持明度。明度计算的公式为
Lightness = (Max(RGB) + Min(RGB)) / 2
因为直接操作了各个通道上的亮度值,整个像素点对应的明度也有可能发生变化,保持明度可以让用户感觉整个色彩平衡的变化更平滑。
原理讲完,上代码:
整个色彩平衡的过程很简单:先是初始化各个亮度区域的调整系数,再通过用户传入的调整系数调整相应的变化参数,最后计算得出调整色彩用的三个Lookup Table。整个代码段中最最关键便是InitTransferArray方法,其定义如下:
这里并不细究上面这个Transfer更深层次的意义(事实是:在网上基本没有相应的解释),但是细心的人很容易发现,在Transfer的初始化过程中,高光增等同于阴影减,阴影增等同于高光减,这没有太大问题,但是问题是中间调的增减竟然和阴影增/高光减是同一个公式。这似乎是很奇怪的,而这个问题也引起了GIMP某些开发者的争议—-建议用其他方法如贝叶斯多项式来使得整个调整更平缓。但在最后Release出来的版本中GIMP还是用了上面这个公式。(相关的讨论,喜欢八卦和考古的童鞋可以猛击这里进行考古活动)
至于上面函数中用到的AdjustCurve的方法已在亮度调整一文中放出,就不重复了。而PreserveLuminosityAdjustCurve方法其实也很简单,只是在用Lookup Table去调整原图各个像素时,进行一次RGB-HSL-RGB的转换,并保证转换前后的L不变即可:(这里有个小技巧:RGB和HSL的转换可以写一个专门的Int型转换,这样可以减少几次浮点除法运算,如下面的Rgb2Hsl_Int)