首页 > 解决方案 > 如何在 JavaScript 中对画布图像进行灰度化?

问题描述

我在 HTML5 画布中有一个 28x28 像素大小的图像。我使用以下代码将画布的 imageData 作为 RGBA(红色、绿色、蓝色、alpha)值的数组:

canvas = document.getElementById('canvas');
ctx = canvas.getContext("2d");
imgData = ctx.getImageData(0, 0, 28, 28);

现在我想对图像进行灰度化处理,以便得到一个包含 784 个值(28x28 像素)的数组,其中每个像素都有一个值(而不是四个)。

我发现了很多不同的灰度公式,有些是乘以 rgb 值,有些只是计算平均值——我真的不知道该使用哪一个......

我也坚持获得 784 个值 - 它始终是 3136(因为有 4 个通道)......

提前致谢!

标签: javascripthtmlcanvasgrayscaleimagedata

解决方案


主要思想是使颜色的红色绿色和蓝色分量具有相同的值。为此,您需要计算每个像素的亮度。有几种计算亮度的方法。这是其中之一。

window.onload = function() {
  let canvas = document.getElementById("c");

  let ctx = canvas.getContext("2d");
  canvas.width = 50;
  canvas.height = 50;

  let srcImg = document.getElementById("sof");
  ctx.drawImage(srcImg, 0, 0, ctx.canvas.width, ctx.canvas.height);
  let imgData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
  let pixels = imgData.data;
  for (var i = 0; i < pixels.length; i += 4) {

    let lightness = parseInt((pixels[i] + pixels[i + 1] + pixels[i + 2]) / 3);

    pixels[i] = lightness;
    pixels[i + 1] = lightness;
    pixels[i + 2] = lightness;
  }
  ctx.putImageData(imgData, 0, 0);
}
<canvas id="c"></canvas>
<img src="data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAZAAD/4QMtaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTJDRTJFNzlFMzkzMTFFODlEQ0FEQ0NCN0JCMjUxRTEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTJDRTJFN0FFMzkzMTFFODlEQ0FEQ0NCN0JCMjUxRTEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoxMkNFMkU3N0UzOTMxMUU4OURDQURDQ0I3QkIyNTFFMSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDoxMkNFMkU3OEUzOTMxMUU4OURDQURDQ0I3QkIyNTFFMSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pv/uAA5BZG9iZQBkwAAAAAH/2wCEABENDQ0ODRIODhIaEQ8RGh8XEhIXHyIXFxcXFyIjGx4dHR4bIyMpKi0qKSM2Njs7NjZBQUFBQUFBQUFBQUFBQUEBEhERFBYUGBUVGBcTFxMXHRcZGRcdLB0dIB0dLDgoIyMjIyg4MjUtLS01Mj09ODg9PUFBQUFBQUFBQUFBQUFBQf/AABEIADQAMgMBIgACEQEDEQH/xACCAAEAAgMBAAAAAAAAAAAAAAAAAwQBAgUGAQEAAwEAAAAAAAAAAAAAAAAAAgMEARAAAQMCAgYHBwUAAAAAAAAAAQACAxEEIRIxQYHREwXwUWGRoSIVcbHBMkJSY2JyIxQ1EQACAgEEAgMBAAAAAAAAAAAAARECITFRYQMSQkGBE3H/2gAMAwEAAhEDEQA/APcIiIAijnnit4zLK7Kwd9TqAVC/fMwxcwtpOJCweZgPkynXt8FC91VN6xlpaxuTp1uzS0nCb0nY6aKOGaOeJssZq1w2g6wfYpFJNNSvki004eGgiIunAiLUvBa4xkPc0HAGvm6kBRn5haiZ9pdRkR6MzhVrvjtVUsksKzWxFzYSfOyuagPXv71vJfyFmS/sSW66YjZXeqrDbcSthcPglcQOFICWuJ1VFfFYr3lzKb9fS64h6m6lIUQ0vZT50fMrNS3y0PZOf638ljKMxJwMbh9J/V7wuso4WRRNEMeUFuJa2gxOk0Ui1ddPCsffC/hl7b+dp+uXy+QiIplZkaVzrQS8G64FBLmOSujN2roa1S9OFSRM8VNcMNKPKOpw5IcvPfuj8NyR23MzPG+dsLmtcC4hozAdhopvT/zv6bU9P/O/ptVX4rE27HG9i39nmKdanapmL/Rm/buVxVoLQQSGTiF5IpirKtKQiIgCIiAIiIAiIgCIiA//2Q=="
  id="sof" />

更新:
替代lightness计算:

  • 维基百科(亮度):
    let lightness = parseInt(pixels[i]*.299 + pixels[i + 1]*.587 + pixels[i + 2]*.114);

  • 其他地方(来源未知):
    let lightness = parseInt(3*pixels[i] + 4*pixels[i + 1] + pixels[i + 2] >>> 3);

  • 维基百科(线性亮度):
    let lightness = 0.2126 * pixels[i] + 0.715 * pixels[i+1] + 0.0722 * pixels[i+2];


推荐阅读