image_transport trong ROS2: gửi ảnh hiệu quả giữa các node
Atlasbot · 18/8/2026 · 11 phút đọc
Một khung hình camera 640×480 chưa nén (raw) nặng gần 1MB — publish liên tục 30 khung hình/giây qua topic ROS2 thông thường có thể chiếm băng thông đáng kể, nhất là khi truyền qua mạng giữa nhiều máy tính trong cùng một AMR. Gói image_transport giải quyết vấn đề này.
Khái niệm chính
Nếu publish ảnh bằng sensor_msgs/Image qua topic ROS2 bình thường (rclpy.Publisher), dữ liệu luôn ở dạng thô — mỗi khung hình gửi đi không hề nén, dù có bao nhiêu subscriber lắng nghe. Với robot chạy nhiều node trên nhiều máy tính khác nhau (VD: 1 máy xử lý camera, 1 máy chạy giao diện giám sát — đúng kiến trúc ROS2 Layer đã học ở bài ROS2 Layer trong AMR), băng thông mạng nội bộ nhanh chóng trở thành nút thắt cổ chai.
Nguyên lý hoạt động
image_transport cung cấp một lớp API tương tự publisher/subscriber thông thường, nhưng cho phép chọn plugin truyền tải khác nhau — phổ biến nhất là raw (không nén, giống publish thông thường), compressed (nén JPEG/PNG), và theora (nén video, tối ưu cho luồng ảnh liên tục).
Điểm hay là subscriber không cần biết publisher đang dùng plugin nào — image_transport tự thương lượng định dạng, giải nén trong suốt trước khi trả ảnh về cho code người dùng.
# Publisher (C++ thường dùng cho tốc độ, nhưng ý tưởng giống Python)
image_transport::ImageTransport it(node);
image_transport::Publisher pub = it.advertise("camera/image", 1);
pub.publish(cv_bridge::CvImage(header, "bgr8", frame).toImageMsg());
# Xem các topic ảnh + biến thể nén mà image_transport tạo ra
ros2 topic list | grep image
# camera/image
# camera/image/compressed
# camera/image/compressedDepth (nếu có depth camera)
Kiến thức kỹ thuật
Công thức
Tỉ lệ nén JPEG điển hình giúp ước lượng lợi ích băng thông khi chuyển từ raw sang compressed:
Kích_thước_raw ≈ Chiều_rộng × Chiều_cao × 3 byte (RGB)
Kích_thước_compressed ≈ Kích_thước_raw / Tỉ_lệ_nén_JPEG
VD: 640×480 RGB raw ≈ 640×480×3 ≈ 921,600 byte ≈ 900KB
JPEG chất lượng trung bình thường nén 10-20 lần
Kích_thước_compressed ≈ 900KB / 15 ≈ 60KB
Băng_thông_raw (30fps) ≈ 900KB × 30 ≈ 27MB/s
Băng_thông_compressed (30fps) ≈ 60KB × 30 ≈ 1.8MB/s
Thông số
| Plugin | Băng thông | Chi phí CPU (nén/giải nén) | Dùng khi |
|---|---|---|---|
| raw | Cao nhất | Không có | Camera và node xử lý cùng máy |
| compressed | Thấp (JPEG/PNG) | Trung bình | Truyền qua mạng tới máy khác |
| theora | Thấp, tối ưu cho video liên tục | Cao hơn compressed | Luồng video dài, ưu tiên nén tốt hơn ảnh tĩnh |
Ứng dụng thực tế
Nếu camera và node xử lý ảnh (OpenCV, YOLO...) chạy trên cùng một máy tính, dùng raw là đơn giản nhất — không có chi phí nén/giải nén thừa. Chỉ cần chuyển sang compressed khi ảnh phải truyền qua mạng tới máy khác, ví dụ gửi hình ảnh camera robot về giao diện giám sát trên PC ở xa — đúng như tính ở mục Công thức, tiết kiệm băng thông hơn 10 lần trong khi chi phí CPU nén/giải nén thường không đáng kể so với lợi ích đó.
Ví dụ thực tế
# So sánh băng thông thực tế giữa raw và compressed
ros2 topic hz /camera/image # tần số publish raw
ros2 topic bw /camera/image # băng thông thực tế raw
ros2 topic hz /camera/image/compressed
ros2 topic bw /camera/image/compressed # băng thông thực tế đã nén
Kết quả điển hình (camera 640x480 @ 30fps):
/camera/image -> ~27 MB/s (raw)
/camera/image/compressed -> ~1.8 MB/s (JPEG nén)
Với mạng WiFi nội bộ (băng thông thực tế thường 10-50 MB/s tuỳ điều kiện),
raw có thể chiếm gần hết băng thông khả dụng, ảnh hưởng các topic khác
(như /scan, /odom) cùng truyền qua mạng — compressed giải quyết đúng vấn đề này
Lỗi thường gặp
- Dùng
rawkhi ảnh cần truyền qua mạng tới máy khác — như ví dụ trên, chiếm băng thông lớn không cần thiết, có thể ảnh hưởng các topic quan trọng khác (odometry, scan) cùng chia sẻ mạng. - Dùng
compressedkhi camera và node xử lý cùng máy — trả chi phí CPU nén/giải nén không cần thiết khi không có lợi ích băng thông tương xứng (không đi qua mạng). - Không kiểm tra băng thông thực tế bằng
ros2 topic bw— chỉ ước lượng lý thuyết mà không xác nhận thực tế, dễ bỏ sót các yếu tố khác (overhead giao thức, nhiều subscriber cùng lúc). - Giả định subscriber tự động hiểu mọi plugin mà không kiểm tra tương thích — dù
image_transportthương lượng định dạng trong suốt, cần đảm bảo cả publisher lẫn subscriber đều cài đúng plugin cần thiết (VD:compressed_image_transport).
Kết luận
image_transport tách biệt việc "gửi ảnh" khỏi "cách nén ảnh" — giúp chuyển đổi giữa raw và các định dạng nén mà không phải sửa lại code xử lý ảnh ở phía subscriber. Chọn đúng plugin theo việc ảnh có đi qua mạng hay không, dựa trên chênh lệch băng thông đáng kể giữa raw và compressed đã tính ở trên. Bài tiếp theo trong chuyên mục đi vào Hiệu chuẩn Camera — bước chuẩn bị cần thiết khi ứng dụng cần đo khoảng cách/kích thước chính xác từ ảnh.