System designHow-to

Compressed image topic not published: get /compressed streams working

Your driver publishes only image_raw. Load the image_transport plugins, restart, or run republish — then confirm the compressed topic streams at frame rate.

LumaSpec Vision9 min read Share on LinkedIn

On this page 9 sections
  1. 01Why the compressed topic is missing
  2. 02Install the plugins and restart the driver
  3. 03Republish when you cannot restart the driver
  4. 04Verify the stream
  5. 05What the stream costs: the numbers
  6. 06Pick the transport per stream
  7. 07Where the stream should run
  8. 08Common mistakes
  9. 09Questions

A depth camera driver that lists /camera/color/image_raw but no /camera/color/image_raw/compressed is not broken. The image_transport compression plugins were simply not loaded when the driver node started, so the compressed child topics were never advertised. This guide gets them back two ways: install the plugin packages and restart the driver, or run an image_transport republish node that converts raw to compressed on the fly. You will finish with a working /compressed and /compressedDepth topic, checked with rostopic hz and rostopic bw, plus the numbers that tell you whether the link you are feeding can carry raw at all. It is written for anyone streaming color and depth to RViz, a laptop or a second computer over Wi-Fi.

Why the compressed topic is missing

image_transport is a publisher layer inside the driver, not a separate node. When a driver advertises an image through it, the library loads every transport plugin it can find once, at node start, and creates one child topic per plugin under the base name: /compressed from compressed_image_transport (JPEG or PNG for color) and /compressedDepth from compressed_depth_image_transport (PNG for depth). Topics appear in the topic list immediately; data only flows once someone subscribes.

So an empty grep compressed means one of two things. Either the plugin packages are missing on the machine running the driver — the usual case with container images and server installs, which ship the base libraries but not the plugins — or the driver publishes plain sensor_msgs/Image through an ordinary publisher, which no plugin can decorate. Both have short fixes.

Tuning the topics once they exist — format, JPEG quality, decoder settings — is the subject of the guide to image transport compression parameters; here the goal is to make them exist.

Install the plugins and restart the driver

  1. Confirm what is missing. ROS 1: rostopic list | grep compressed. ROS 2: ros2 topic list | grep compressed. Empty output means no plugin has loaded.
  2. Install both plugin packages from your distribution's repository:
sudo apt install ros-noetic-compressed-image-transport ros-noetic-compressed-depth-image-transport

On ROS 2 the same package names carry the distro prefix, for example ros-humble-compressed-image-transport and ros-humble-compressed-depth-image-transport. Swap noetic or humble for your distribution: melodic, foxy, jazzy and so on.

  1. Restart the camera driver completely: stop the launch and start it again. Plugins load once, at node start, so installing them while the driver runs changes nothing about the running node.
  2. Run the grep again. A color and depth driver now shows /camera/color/image_raw/compressed, /camera/depth/image_rect_raw/compressedDepth, and usually a /compressedDepth child under the color base too, because every loaded plugin attaches to every image_transport publisher. Use /compressed for color.

Republish when you cannot restart the driver

When the driver belongs to a launch you cannot bounce, or it never used image_transport, a republish node subscribes with one transport and republishes with another. Run it on the machine that runs the driver.

ROS 1, color:

rosrun image_transport republish raw in:=/camera/color/image_raw compressed out:=/camera/color/image_raw

That publishes /camera/color/image_raw/compressed. Depth follows the same pattern with the depth plugin:

rosrun image_transport republish raw in:=/camera/depth/image_rect_raw compressedDepth out:=/camera/depth/image_rect_raw

ROS 2 takes the transports as arguments and the topics as remaps:

ros2 run image_transport republish raw compressed --ros-args -r in:=/camera/color/image_raw -r out:=/camera/color/image_raw
ros2 run image_transport republish raw compressedDepth --ros-args -r in:=/camera/depth/image_rect_raw -r out:=/camera/depth/image_rect_raw

Keep the republisher on the driver's host. Raw frames must not cross the Wi-Fi link before compression — that would be the exact failure you started with.

Verify the stream

Rate first: rostopic hz /camera/color/image_raw/compressed should sit at the driver's configured frame rate — 30.0 on a 30 fps stream. ROS 2 reads the same with ros2 topic hz. Bandwidth second: rostopic bw prints measured bytes per second, which you want for sizing the link. Each republish node you add does its own encode on the host, so when several nodes need the same stream, run one republisher and share its output — the camera stream fan-out guide covers sharing one capture across consumers.

RViz subscribes through image_transport as well: in the Image or Camera display, set the Transport Hint property to compressed instead of typing a full topic name. If a display stays empty while hz reads a healthy rate, the streams are not meeting: on ROS 2 that is nearly always a QoS mismatch, which the RViz2 QoS mismatch walkthrough diagnoses; if color and depth land under each other's names, the depth and color compression routing guide covers that case.

What the stream costs: the numbers

bytes per frame = width × height × bytes per pixel Mbit/s = bytes per frame × fps × 8 ÷ 1,000,000
Stream, 640 × 480 at 30 fps Bytes per frame Rate 100 Mbit/s link
Color rgb8 raw 921,600 221 Mbit/s No
Color JPEG, compressed ≈92,000 ≈22 Mbit/s Yes
Depth 16UC1 raw 614,400 147 Mbit/s No
Depth PNG, compressedDepth ≈307,000 ≈74 Mbit/s Tight

The color arithmetic: 640 × 480 × 3 = 921,600 bytes per frame; × 30 fps = 27.6 MB/s; × 8 = 221 Mbit/s. Depth at 2 bytes per pixel: 640 × 480 × 2 = 614,400 bytes, 18.4 MB/s, 147 Mbit/s. Step the resolution up to 1280 × 720 and raw color is 1280 × 720 × 3 = 2,764,800 bytes per frame, 82.9 MB/s, 664 Mbit/s at 30 fps — JPEG brings that to roughly 66 Mbit/s.

Against real links: a healthy 2.4 GHz Wi-Fi connection delivers 50–100 Mbit/s, so raw color fails even at 640 × 480, and the compressed stream at ≈22 Mbit/s fits with room to spare. A wired GigE link carries about 940 Mbit/s of real throughput, so even 720p raw color fits — wire beats compression whenever wire is an option. Halve the camera to 15 fps and every number halves with it: 921,600 × 15 × 8 ÷ 1,000,000 = 110.6 Mbit/s. The JPEG and PNG ratios move with scene texture, so take one measurement with rostopic bw and size the link to that.

Pick the transport per stream

Color for viewing: /compressed (JPEG). Lossy but visually faithful; right for RViz, remote monitoring and logging previews. Never for measurement:

Depth anywhere: /compressedDepth. PNG is lossless, so decoded depth carries the same 16-bit values as raw; it is safe to record and to inspect.

Anything measured: raw. Decision, stated once: viewing over Wi-Fi — compressed; depth viewing and depth bags — compressedDepth; measurement, calibration and odometry on visual features — raw.

Where the stream should run

Put the driver and any republisher on a machine in the cell and cross the distance on wired Ethernet, so Wi-Fi carries the compressed stream from the table above rather than raw RGB. The vision controllers category is made for that job:

Vision controllersHikrobot MV-VC3301H-128G66 I3-8100, 8GB+128G SSD, No PoE, PCIe expansion supported, Incl. VM6200Pro licenseMV-VC3301H-128G66
LAN ports
5+ LAN ports
USB 3 ports
3-4 USB 3 ports
$2,419.00View part
Vision controllersHikrobot MV-VC5525-256G70-NN VC5000 Vision Controller, 12th-I5, 32GB+256G SSD, Supported PCIEMV-VC5525-256G70-NN
LAN ports
5+ LAN ports
USB 3 ports
3-4 USB 3 ports
$4,479.00 · quotedView and quote

The MV-VC5525-256G70-NN has 5+ LAN ports, PoE camera ports, 8 built-in channels and 32 GB of memory; PoE ports power PoE cameras directly and keep the cell cabling to one switch. The MV-VC3301H-128G66 pairs an Intel Core i3 with 8 GB of memory, a 128 GB SSD and 5+ LAN ports, no PoE. RViz plus a couple of republish nodes sit comfortably in 8 GB; give 16 GB or more when you also record bags.

If the far end is a panel or HMI rather than RViz, image_transport is not what those devices read — panels consume RTSP or MJPEG streams, as in this guide to streaming RTSP camera video to industrial HMI panels. And when you are specifying depth hardware rather than rescuing a laptop link, check the ROS interface before you buy: the 3D sensors category spans laser profilers and stereo depth cameras, and expert support comes free with every order.

Common mistakes

  • Installing the plugins but not restarting the driver. Plugin loading happens at node start; topics are advertised then, never retroactively.
  • Running the republisher on the viewer machine. Raw frames then cross the slow link first, which is the failure you began with.
  • Expecting compression to relieve the camera's own cable. Compression runs on the host, downstream of the driver, so it cannot change the load on the camera link. If the driver log repeats control_transfer returned error warnings, the link itself is unstable: lower the camera's fps or resolution and follow the USB bandwidth check for depth and color streams.
  • Recording JPEG into a bag and measuring on it later. Keep raw color for any bag that might feed tuning or training.
  • Flipping stream enable flags and waiting for compressed children. Launch arguments that enable a stream add base topics; transports only come from plugins or republish.
  • Subscribing to the base topic with a plain subscriber and wondering why bandwidth did not drop. To receive CompressedImage, subscribe to the /compressed topic directly or set a compressed transport hint through image_transport.

If the topic list still looks wrong after all of this, send the launch file and the grep output through the contact page — or configure a vision system around cameras and controllers that publish what you need. More stream-side debugging guides live on the systems topic page.

Questions

Why does the compressed topic show in the list but deliver no frames?

A transport topic is advertised when the driver starts and only carries data while a subscriber is connected. If the rate still reads zero with your node subscribed, publisher and subscriber are not meeting: on ROS 2 check QoS compatibility with ros2 topic info; on ROS 1 make sure a republish node is actually running and remapped to the right base topic name.

Is the /compressed topic lossless?

Not necessarily. The color /compressed topic carries JPEG or PNG as configured — check the format field of the CompressedImage message to see which — and JPEG is lossy, so it must not feed measurement or calibration. /compressedDepth is PNG-based and lossless: decoded depth keeps its exact 16-bit values.

How much CPU does running republish cost?

Compression runs on the publishing host, so a republisher adds one encode per frame. A 720p color frame typically JPEG-encodes in a few milliseconds on a desktop-class core, which leaves headroom at 30 Hz. Watch the republisher with rostopic hz: if its rate falls below the driver's configured frame rate, the host CPU is the bottleneck — halve the fps or move the node.

Does compression reduce the camera's USB bandwidth?

No. The camera sends raw frames over its own USB link regardless of what clients subscribe to; compression happens in the host after the driver has the data, cutting network and disk traffic only. To cut USB load, lower resolution or frame rate at the camera itself. Repeated control-transfer warnings in the driver log point to the same conclusion.

Can I record compressed topics into a rosbag?

Yes. Depth bags are a clear win: /compressedDepth decodes to identical 16-bit values, so the bag shrinks without data loss. For color, JPEG in a bag throws detail away permanently, so record raw color whenever the bag might later feed tuning, training or measurement.