ros-perception / image_common

Common code for working with images in ROS
http://www.ros.org/wiki/image_common
124 stars 219 forks source link

image_transport publisher nodes should support subscriber specific compression config #273

Open adityapande-1995 opened 1 year ago

adityapande-1995 commented 1 year ago

Overview

Suppose there is a setup with one image transport publisher node, and one subscriber node, which uses the theora std to compress images. If we add a second subscriber using the theora std, it has to use the same config (bitrate, quality, etc) as the subscriber 1.

Workarounds for now

Right now, this can be implemented using republish nodes. We could the actual publisher node, then several republish nodes that publish the compressed topics with the required configs.

Implementation suggestions

The subscriber can make a service call to the publisher, requesting the config it needs. The publisher should spin up the required topic with the config, and reply with a boolean status. If the response is positive, the subscriber should start listening in on the new topic and the required config.

The publisher can then stop the new encoding if no subscriber is listening in on it.

Open to design suggestions @ahcorde @clalancette @mjcarroll

clalancette commented 1 year ago

This is a pretty large and complicated issue.

First, I'll mention that this is very similar to (though perhaps not exactly the same as) the work I did back in 2021 on negotiated topics/REP-2009. The idea there was that we wanted to have the publishers and subscribers "negotiate" to find the subset of topics that would satisfy all of the subscribers, while creating the least number of publishers. You want to create the least number of publishers because that means you end up redoing the compression (or whatever) the fewer number of times. The problem with negotiation, however, is that it ends up being very complex, and thus probably is only useful in certain situations. Still, I encourage you to read the work there as it informs my thinking here.

One other preamble thing I'll mention here is that you have to think about the combination of topic_name, topic_type, and the metadata specified in the topic type as a tuple. For instance, at one extreme you could have no compression metadata specified in the topic type at all, and instead just do this with topic names: image_raw, image_theora_compressed, image_jpg_compressed, etc. In that case, the subscribers just have to know that the topic name they are using encodes the data the way the topic name expresses. On the other extreme, you could have a single message type (Image), which specifies the compression (none, theora, jpg, etc), and doesn't care about the topic name at all. Our ROS systems actually are somewhere in the middle here, where we have separate topic types for compressed/raw (CompressedImage/Image), we have metadata within the types describing the type of compression, and we have conventions on the topic name image/image_raw.

Coming back to the original question, in my mind, the "workarounds" section you have above isn't actually a workaround; that is probably the most ROS-like way to do it. That is, you end up having a network that looks like:

┌───────────────────────┐  image_raw   ┌────────────────────────┐
│ Theora compress node  │ ◀─────────── │ Raw image collect node │
└───────────────────────┘              └────────────────────────┘
  │                                      │
  │ image_theora                         │ image_raw
  ▼                                      ▼
┌───────────────────────┐              ┌────────────────────────┐
│ Theora subscribe node │              │   JPG compress node    │
└───────────────────────┘              └────────────────────────┘
                                         │
                                         │ image_jpg
                                         ▼
                                       ┌────────────────────────┐
                                       │   JPG subscribe node   │
                                       └────────────────────────┘

The downside to this setup, of course, is performance. In particular, the Raw image collect node needs to deliver the data on the network twice; once to the Theora compress node, and once to the JPG compress node. But the thing is that we have solutions for that. For instance, the absolutely most efficient way to do this would be to make all three of those nodes rclcpp intraprocess nodes in the same process. If you then also make sure that the subscribers are const shared_ptr subscriptions, then no copying will be done at all in delivering the raw data. It will only be accessed while doing the compression (which would have to be done anyway).

This is my initial thought of the best way to do this. The whole concept of creating and destroying publishers on the fly in reaction to what subscribers want is possible, but is complicated and tricky to get right. And it makes the graph difficult to debug. So I'd avoid it unless we really find we can't do it another way.

adityapande-1995 commented 1 year ago

Linked PR : https://github.com/ros-perception/image_common/pull/275