Search code examples
javascriptimagealgorithmgrayscale

Understand how to JavaScript Grayscale Algorithm works (without use jQuery)


Today I was looking for an algorithm that converts the color image to grayscale, and the result is not a long search I found the following article

3 Ways to Turn Web Images to Grayscale

This article contains the following code snippet

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);

Also in this article http://www.ajaxblender.com/howto-convert-image-to-grayscale-using-javascript.html in comments it was suggested to replace:

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;
    }
}

with:

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;
}

Demo on JSFiddle https://jsfiddle.net/n6q9a2c9/

And I have some problems with the understanding of how this algorithm works.

In this code snippet

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;
}

I understand that var avg = (imgPixels.data[i] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3 is formula (R + G + B) / 3 below is the part that is confusing to me

for (var i = 0; i < imgPixels.data.length; i = i + 4) {

Why here we increment by 4?

I will be grateful if answer how this algorithm works.


Solution

  • Canvas data is provided to you in RGBA (red, green, blue, and a transparency value called 'alpha') interleaved format. Each channel needs a byte per pixel and you have four channels and so there are four values per pixel. Since the channels are interleaved, you increment by 4 to step through the pixels.

    References: