你知道如果图像中的每种颜色足够明亮或过度曝光,它们最终会如何变成白色?我正在尝试找出一个函数来执行此操作以应用于生成的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},但它太简单且不太现实。我强烈怀疑一个可接受的解决方案可能在这个微不足道的任何地方。
我确信一定有关于这个主题的研究已经完成,但是我找不到任何相关的文献,而感光测定似乎并不是我想要的。
答案 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.;
}
}
这里有一个线性橙色渐变的样子:
它没有使用像任意伽玛那样好的东西,唯一大多数任意的东西都与亮度权重有关,但我想这些是非常必要的。
答案 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)。
这是映射功能的一个例子。它们数量无限。选择一个最适合你的。