如何从 img 获取 RGB 数组?

Posted

技术标签:

【中文标题】如何从 img 获取 RGB 数组?【英文标题】:How can I get RGB array from img? 【发布时间】:2022-01-14 21:48:17 【问题描述】:

我正在尝试使用这样的画布获取 img 的 RGB 数组:

铁板

<!DOCTYPE html>
<html>
  <head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <div id="display"></div>
    <img id="face" src="./220px-Leonhard_Euler.jpg" />
    <canvas
      id="face2"
      
      
      style="border: 1px solid #d3d3d3;"
    ></canvas>

    <script src="src/index.js"></script>
  </body>
</html>

脚本

const img = document.getElementById("face");
img.crossOrigin = "anonymous";

const canvas = document.getElementById("face2");
const context = canvas.getContext("2d");
context.drawImage(img, 0, 0);

let pix = context.getImageData(0, 0, 112, 112).data;
pix = Array.from(pix);

const pix2 = [];

for (let i = 0; i < pix.length; i += 4) 
  pix2.push(pix[i + 0]);
  pix2.push(pix[i + 1]);
  pix2.push(pix[i + 2]);


const imgData = context.createImageData(112, 112);

for (let i = 0; i < imgData.data.length; i += 4) 
  imgData.data[i + 0] = pix2[i + 0];
  imgData.data[i + 1] = pix2[i + 1];
  imgData.data[i + 2] = pix2[i + 2];
  imgData.data[i + 3] = 255;


context.putImageData(imgData, 10, 10);

正如您在代码的第一部分中看到的,我尝试提取图像 RGBA 的 4d 数组,并尝试移除 alpha 通道。

之后,我尝试使用默认的 alpha 通道(如 255)再次设置图像,只是为了检查我是否只获得了 RGB 数据。

但我得到了以下图像:

输入图像是112x112,画布是112x112,知道为什么我只能得到img的RGB吗?

EDIT2

@tracktor 响应有效,但我仍然收到这样的另一张图片错误:

相同的代码,唯一的区别是我使用 http://localhost:8080/face.jpg 而不是 crossorigin 加载此图像。

谢谢

【问题讨论】:

pix 中设置 alpha 通道字节可能更容易另外建议检查画布是否被污染并且像素值实际上是可访问的。 我想删除数组的 alpha 像素,并且我想检查我是否删除了在另一个画布中再次绘制的正确像素。 【参考方案1】:

HTMLImageElement crossorigin 属性

在 HTML 中的 img 标记上放置 crossorigin 属性,以确保浏览器请求图像带有 CORS 操作的标题,例如

   Origin: http://localhost
   Sec-Fetch-Mode: cors
   Sec-Fetch-Site: cross-site

作为返回响应图像数据的站点必须包含从“origin”请求标头设置的“Access-Control-Allow-Origin”标头,例如

Access-Control-Allow-Origin: http://localhost

或通配符版本:

Access-Control-Allow-Origin: *

启用 javascript 访问返回的数据。

注意https://i.stack.imgur.com 返回访问控制标头,因此从该域返回的图像将污染画布对象。如果您正在编写或修改节点/express 服务器以支持 CORS,我强烈建议您阅读 http://expressjs.com/resources/middleware/cors.html。

窗口load事件

等到窗口load 事件触发后处理图像数据。如果处理较早的图像加载可能不可用。


损坏的图像结果

更新帖子中显示的图像数据不正确是由于未将pix2 中的 rgb 数据的 3 元组与imageData.data 中所需的 rgba 数据的 4 元组对齐造成的。要成功转置像素数据,请尝试等效于:

for (let i = 0, j = 0; i < imgData.data.length; i += 4) 
  imgData.data[i + 0] = pix2[j++];
  imgData.data[i + 1] = pix2[j++];
  imgData.data[i + 2] = pix2[j++];
  imgData.data[i + 3] = 128;  // test value


下面的 sn-p 创建了两个画布元素:一个显示加载的图像,另一个显示画布数据操作的结果。该代码在不同端口上使用 localhost 服务器,没有它们将无法成功运行:

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>cross origin</title></head>

<body>
<h2>Image</h2>
<img id="face" crossorigin src="http://localhost:8080/share/imperial.jpg" />
<h2>Canvas</h2>
<canvas
    id="face2"
    
    
    style="border: 1px solid blue"
></canvas>

<canvas
    id="modified"
    
    
    style="border: 1px solid red"
></canvas>

<script type="text/javascript">"use strict";
window.addEventListener("load", ()=> 
  const img = document.getElementById("face");
  const canvas = document.getElementById("face2");
  const context = canvas.getContext("2d");
  context.drawImage(img, 0, 0);

  let imgData1 = context.getImageData(0, 0, 112, 112)
  let pix;
  try 
    pix = imgData1.data;
  
  catch( err) 
    console.warn( err.message);
  

  pix = Array.from(pix);

  const pix2 = [];

  for (let i = 0; i < pix.length; i += 4) 
    pix2.push(pix[i + 0]);
    pix2.push(pix[i + 1]);
    pix2.push(pix[i + 2]);
  

  const imgData = context.createImageData(112, 112);
  for (let i = 0, j = 0; i < imgData.data.length; i += 4) 
    imgData.data[i + 0] = pix2[j++];
    imgData.data[i + 1] = pix2[j++];
    imgData.data[i + 2] = pix2[j++];
    imgData.data[i + 3] = 128; // test value
  
 
  const canvas2 = document.getElementById("modified");
  const context2 = canvas2.getContext("2d");
  context2.putImageData(imgData, 10, 10);

);
</script></body>
</html>

【讨论】:

我用当前错误编辑了我的问题,你知道为什么会这样吗?感谢之前的回复。 抱歉耽搁了 - 编写支持跨源的图像服务器花费的时间最长 :) 代码中的错误将 rgb 数据复制到 rgba 数据缓冲区,这很容易修复 - 请参阅更新详细回答。 感谢您的努力,我会稍后检查此回复,但看起来还可以。

以上是关于如何从 img 获取 RGB 数组?的主要内容,如果未能解决你的问题,请参考以下文章

用opencv如何提取像素点的RGB分量

如何从窗口获取像素数据\像素缓冲区并提取RGB?

如何在 SwiftUI 中从颜色中获取 RGB 分量

如何将 rgb 图像数组从 sws_scale 转换为 DIB(在内存位图中)

如何从颜色变量中获取 RGB 值

如何从 UIColor 对象中获取红绿蓝 (RGB) 和 alpha?