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



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

对于上下文,此 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字符串,我尝试在画布上显示它,将其转换为 base64 等,但无法做到。我知道 ROS 中的web_video_server可以帮助通过端口发送这些图像,但不幸的是,这对我来说不是一个选择 - 我需要直接与data合作。

有没有办法在浏览器中显示此 rgb8 数据?根据此处的文档,data应表示为uint8[](如果有帮助(。

非常感谢!

首先创建一个正确大小的画布并获取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");

然后创建一个图像缓冲区来保存像素

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

将像素数据放入画布中;

ctx.putImageData(imgData, 0, 0);

并将画布添加到您的 HTML 中

document.body.appendChild(can);

你完成了。

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

更新

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

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

目前尚不清楚恩迪亚在哪里。我的猜测是它在解码的字符串中,因此代码为每个字符代码交换字节,因为在 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);

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

最新更新