将色温(K)转换为RGB:算法和代码示例



如果您不知道什么是色温,请从此处开始

在使用PhotoDemon的“色温”工具时,我花了一整个晚上试图确定一种简单明了的算法来在温度值(以Kelvin为单位)和RGB之间进行转换。 我认为这样的算法很容易找到,因为许多照片编辑器都有校正色温的工具,并且在包括智能手机在内的每台现代相机中,都会根据照明条件进行白平衡调整。


具有白平衡设置的相机屏幕示例。 来源

事实证明,找到可靠的公式将温度转换为RGB几乎是不可能的。 当然,有一些算法,但是大多数算法都是通过将温度转换为XYZ颜色空间来工作的,然后可以向其中添加RGB变换。 这样的算法似乎基于Robertson方法,一种实现在这里 ,另一种实现 这里

不幸的是,这种方法没有提供纯粹的数学公式-它只是根据转换表进行插值。 在某些情况下,这可能是合理的,但是如果考虑到XYZ→RGB的附加转换,结果实在太慢,无法实时简单地调整色温。

所以我写了自己的算法,效果很好。 这就是我的方法。

有关此算法的警告


警告1 :我的算法提供了高质量的近似值,但对于足够的科学用途而言,其准确性不够。 它主要用于处理照片-因此请勿尝试将其用于天文学或医学中。

警告2 :由于其相对简单性,该算法足够快,可以在尺寸合理的图像上实时运行(我在12兆像素的图像上对其进行了测试),但是为了获得最佳结果,请使用针对您的编程语言的数学优化。 我展示了没有数学优化的算法,以免使其复杂化。

警告3 :该算法仅在1000 K至40,000 K的范围内使用,这是摄影的好范围。 (实际上,它比大多数情况下所需的要大得多)。 尽管它适用于此范围之外的温度,但质量会下降。

特别感谢Mitchell Charity


首先,我必须承担很多债务,并感谢Mitchell Charity提供了我用来创建这些算法的初始数据: 未处理的黑体文件 。 Charity提供了两组数据,我的算法使用了CIE 1964 10度颜色匹配功能 。 关于2度CIE 1931函数以及Judd Wos与10度集的校正的讨论超出了本文的讨论范围,但是如果您有兴趣,可以从此页面开始进行全面的分析。

算法:示例输出


这是算法的输出,范围从1000 K到40,000 K:


我的算法的输出范围是1000 K至40,000K。白点是6500–6600 K,非常适合在现代LCD监视器上处理照片

这是该算法的更详细的快照,范围从1500 K到15000 K,可用于摄影:


相同的算法,但是从1500 K到15000 K

如您所见,带区是最小的,这比上面的匹配表有很大的改进。 该算法还可以很好地保持白点附近的淡黄色调,这对于在后期处理照片中模拟日光非常重要。

我是怎么想到这个算法的


得出可靠公式的第一步是从Charity绘制黑体原始值 。 您可以使用LibreOffice / OpenOffice .ods格式(430 KB)下载整个电子表格

这是绘制后的数据:


RGB(sRGB)中的原始温度数据(K),LibreOffice Calc图形。 同样,该转换基于CIE 1964的10度CMF函数,根据需要,白点介于6500 K和6600 K之间(图表的左侧)。 来源

容易注意到,有几个部分简化了我们的算法。 特别是:

  • 低于6600 K的红色值始终为255
  • 低于2000 K的蓝色值始终为0
  • 高于6500 K的蓝色值始终为255

同样重要的是要注意,为了使曲线适合数据,最好将绿色视为两条单独的曲线-一条用于温度低于6600 K的曲线,另一条用于温度高于此点的曲线。

从这一刻起,我将数据(没有“ always 0”和“ always 255”段)划分为单独的颜色分量。 在理想的世界中,可以将曲线调整为每个点集,但是不幸的是,实际上并不是那么简单。 由于图形上X和Y的值之间存在很大的不匹配-所有x值都大于1000并以100个点段显示,而y值在255和0之间-我必须转置x数据以获得最佳拟合。 出于优化目的,我首先将每种颜色的x(温度)值除以100,然后减去需要多少以适应图形。 以下是每条曲线的结果图,以及最合适的曲线和确定系数的相应值(R平方):









我对字体的可怕字距和图表提示深表歉意。 LibreOffice具有许多优点,但是无法平滑图形上的字体是完全可耻的。 我也不喜欢从屏幕截图中提取图表,因为它们没有导出选项,但最好将其留待以后使用。

如您所见,所有曲线的对齐方式都很好,确定系数的值大于0.987。 我可以花更多时间调整曲线,但这足以处理照片。 没有一个居民会说曲线并不完全对应于黑体的初始理想观察结果,对吗?

演算法


这是算法的全部荣耀。

一,伪代码:

     -  1000  40000. (   ,             40000 K).  ,             . Set Temperature = Temperature \ 100  : If Temperature <= 66 Then Red = 255 Else Red = Temperature - 60 Red = 329.698727446 * (Red ^ -0.1332047592) If Red < 0 Then Red = 0 If Red > 255 Then Red = 255 End If  : If Temperature <= 66 Then Green = Temperature Green = 99.4708025861 * Ln(Green) - 161.1195681661 If Green < 0 Then Green = 0 If Green > 255 Then Green = 255 Else Green = Temperature - 60 Green = 288.1221695283 * (Green ^ -0.0755148492) If Green < 0 Then Green = 0 If Green > 255 Then Green = 255 End If  : If Temperature >= 66 Then Blue = 255 Else If Temperature <= 19 Then Blue = 0 Else Blue = Temperature - 10 Blue = 138.5177312231 * Ln(Blue) - 305.0447927307 If Blue < 0 Then Blue = 0 If Blue > 255 Then Blue = 255 End If End If 

注意,在上面的伪代码中, Ln()表示自然对数 。 另请注意,如果温度始终在建议范围内,则可以省略颜色是否小于0的检查。 (但是,您仍然需要选中“如果颜色大于255”)。

关于实际代码,这是我在PhotoDemon中使用的确切的Visual Basic函数。 尚未进行优化(例如,对应表的对数会更快),但至少代码简洁易读:

 '   ( )  RGB- Private Sub getRGBfromTemperature(ByRef r As Long, ByRef g As Long, ByRef b As Long, ByVal tmpKelvin As Long) Static tmpCalc As Double '      1000  40000  If tmpKelvin < 1000 Then tmpKelvin = 1000 If tmpKelvin > 40000 Then tmpKelvin = 40000 '   tmpKelvin \ 100,       tmpKelvin = tmpKelvin \ 100 '     '  If tmpKelvin <= 66 Then r = 255 Else ':  R-    0,988 tmpCalc = tmpKelvin - 60 tmpCalc = 329.698727446 * (tmpCalc ^ -0.1332047592) r = tmpCalc If r < 0 Then r = 0 If r > 255 Then r = 255 End If '  If tmpKelvin <= 66 Then ':  R-    0,996 tmpCalc = tmpKelvin tmpCalc = 99.4708025861 * Log(tmpCalc) - 161.1195681661 g = tmpCalc If g < 0 Then g = 0 If g > 255 Then g = 255 Else ':  R-    0,987 tmpCalc = tmpKelvin - 60 tmpCalc = 288.1221695283 * (tmpCalc ^ -0.0755148492) g = tmpCalc If g < 0 Then g = 0 If g > 255 Then g = 255 End If ',  If tmpKelvin >= 66 Then b = 255 ElseIf tmpKelvin <= 19 Then b = 0 Else ':  R-    0,998 tmpCalc = tmpKelvin - 10 tmpCalc = 138.5177312231 * Log(tmpCalc) - 305.0447927307 b = tmpCalc If b < 0 Then b = 0 If b > 255 Then b = 255 End If End Sub 

在本文开头,该函数用于生成示例输出,因此我可以保证它可以正常工作。

样本图片


这是色温调节功能的一个很好的例子。 下图是HBO的《真爱如血》的广告海报,壮观地展示了调节色温的潜力。 左边是原始框架。 在右侧-使用上面的代码调整色温。 只需单击一下,即可将夜景重现为白天。


进行色温调整

我的PhotoDemon程序中的真实色温工具如下:


PhotoDemon色温工具

下载程序并观看实际操作。

2014年10月更新


雷诺·贝达(Renault Bedar)对该算法进行了出色的在线演示 。 谢谢雷诺!

2015年4月更新


感谢所有提出对原始算法进行改进的人。 我知道这篇文章有很多评论,但是如果您打算实现自己的版本,则值得阅读。

我想强调两个具体的改进。 首先,尼尔B为原始曲线拟合函数提供了最佳版本,该函数会稍微改变温度系数。 这些变化在他的出色文章中有详细描述。

然后,弗朗西斯·洛奇(Francis Loch)添加了一些注释和图像示例,如果要将这些转换应用于照片,这些注释和示例非常有用。 如示例所示,对它的修改会产生更加详细的图像。

Source: https://habr.com/ru/post/zh-CN427333/


All Articles