今天我正在寻找一种将彩色图像转换为灰度图像的算法,结果并不需要长时间搜索,我找到了以下文章。
3种将Web图像转换为灰度的方法
本文包含以下代码片段。
在本文中,http://www.ajaxblender.com/howto-convert-image-to-grayscale-using-javascript.html 的评论中建议替换以下内容:
var imgObj = document.getElementById('js-image');
function gray(imgObj) {
var canvas = document.createElement('canvas');
var canvasContext = canvas.getContext('2d');
var imgW = imgObj.width;
var imgH = imgObj.height;
canvas.width = imgW;
canvas.height = imgH;
canvasContext.drawImage(imgObj, 0, 0);
var imgPixels = canvasContext.getImageData(0, 0, imgW, imgH);
for (var y = 0; y < imgPixels.height; y++) {
for (var x = 0; x < imgPixels.width; x++) {
var i = (y * 4) * imgPixels.width + x * 4;
var avg = (imgPixels.data[i] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3;
imgPixels.data[i] = avg;
imgPixels.data[i + 1] = avg;
imgPixels.data[i + 2] = avg;
}
}
canvasContext.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height);
return canvas.toDataURL();
}
imgObj.src = gray(imgObj);
在本文中,http://www.ajaxblender.com/howto-convert-image-to-grayscale-using-javascript.html 的评论中建议替换以下内容:
for (var y = 0; y < imgPixels.height; y++) {
for (var x = 0; x < imgPixels.width; x++) {
var i = (y * 4) * imgPixels.width + x * 4;
var avg = (imgPixels.data[i] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3;
imgPixels.data[i] = avg;
imgPixels.data[i + 1] = avg;
imgPixels.data[i + 2] = avg;
}
}
使用:
for (var i = 0; i < imgPixels.data.length; i = i + 4) {
var avg = (imgPixels.data[i] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3;
imgPixels.data[i] = avg;
imgPixels.data[i + 1] = avg;
imgPixels.data[i + 2] = avg;
}
JSFiddle演示 https://jsfiddle.net/n6q9a2c9/
我对这个算法的理解有一些问题。
在这段代码片段中:
for (var i = 0; i < imgPixels.data.length; i = i + 4) {
var avg = (imgPixels.data[i] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3;
imgPixels.data[i] = avg;
imgPixels.data[i + 1] = avg;
imgPixels.data[i + 2] = avg;
}
我知道var avg = (imgPixels.data[i] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3
是公式(R + G + B) / 3
,下面是让我感到困惑的部分
for (var i = 0; i < imgPixels.data.length; i = i + 4) {
为什么这里我们要增加4?
如果能解释一下这个算法的工作原理,我将不胜感激。
500 * 333 = 166500
,由于每个像素有4个通道(RGBA),所以乘以166500 * 4 = 666000
。 - Mikhailfor
循环来迭代该数组,而是在x
和y
上进行迭代,然后将其转换为像素数据数组的索引i
。你所问的那行代码执行了从x,y
到索引的转换。如果示例使用公式var i = (y * imgPixels.width + x) * 4;
,可能会更易理解。请记住,索引通常从零开始,直到数组大小之前结束。根据原始公式:332 * 4 * 500 + 499 * 4 = 665996
。 - Ouroborusfor
循环的示例中,我们跳过了alpha通道(因为我们每次增加4),就像这样http://pastebin.com/3wz1nX2A,在两个`for`循环的示例中,算法不会这样做(不会增加4)。 - Mikhaili = (y * imgPixels.width + x) * 4
比例子中使用的i = (y * 4) * imgPixels.width + x * 4
更容易理解。它们做的事情是相同的,只是我的版本在数学上更清楚地说明了正在发生的事情。 - Ouroborus