Отображение данных пикселей rgb8 в браузере - PullRequest
1 голос
/ 08 января 2020

Я нашел похожие вопросы к моим на SO, но еще не нашел ответа на эту проблему. У меня есть изображение в кодировке rgb8, которое я пытаюсь отобразить в браузере, либо в элементе img, либо canvas. Я не уверен, как правильно преобразовать эти данные пикселей в изображение, и искал какую-либо информацию.

Для контекста источником этих данных rgb8 является ROS topi c с типом sensor_msgs/Image. При подписке на эту топи c с использованием 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 и т. Д. c. но не смогли. Я знаю о web_video_server в ROS, чтобы помочь отправить эти изображения через порт, но, к сожалению, это не вариант для меня - мне нужно работать напрямую с data.

Есть ли способ, которым я могу go об отображении этих данных rgb8 в браузере? На основании документации здесь , data должен быть представлен как uint8[] (если это поможет).

Большое спасибо!

1 Ответ

1 голос
/ 08 января 2020

Сначала создайте холст правильного размера и получите 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);

Из данных примера я получил изображение какой-то тротуарной плитки возле дороги.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...