From 46bd704a3f4abf9a05a627c0135c6b868576721d Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Wed, 24 Oct 2012 09:35:44 -0700 Subject: [PATCH 1/2] Reduce loops and pixel position math Since the pixel rewrite loop will run literally thousands of times on just a single image, it makes sense to optimize it as much as possible. Reducing to a single iterative loop instead of two nested loops. Also reduce the math run inside of each loop to calculate the pixel position in the array. --- js/grayscale.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/js/grayscale.js b/js/grayscale.js index f2bc2ce..be17a5e 100644 --- a/js/grayscale.js +++ b/js/grayscale.js @@ -38,16 +38,13 @@ return this.each(function(){ var imgPixels = ctx.getImageData(0, 0, canvas.width, canvas.height); - 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 + 0] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3; + for(var i = 0, n = imgPixels.data.length; i < n; i += 4) { + var avg = (imgPixels.data[i + 0] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3; - imgPixels.data[i + 0] = avg; - imgPixels.data[i + 1] = avg; - imgPixels.data[i + 2] = avg; - } - } + imgPixels.data[i + 0] = avg; + imgPixels.data[i + 1] = avg; + imgPixels.data[i + 2] = avg; + } ctx.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height); $this.attr('src',canvas.toDataURL()); From fe70edf1058a951ea83ca4eed4867df02f3e6ad6 Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Wed, 24 Oct 2012 09:49:17 -0700 Subject: [PATCH 2/2] Grayscale calculation using standard Luma formula MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The standard "Luma" formula is closer to how humans perceive colors and grayscale. While an average is technically correct, it doesn't match what the human eye perceives. See http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/ for more explanation. --- js/grayscale.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/js/grayscale.js b/js/grayscale.js index be17a5e..c810a0c 100644 --- a/js/grayscale.js +++ b/js/grayscale.js @@ -39,11 +39,13 @@ return this.each(function(){ var imgPixels = ctx.getImageData(0, 0, canvas.width, canvas.height); for(var i = 0, n = imgPixels.data.length; i < n; i += 4) { - var avg = (imgPixels.data[i + 0] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3; - - imgPixels.data[i + 0] = avg; - imgPixels.data[i + 1] = avg; - imgPixels.data[i + 2] = avg; + //Calculate monochrome value using Classic Luma formula used by most image processing software + var avg = imgPixels.data[i + 0] * 0.2126 + imgPixels.data[i + 1] * 0.7152 + imgPixels.data[i + 2] * 0.0722; + + imgPixels.data[i + 0] = avg; //red channel + imgPixels.data[i + 1] = avg; //blue channel + imgPixels.data[i + 2] = avg; //green channel + // i + 4 would be the alpha channel } ctx.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height);