我需要构建一个简单的应用程序,将彩色图像或灰度图像转换为黑白图像,我正在考虑遍历每个像素并检查RGB值,以及是否所有这些值均小于特定值(请说20)将像素重绘为黑色,如果大于该值,则将像素重绘为白色。这样的事情。
function blackWhite(context, canvas) {
var imgData = context.getImageData(0, 0, canvas.width, canvas.height);
var pixels = imgData.data;
for (var i = 0, n = pixels.length; i < n; i += 4) {
if (pixels[i] <= 20 || pixels[i+1] <= 20 || pixels[i+2] <= 20){
pixels[i ] = 0; // red
pixels[i+1] = 0; // green
pixels[i+2] = 0; // blue
}else{
pixels[i ] = 255; // red
pixels[i+1] = 255; // green
pixels[i+2] = 255; // blue
}
}
//redraw the image in black & white
context.putImageData(imgData, 0, 0);
}
Run Code Online (Sandbox Code Playgroud)
最大的问题是,红色,绿色和蓝色的正确组合是什么,才能将像素定义为黑色,这要考虑到人眼感知到的颜色不同,例如,对于我们的眼睛而言,绿色更为重要颜色比红色和蓝色要好一些,但我尝试性地尝试了一些值,但我没有接近黑色,而且图像的像像可以通过将扫描仪中的一张纸数字化为黑白来得到。
当然,如果有更快的方法可以做到这一点,我将不胜感激。
我相信您要寻找的是相对亮度。虽然不是最先进的阈值方法,但它更好地遵循了人类感知光的方式,这就是我认为您想要的。
https://zh.wikipedia.org/wiki/Relative_luminance
从维基百科的文章中,可以如下计算亮度:
let lum = .2126 * red + .7152 * green + .0722 * blue
该值将是一的一小部分,因此,如果您想在中间将其拆分,请使用阈值.5
编辑
真正的问题在于选择阈值。并非所有图像都以相同的方式点亮,而具有较低亮度的更多像素的图片(即,更多的黑色)将受益于较低的阈值。您可以考虑使用多种技术,例如分析图像的直方图。
小智 5
(我正在为未来的访问者添加这个。)对于将图像转换为黑白,其中诸如亮度优势、伽马等特征是未知的,“大津方法”往往会提供良好的结果。
这是一个相当简单的算法,它使用图像的亮度直方图结合像素计数来找到最佳的基于聚类的阈值。
主要步骤是(来源:同上):
所以我们需要做的第一件事就是建立一个直方图。这将需要使用平坦的 33.3% 因子将 RGB 转换为亮度,或者在 Khauri 的回答中使用 Rec.709(用于 HD)公式(也可以使用 Rec.601)。请注意,Rec.* 因子假定 RGB 已转换为线性格式;现代浏览器通常会对用于画布的图像应用伽马(非线性)。但让我们在这里忽略它。
平坦的转换可能对性能有益,但提供的结果不太准确:
var luma = Math.round((r + g + b) * 0.3333);
Run Code Online (Sandbox Code Playgroud)
而 Rec.709 会给出更好的结果(使用线性数据):
var luma = Math.round(r * 0.2126 + g * 0.7152 + b * 0.0722);
Run Code Online (Sandbox Code Playgroud)
因此,将每个像素转换为整数 luma 值,将结果值用作 256 大数组中的索引并递增索引:
var luma = Math.round((r + g + b) * 0.3333);
Run Code Online (Sandbox Code Playgroud)
现在我们有了直方图,我们可以将其提供给 Oto 方法并获得图像的黑白版本。
翻译成我们会做的 JavaScript(方法部分的来源基于同上的变体 2):
var luma = Math.round(r * 0.2126 + g * 0.7152 + b * 0.0722);
Run Code Online (Sandbox Code Playgroud)
另请参阅改进部分。