制作过亮(HDR)颜色的算法会变白吗?

时间:2013-04-22 18:36:52

标签: algorithm graphics colors

你知道如果图像中的每种颜色足够明亮或过度曝光,它们最终会如何变成白色?我正在尝试找出一个函数来执行此操作以应用于生成的HDR图像,以逼真和令人愉悦的方式(使用理想化的相机性能作为参考,我猜)。

我想要获得的算法/函数应该解决的问题是,假设你有一个带有(线性RGB)值{1.0,0.2,0.0}的橙色像素。如果你将每个值乘以因子1.0或更小,一切都很好,但是假设你将该像素乘以6,现在得到{6.0,1.2,0.0},你如何处理超出范围的红色和绿色值6.0和1.2?你可以剪辑它们会给你{1.0,1.0,0.0},这可能是Photoshop和3DS Max所做的,但它看起来非常错误,因为现在你以前的橙色像素是黄色的(所以如果你从任何饱和开始色调(意思是至少一个通道是0.0)你总是以洋红色,黄色或青色结束)并且永远不会变成白色。

我考虑将一个通道的一半超出并在其他通道之间平均分配,因此例如{1.6,0.5,0.1}将变为{1.0,0.8,0.4},但它太简单且不太现实。我强烈怀疑一个可接受的解决方案可能在这个微不足道的任何地方。

我确信一定有关于这个主题的研究已经完成,但是我找不到任何相关的文献,而感光测定似乎并不是我想要的。

3 个答案:

答案 0 :(得分:1)

修改我在answer on another question中留下的Python代码,使其在[0.0-1.0]范围内工作:

def redistribute_rgb(r, g, b):
    threshold = 1.0
    m = max(r, g, b)
    if m <= threshold:
        return r, g, b
    total = r + g + b
    if total >= 3 * threshold:
        return threshold, threshold, threshold
    x = (3 * threshold - total) / (3 * m - total)
    gray = threshold - x * m
    return gray + x * r, gray + x * g, gray + x * b

这应该在线性或伽马校正的色彩空间中返回可接受的结果,尽管线性会更好。

将每个r,g,b值乘以相同的量会保留其原始比例,从而保持色调,直到x=0并且您已达到白色的程度。一旦裁剪开始,你已经表达了对非线性响应的兴趣,但我并不完全确定如何处理它。数学是经过仔细选择的,因此至少有一个返回值将达到阈值,并且没有将在上面。

(1.6, 0.5, 0.1)的示例上运行此操作会返回(1.0, 0.6615, 0.5385)

答案 1 :(得分:1)

根据Mark Ransom的建议,我找到了一种方法。当颜色超出色域时,我们计算等效感知亮度的灰色,然后我们在色域外输入颜色和灰度值之间进行线性插值,以找到第一个色域内颜色。对每个RGB通道进行加权以获得感知亮度部分是一个棘手的部分,因为CIELab L = 0.2126*red + 0.7152*green + 0.0722*blue中最常用的公式非常明显错误,因为它使蓝色方式过于明亮。相反,我做了一些测试并选择了对我来说最合适的重量,虽然这些不是很明确,你可能想要调整它们,尽管对于这个特殊的问题,这可能不是太关键。

或者用更少的话说解决方案就是将色域外的色彩去饱和,以至于它可能在色域内。

这是我在C代码中的解决方案。所有变量都采用浮点格式。

Wr=0.125; Wg=0.68; Wb=0.195;        // these are the weights for each colour

max = MAXN(MAXN(red, grn), blu);    // max is the maximum value of the 3 colours

if (max > 1.)       // if the colour is out of gamut
{
    L = Wr*red + Wg*grn + Wb*blu;   // Luminosity of the colour's grey point

    if (L < 1.) // if the grey point is no brighter than white
    {
        // t represents the ratio on the line between the input colour
        // and its corresponding grey point. t is between 0 and 1,
        // a lower t meaning closer to the grey point and a
        // higher t meaning closer to the input colour
        t = (1.-L) / (max-L);

        // a simple linear interpolation between the
        // input colour and its grey point
        red = red*t + L*(1.-t);
        grn = grn*t + L*(1.-t);
        blu = blu*t + L*(1.-t);
    }
    else    // if it's too bright regardless of saturation
    {
        red = grn = blu = 1.;
    }
}

这里有一个线性橙色渐变的样子: linear orange gradient

它没有使用像任意伽玛那样好的东西,唯一大多数任意的东西都与亮度权重有关,但我想这些是非常必要的。

答案 2 :(得分:0)

您必须将其映射到某个非线性比例。例如:http://en.wikipedia.org/wiki/Gamma_correction

Ex:设y = f(x)= log(1 + x) - log(1-x)定义“实际”发光。

反函数是x = g(y)=(e ^ y-1)/(e ^ y + 1)。

现在,您的值为x = 1且x = 0.2。对于第一种情况,相应的y是无穷大。无穷大的六倍仍然是无穷大。如果你使用函数g,你得到新的x_new = 1。

对于x = 0.2,y = 0.4054651。乘以6后,y_new = 2.432791。对应的x_new = 0.8385876。

对于x = 0,x_new仍为0(我将把计算留给你)。

所以从(1.0,0.2,0.0)开始,你的新点集是(1.0,0.8385876,0.0)。

这是映射功能的一个例子。它们数量无限。选择一个最适合你的。