改变RGB图像色温-实现和细节

在其他文章中,已经有了最基本的冷暖色调转换方案,比如单纯根据level值加减R,B分量,

OpenCV图像色温_提取图片的色温-优快云博客

python实现图像的白平衡,破坏图像的白平衡(冷、暖)和调节图像的亮度_python 根据照片求色温-优快云博客

或者高级一些,定量计算某个色温下黑体辐射的RGB值,即白点RGB坐标:

色温(Kelvin)到RGB的转换:算法和样例_色温转rgb-优快云博客

但这篇文章有一个问题,按照给出的代码只能画出不同色温下白点的颜色,没有说明实际图像中各个像素的rgb值是怎么变化的,即怎么做整个图像色温变换。根据原文链接,我们可以找到这部分代码对应的PhotoDemon软件开源源码:

PhotoDemon/Forms/Adjustments_Color_Temperature.frm at 5ae6a3e53e1d332f3026c4de9fdca283395c5674 · tannerhelland/PhotoDemon (github.com)

逐像素调节色温的核心代码在 Forms/Adjustments_Color_Temperature.frm 295行附近,

其中If (temperatureMethod = PDTA_Basic) 分支直接对应“单纯根据level值加减R,B分量”的简化方案;else分支对应的是改进后方案,即计算出白点的tmpR,tmpG,tmpB后和原始像素混合。Colors.BlendColors(r, tmpR, tempStrength)是颜色混合函数,具体定义可以在Modules/Colors.bas中找到。

至于为什么是像素RGB和白点RGB值混合,我想是利用两个颜色向量插值,来实现原始色彩向目标场色彩偏移。

    For y = initY To finalY
        workingDIB.WrapArrayAroundScanline imageData, tmpSA1D, y
    For x = initX To finalX Step 4
        
        'Get the source pixel color values
        b = imageData(x)
        g = imageData(x + 1)
        r = imageData(x + 2)
        
        'If luminance is being preserved, we need to determine the initial luminance value
        originalLuminance = Colors.GetLuminance(r, g, b) * ONE_DIV_255
        
        If (temperatureMethod = PDTA_Basic) Then
            Colors.ImpreciseRGBtoHSL rLookup(r), g, bLookup(b), h, s, l
            Colors.ImpreciseHSLtoRGB h, s, originalLuminance, r, g, b
        Else
            
            'Blend the original and new RGB values using the specified strength
            r = Colors.BlendColors(r, tmpR, tempStrength)
            g = Colors.BlendColors(g, tmpG, tempStrength)
            b = Colors.BlendColors(b, tmpB, tempStrength)
            
            'If the user wants us to preserve luminance, determine the hue and saturation of the new color, then replace the luminance
            ' value with the original
            If preserveLuminance Then
                Colors.ImpreciseRGBtoHSL r, g, b, h, s, l
                Colors.ImpreciseHSLtoRGB h, s, originalLuminance, r, g, b
            End If
        
        End If
        
        'Assign the new values to each color channel
        imageData(x) = b
        imageData(x + 1) = g
        imageData(x + 2) = r

总结

采用基于白点的色温转换(色温(Kelvin)到RGB的转换:算法和样例_色温转rgb-优快云博客),需要注意算出白点后和原始像素线性加权混合,才能完成实际图像的色彩转换.

或者,按照原评论区所讲述的方案,将目标色温下的RGB作为最大值归一化。即R1=R/R_temp*255,也是可以的。这种方法的背后原理是色适应变换(CAT),更深入可以了解CIE CAM02中的CAT02算法和实现。

附录:python实现

def get_rgb_from_temperature(temp):
    """
    根据色温 (Kelvin) 计算白点的 RGB 值
    :param temp: 色温 (Kelvin),通常范围在 1000K - 40000K
    :return: 对应色温的 RGB (r, g, b) 值
    """

    # 限制色温的范围
    temp = max(1000, min(temp, 40000)) / 100.0  # 将色温范围限制在1000K到40000K之间,并转换为百位制

    # 初始化 RGB
    r, g, b = 0, 0, 0

    # 计算红色分量
    if temp <= 66:
        r = 255
    else:
        tmpCalc = temp - 55
        r = 351.976905668057 + 0.114206453784165 * tmpCalc + -40.2536630933213 * np.log(tmpCalc)
        r = min(255, max(0, r))  # 限制在0-255之间

    # 计算绿色分量
    if temp <= 66:
        tmpCalc = temp-2
        g = -155.254855627092 + -0.445969504695791 * tmpCalc + 104.492161993939 * np.log(tmpCalc)
        g = min(255, max(0, g))  # 限制在0-255之间
    else:
        tmpCalc = temp - 50
        g = 325.449412571197 + 7.94345653666234E-02 * tmpCalc + -28.0852963507957 * np.log(tmpCalc)
        g = min(255, max(0, g))  # 限制在0-255之间

    # 计算蓝色分量
    if temp >= 66:
        b = 255
    else:
        if temp <= 19:
            b = 0
        else:
            tmpCalc = temp - 10
            b = -254.769351841209 + 0.827409606400739 * tmpCalc + 115.679944010661 * np.log(tmpCalc)
            b = min(255, max(0, b))  # 限制在0-255之间

    return np.array([r,g,b],dtype=np.uint8).reshape(1,1,3)

# 示例调用
temp = 6500  # 色温 (Kelvin)
rgb = get_rgb_from_temperature(temp)
r = rgb[...,0]
g = rgb[...,1]
b = rgb[...,2]
print(f"色温 {temp}K 的 RGB 值是: R={r}, G={g}, B={b}")

# show color bar
img_array = np.zeros((20,150-15,3),dtype=np.uint8)
for i in range(0,150-15):
    rgb_temp = get_rgb_from_temperature((15+i)*100)
    img_array[:,i,:] = rgb_temp
plt.imshow(img_array)

#---- 对一张图做色彩变换 ----#
def blend_color(img_ori,white_point,alpha=0.8):
    ''' 
    Color fusion.

    Out = alpha*img_ori+(1-alpha)*white_point
    '''
    img_dst = alpha*img_ori+(1-alpha)*white_point
    img_dst[img_dst>255] = 255
    img_dst = np.uint8(img_dst)
    return img_dst
img_ori = ...    # 注意要求RGB顺序
img_dst = blend_color(img_ori,get_rgb_from_temperature(8000))
plt.imshow(img_dst)

# 或采用色适应假设:以的白点归一化. 这种方案不会显得图片偏白
white_point = get_rgb_from_temperature(8000)
img_dst = img_ori/white_point*255.
img_dst[img_dst>255] = 255
img_dst = np.uint8(img_dst)
plt.imshow(img_dst)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值