在浏览器中显示 rgb8 像素数据

Displaying rgb8 pixel data in-browser

我在 SO 上发现了与我类似的问题,但还没有找到这个问题的答案。我有一个 rgb8 编码图像,我试图在浏览器中显示在 imgcanvas 元素中。我不确定如何将此像素数据正确转换为图像,并且正在寻找任何见解。

对于上下文,此 rgb8 数据的来源来自类型为 sensor_msgs/Image 的 ROS 主题。使用 roslibjs 订阅此主题时,我得到以下对象:

{
  data: “MT4+CR…”, (of length 1228800)
  encoding: "rgb8",
  header: {
    frame_id: “camera_color_optical_frame”,
    seq: 1455,
    stamp: ...timestamp info
  },
  height: 480,
  is_bigendian: 0,
  step: 1920,
  width: 640
}

对于 data 字符串,我曾尝试在 canvas 上显示它,将其转换为 base64 等,但未能成功。我知道 ROS 中的 web_video_server 有助于通过端口发送这些图像,但不幸的是,这对我来说不是一个选项 - 我需要直接使用 data.

有什么方法可以在浏览器中显示此 rgb8 数据?根据 here 上的文档,data 应表示为 uint8[](如果有帮助的话)。

非常感谢!

先创建一个大小正确的canvas,得到一个CanvasRenderingContext2D

// Assuming that imgMes is the image message as linked in question

const can = document.createElement("canvas");
can.width = imgMes.width;
can.height = imgMes.height; 
const ctx = can.getcontext("2d");

然后创建一个image buffer来保存像素

const imgData = ctx.createImageData(0, 0, imgMes.width, imgMes.height);
const data = imgData.data;
const inData = imgMes.data;

然后从图像消息中读取数据。确保使用标志 is_bigendian

中定义的正确顺序
var i = 0, j, y = 0, x;
while (y < imgMes.height) {
    j = y * imgMes.step;
    for (x = 0; x < imgMes.width; x ++) {
        if (imgMes.is_bigendian) {
            data[i]     = inData[j];     // red
            data[i + 1] = inData[j + 1]; // green
            data[i + 2] = inData[j + 2]; // blue
        } else {
            data[i + 2] = inData[j];     // blue
            data[i + 1] = inData[j + 1]; // green
            data[i]     = inData[j + 2]; // red
        }
        data[i + 3] = 255;  // alpha
        i += 4;
        j += 3;
     }
     y++;
 }

put the pixel data改成canvas;

 ctx.putImageData(imgData, 0, 0);

并将 canvas 添加到您的 HTML

 document.body.appendChild(can);

大功告成。

请注意,我可能 is_bigendian 走错了路。如果是这样,只需将行 if (imgMes.is_bigendian) { 更改为 if (!imgMes.is_bigendian) {

更新

通过有关数据格式的更多信息,我能够提取图像。

我用atob解码了Base64字符串。这 returns 另一个字符串。然后我迭代字符串中的每个字符,获取要添加到每个像素的字符代码。

尚不清楚字节序在哪里。我的猜测是它在解码后的字符串中,因此代码会为每个字符代码交换字节,因为在 3 个字节的倍数上具有字节序是没有意义的

const can = document.createElement("canvas");
can.width = imgMes.width;
can.height = imgMes.height;
const ctx = can.getContext("2d");

const imgData = ctx.createImageData(imgMes.width, imgMes.height);
const data = imgData.data;
const inData = atob(imgMes.data);

var j = 0; i = 4; // j data in , i data out
while( j < inData.length) {
    const w1 = inData.charCodeAt(j++);  // read 3 16 bit words represent 1 pixel
    const w2 = inData.charCodeAt(j++);
    const w3 = inData.charCodeAt(j++);
    if (!imgMes.is_bigendian) {
        data[i++] = w1; // red
        data[i++] = w2; // green
        data[i++] = w3; // blue
    } else {
        data[i++] = (w1 >> 8) + ((w1 & 0xFF) << 8);
        data[i++] = (w2 >> 8) + ((w2 & 0xFF) << 8);
        data[i++] = (w3 >> 8) + ((w3 & 0xFF) << 8);
    }
    data[i++] = 255;  // alpha
}

ctx.putImageData(imgData, 0, 0);
document.body.appendChild(can);

从示例数据中,我得到了道路附近铺路的图像。