调整Canvas亮度/对比度的公式是什么?

3

和将图像转换为灰度图像一样,是否有一种公式可以增加图像的亮度并在同等程度上降低亮度?我尝试为每个r、g和b像素添加一个值。虽然它确实增加了亮度,但当我减少相同的值时,我无法得到原始值。

var pixels = context.getImageData(...);

//loop over the pixel data and add a value
p[i] = p[i]+100;
p[i+1] = p[i+1]+100;
p[i+2] = p[i+2]+100;

这将提高图像亮度。但是,当我从每个像素减去100时,就不能恢复原始图像。

我在网上看到有一些公式可以正确地计算这个问题。有人能解释一下吗?类似的还有对比度和gamma吗?

更新:

感谢大家提供的建议。在阅读下面的一些帖子后,我尝试了这个方法。

增加亮度:

var pixels = context.getImageData(...);

//loop over the pixel data and add a value
p[i] = p[i]+100 < 255 ? p[i]+100 : 255;
p[i+1] = p[i+1]+100 < 255 ? p[i+1]+100 : 255;
p[i+2] = p[i+2]+100 < 255 ? p[i+2]+100 : 255;

对于降低亮度:

var pixels = context.getImageData(...);

//loop over the pixel data and add a value
p[i] = p[i]-100 >= 0 ? p[i]-100 : 0;
p[i+1] = p[i+1]-100 >= 0 ? p[i+1]-100 : 0;
p[i+2] = p[i+2]+100 >= 0 ? p[i+2]-100 : 0;

我可以看到增量效果很好,但是当我减量时,我仍然没有得到原始图像,原始图像和变亮的图像之间有一点差异!我做错了什么?

你介意分享一下你最终使用的公式吗? - Kyle
2个回答

5
由于取整和值域限制等因素,许多图像操作是不可逆的。
你的每个颜色通道p[i]可能是字节类型。如果是这样,只能存储0到255之间的值。例如,将100添加到223会得到323,这不能保存在1个字节中。这应该导致溢出为67,或者被截断为255(最大可能的数字)。 减去100不会恢复223,而是得到155。
与其添加偏移量,你应该尝试将颜色进行乘法运算。但这也会带来信息损失,正如AngelCastillo所回答的那样。(这里也会有信息丢失,但结果更好)
对更新的反应 我的意思是,限制值(例如您的实际实现)会导致数据丢失。就像上面解释的例子一样,一个太大的值变成255。因此,再减去100将把所有颜色设置为155,这在原始图像中是155或更大的颜色。更亮的颜色(>155)的信息已经丢失了。
在其他情况下(对比度和伽马变化),由于四舍五入将以前不同的颜色设置为相同的值,您也会丢失信息。
唯一避免这种情况的方法是使用每个通道具有更多信息的其他格式。例如,>16位有符号整数或浮点数。我怀疑你的画布没有这样的选项,所以你需要保存一个具有更高值范围的背景副本。在副本上进行所有转换,并只在画布上显示被截断的图像。

谢谢!我尝试使用上限255和下限0来添加和减少。请查看我的更新问题! - Rutwick Gangurde
请问您能否建议一种使用有符号整数或浮点数来完成它的方法? - Rutwick Gangurde
抱歉,我不熟悉HTML5。但我认为你将使用第二个备份图像来运行解决方案 :-) - Johannes Jendersie
嘿@Johannes Jendersie,我用备份/重绘画布的技巧让它工作了!谢谢你的帮助伙计! :) - Rutwick Gangurde

5
在谷歌上快速搜索显示:

使用C++调整位图图像的亮度/对比度

链接:

https://web.archive.org/web/20091229041814/http://www.kweii.com/site/color_theory/2007_LV/BrightnessCalculation.pdf

https://web.archive.org/web/20140825114946/http://bobpowell.net/image_contrast.aspx

在发布问题之前,请记得先查找类似的问题 :)

编辑:

另外两个链接:

图像处理算法第五部分:对比度调整:

http://thecryptmag.com/Online/56/imgproc_5.html

图像处理算法第四部分:亮度调整:

http://www.dfstudios.co.uk/articles/image-processing-algorithms-part-4/

编辑:

您发布的第二个代码块中存在错误:

var pixels = context.getImageData(...);

//loop over the pixel data and add a value
p[i] = p[i]-100 >= 0 ? p[i]-100 : 0;
p[i+1] = p[i+1]-100 >= 0 ? p[i+1]-100 : 0;
p[i+2] = p[i+2]+100 >= 0 ? p[i+2]-100 : 0; // <- Tha p[i+2]+100 should be a p[i+2]-100 right?

Johannes Jendersie所说的是真的,你的问题在于:

假设您有一个像素具有这些值

R = 100;
G = 210;
B = 20;

然后你给每个颜色加上100,现在你有:

R = 200;
G = 255; // It was 310 but you have to clamp it to 255.
B = 120;

现在你减去同样的100:

R = 100; // same
G = 155; // different!, this have to be 210!!
B = 20;  // same

这就是为什么这个操作不可逆的原因。你可以做的是始终保留原始图像的副本,每次更改值时重新应用亮度校正。

因此,撤消添加100的操作的方法不是减去100,而是将亮度校正值设置为0。这是许多图像编辑程序的工作方式,您有一个滑块,在滑块窗口更改值时,如果将其设置为0,则始终可以获得原始图像,但是一旦“应用”校正,它就无法撤消,当您重新打开滑块窗口时,“0”现在是先前过滤的图像。

因此,您可以在某个地方保留图像和亮度校正值的备份,并且每次更改值时都要在图像上重新应用校正,或者您只需接受这样的事实,即您将无法将图像恢复到其以前的辉煌状态 xD(至少不是使用这种亮度校正的方法,不确定是否有更好的方法)。

希望对您有所帮助。


谢谢!我会去看看这些的!我一直在阅读相关资料,但因为我正在寻找一个通用公式,所以没有查看这些。 - Rutwick Gangurde
1
关于亮度的论文是通用的,不与任何语言绑定,另一个有C#代码。我在回复中添加了2个更通用的链接。 - AngelCastillo
啊,打错字了!是的,我意识到了这个错误。我正在寻找一种使用第二个备份图像来解决这个问题的方法。 - Rutwick Gangurde
最终我通过重新绘制画布的方法解决了它!感谢你的帮助,伙计!:D - Rutwick Gangurde
“图像处理调整”链接已经失效。 - user1881400

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接