当前位置: 首页 > news >正文

ros中相机话题在web页面上的显示,尝试js解析sensor_msgs/Image数据

ros中相机话题在web页面上的显示

思路:
rosbridge websocket 开启ros与web的通路,
话题数据转换为image或者绘制在 canvas中。

话题格式:
sensor_msgs/Image
测试数据编码类型为bgr8

尝试:

解析 为bitmap arraybuffer 写入bgr8,颜色错误
转换颜色通道arraybuffer 填到 canvas
直接绘制为canvas
直接 显示image

占用资源很高,显示不太流畅,待优化

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" /><script src="js/three.min.js"></script>
<script src="js/eventemitter2.js"></script>
<script src="js/roslib.js"></script>
<script src="js/ros3d.js"></script><!--
<script src="https://cdn.jsdelivr.net/npm/three@0.89.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/eventemitter2@6.4/lib/eventemitter2.js"></script>
<script src="https://cdn.jsdelivr.net/npm/roslib@1/build/roslib.js"></script>
<script src="../build/ros3d.js"></script>
-->
<script>/*** Setup all visualization elements when the page is loaded.*/function init() {// Connect to ROS.var ros = new ROSLIB.Ros({//url : 'ws://192.168.20.104:9090'url : 'ws://192.168.10.168:9090'});ros.on('connection', function() {console.log('Connected to websocket server.');});ros.on('error', function(error) {console.log('Error connecting to websocket server: ', error);});ros.on('close', function() {console.log('Connection to websocket server closed.');});var canvas = document.getElementById('img_canvas');canvas.width = 800;canvas.height = 600;var image = new Image();document.body.appendChild(image);image.onload = function() {var canvasWidth=canvas.width ;var canvasHeight=canvas.height;var imageWidth = image.width;var imageHeight = image.height;var imageAspectRatio = imageWidth / imageHeight;var canvasAspectRatio = canvasWidth / canvasHeight;var scaledWidth=1.0;var scaledHeight=1.0;if (imageAspectRatio > canvasAspectRatio) {scaledWidth = canvasWidth;scaledHeight = Math.round(scaledWidth / imageAspectRatio);} else {scaledHeight = canvasHeight;scaledWidth = Math.round(scaledHeight * imageAspectRatio);}var x = (canvasWidth - scaledWidth) / 2;var y = (canvasHeight - scaledHeight) / 2;ctx = canvas.getContext('2d');// 设置背景色并填充整个画布ctx.fillStyle = "#f0f0f0"; // 浅灰色ctx.fillRect(0, 0, canvasWidth, canvasHeight);ctx.drawImage(image, x, y, scaledWidth, scaledHeight);};var example2 = ros.Topic({name: '/usb_cam/image_raw',messageType: 'sensor_msgs/Image'});var ccc=0function generateBMP(width,height,channel) {//var channel=3;//const width = 100;//const height = 100;const fileSize = 54 + width * height * channel; // Header size + pixel data sizevar  buffer = new ArrayBuffer(fileSize);const data = new DataView(buffer);// BMP Headerdata.setUint8(0, 0x42); // 'B'data.setUint8(1, 0x4d); // 'M'data.setUint32(2, fileSize, true); // file sizedata.setUint32(6, 0, true); // reserveddata.setUint32(10, 54, true); // pixel data offset// DIB Headerdata.setUint32(14, 40, true); // DIB header sizedata.setUint32(18, width, true); // widthdata.setUint32(22, height, true); // heightdata.setUint16(26, 1, true); // planesdata.setUint16(28, channel*8, true); // bits per pixel (32-bit)data.setUint32(30, 0, true); // compression (none)//data.setUint32(34, width * height * 4, true); // image sizedata.setUint32(34, width * height * channel, true); // image size --------------zzzdata.setUint32(38, 2835, true); // horizontal resolution (72 DPI)data.setUint32(42, 2835, true); // vertical resolution (72 DPI)data.setUint32(46, 0, true); // colors in palette (none)data.setUint32(50, 0, true); // important colors (all)// Pixel data (simple gradient with transparency)let offset = 54;for (let y = 0; y < height; y++) {for (let x = 0; x < width; x++) {const red = (x / width) * 255;const green = (y / height) * 255;const blue = ((x + y) / (width + height)) * 255;const alpha = (x / width) * 255; // Varying alpha//for transparencydata.setUint8(offset++, blue); // bluedata.setUint8(offset++, green); // greendata.setUint8(offset++, red); // red//data.setUint8(offset++, alpha); // alpha}}const blob = new Blob([buf], { type: "image/bmp" });image.src = URL.createObjectURL(blob);return buffer}var buf=null;example2.subscribe(function(message) {ccc++;if (ccc==1){buf=generateBMP(message.width, message.height,3)}//console.log('Received image seq=%d', message['header']['seq']);//AI???//const image = new ROSLIB.Image(); // 创建 Image 对象实例//image.data = new Uint8Array(message.data); // 设置图像数据//image.width = message.width; // 设置图像宽度//image.height = message.height; // 设置图像高度//image.encoding = message.encoding; // 设置图像编码格式,例如 'rgb8' 或 'mono8' 等//if (ccc%5!=1){return;}let raw = window.atob(message.data);let rawLength = raw.length;//buf.set(raw, 54);a=rawLength/3b=new Uint8Array(buf)
/*b.set(raw.split('').map(char => char.charCodeAt(0)), 54);const blob = new Blob([b.buffer], { type: "image/bmp" });image.src = URL.createObjectURL(blob);//*//*// 将base64字符串中的每个字符转换成ASCII码(字符编码值)for (let i = 0; i < a; i++) {b[54+i*3] = raw.charCodeAt(i*3+2);b[54+i*3+2] = raw.charCodeAt(i*3);b[54+i*3+1] = raw.charCodeAt(i*3+1);}const blob = new Blob([b.buffer], { type: "image/bmp" });image.src = URL.createObjectURL(blob);//*///*var ctx = canvas.getContext('2d');var imageData = ctx.createImageData(message.width, message.height); // 创建ImageData对象//console.log('Received image', message.width, message.height,message.step, message.encoding);// 创建一个Uint8Array类型的数组let uInt8Array = new Uint8Array(rawLength/3*4);// 将base64字符串中的每个字符转换成ASCII码(字符编码值)for (let i = 0; i < a; i++) {uInt8Array[i*4] = raw.charCodeAt(i*3);uInt8Array[i*4+1] = raw.charCodeAt(i*3+1);uInt8Array[i*4+2] = raw.charCodeAt(i*3+2);uInt8Array[i*4+3] = 255;}imageData.data.set(uInt8Array); // 将图像数据转换为Uint8ClampedArray并设置到ImageData对象中ctx.putImageData(imageData, 0, 0); // 将ImageData绘制到Canvas上
//*//*//console.log('Received image', message.width, message.height,message.step, message.encoding);var ctx = canvas.getContext('2d');var imageData = ctx.createImageData(message.width, message.height); // 创建ImageData对象// 将base64字符串中的每个字符转换成ASCII码(字符编码值)for (let i = 0; i < a; i++) {imageData.data[i*4] = raw.charCodeAt(i*3);imageData.data[i*4+1] = raw.charCodeAt(i*3+1);imageData.data[i*4+2] = raw.charCodeAt(i*3+2);imageData.data[i*4+3] = 255;   }ctx.putImageData(imageData, 0, 0); // 将ImageData绘制到Canvas上
//*/});}
</script>
</head><body onload="init()"><h1>sensor_msgs/Image Example</h1>
<!--<p>Run the following commands in the terminal then refresh the page.</p><ol><li><tt>roscore</tt></li><li><tt>roslaunch rosbridge_server rosbridge_websocket.launch</tt></li><li><tt>rosrun tf2_web_republisher tf2_web_republisher</tt></li><li><tt>roslaunch openni_launch openni.launch depth_registration:=true</tt></li></ol>
--><canvas id="img_canvas"> </canvas>
</body>
</html>
http://www.lryc.cn/news/572412.html

相关文章:

  • 嵌入式开发之freeRTOS移植
  • Kafka性能调优全攻略:从JVM参数到系统优化
  • Java的SpringAI+Deepseek大模型实战
  • 基于keepalived、vip实现高可用nginx (centos)
  • mongodb单节点改副本集模式
  • Python 开发环境全栈隔离架构:从 Anaconda 到 PyCharm 的四级防护体系
  • NetworkManager介绍与用法
  • 【单片机】51单片机练习代码
  • GRBL_UNO R3编译下载
  • Spring Boot 虚拟线程 vs WebFlux:谁更胜一筹?
  • Spring-创建第一个SpringBoot项目
  • apisix-使用hmac-auth插件进行接口签名身份验证\apisix consumer
  • SpringBoot项目启动时自动加载数据到Redis的完整实现方案,用于存储字典,定时任务,登录用户等
  • Spring @Autowired 依赖注入全解析
  • 语音情感识别:CNN-LSTM 和注意力增强 CNN-LSTM 模型的比较分析
  • Hive优化详细讲解
  • Redis 的优势有哪些,它是CP 还是 AP?CAP 理论又是什么?
  • C#的泛型和匿名类型
  • Ubuntu最新版本(Ubuntu22.04LTS)安装nfs服务器
  • Java八股文——计算机网络「传输层篇」
  • CppCon 2017 学习:Everything You Ever Wanted to Know about DLLs
  • CppCon 2017 学习:dynamic_cast from scratch
  • 【AJAX 实战】图书管理系统上 渲染图书列表+新增图书+删除图书
  • windows系统JDK1.8 与JDK 17切换
  • css3 文本效果(text-shadow、text-overflow、word-wrap、word-break)文本阴影、文本换行、文本溢出并隐藏显示省略号
  • 数据结构 6(算法)
  • CMake实践:指定gcc版本编译和交叉编译
  • 华为OD机试-最佳植树距离-二分(JAVA 2025A卷)
  • DeserializationViewer使用说明
  • Java并发编程实战 Day 29:大数据处理的并行计算模型