1

你知道如果图像足够亮或曝光过度,每种颜色最终会变成白色吗?我正在尝试找出一个函数来执行此操作,以以逼真且令人愉悦的方式应用于生成的 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} 但它过于简单且不太现实。我强烈怀疑一个可接受的解决方案可能接近这个微不足道的任何地方。

我确信一定已经对这个主题进行了研究,但我找不到任何相关的文献,而且感光度法似乎并不是我想要的。

4

3 回答 3

1

修改我在另一个问题的答案中留下的 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)

于 2013-04-22T23:13:42.697 回答
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.;
    }
}

这是线性橙色渐变的样子: 线性橙色渐变

它不使用任何像任意伽玛这样的东西,这很好,唯一最随意的事情与亮度权重有关,但我想这些是非常必要的。

于 2013-05-03T19:43:45.777 回答
-1

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

例如:让 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)。

这是映射函数的一个例子。它们有无数个。选择一个最适合您的。

于 2013-04-22T18:47:07.427 回答