ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
1

How to fill a sensor_msgs/image without a memcpy ?

asked 2011-03-08 01:01:57 -0600

Nicolas Turro gravatar image

Hi,

i am writing a ros driver for our deepsea tyzx stereo camera. I try to adapt the driver for firewire camera, and i need an advice for this part of the code :

right_image_.data.resize(image_size);
memcpy(&right_image_.data[0],  DSIF->getRImage(), image_size);

right_image_ is a sensor_msg/Image , whose field data is a vector<uint_8,...&gt; image_size="" is="" the="" size="" of="" the="" image="" returned="" by="" my="" camera="" proprietary="" driver,="" and="" dsif-="">getRImage() is a pointer to this image.

My question is : Is it possible to avoid a memcpy with something like creating a vector with a custom allocator using directly the pointer returned by DSIF->getRImage() as data and image_size as size, plus type if needed, and then use set_data_vec() fuction of the image message ?

edit retag flag offensive close merge delete

Comments

What's your use case that you want to avoid the memcpy? Seems like if you had th ROS image and the Driver image sharing data, the driver's framerate could become dependent on how quickly you could publish ROS images (i.e. you'd have to lock to avoid the changing the driver frame while publishing).
Eric Perko gravatar image Eric Perko  ( 2011-03-11 07:30:06 -0600 )edit

Ideally they would have a nodelet receiving the sensor_msgs::Image in a callback so the serialization would be skipped. However the initial copy from the driver is still wasted cycles. They aught to be able to create a custom allocator.

emrainey gravatar image emrainey  ( 2016-11-02 00:40:48 -0600 )edit

3 Answers

Sort by ยป oldest newest most voted
5

answered 2011-04-01 11:28:06 -0600

Patrick Mihelich gravatar image

Hi Nicolas,

It's possible to avoid that memcpy, but probably not useful.

Consider what happens in detail when you publish your image message to a separate node:

  1. You mempcy the data to a sensor_msgs/Image message.
  2. When you publish the sensor_msgs/Image, ROS serializes its fields into a buffer for inter-process transport - another memcpy.
  3. The subscriber node populates another sensor_msgs/Image by deserializing the received buffer. If the nodes are on the same machine (subscribed over loopback), I believe the kernel optimizes this pretty well, but it's another memcpy or two.

It's possible to reduce the first two steps to a single memcpy by defining your own custom image type, that simply points to the DSIF->getRImage() data, and registering it with roscpp using message traits. Essentially, your custom type pretends to be sensor_msgs/Image (by registering the same MD5 sum) and serializes to exactly the same over-the-wire format as sensor_msgs/Image, so any subscribing nodes can't tell the difference. I can point you to examples of this if you want.

However, after doing all that we're still talking about IPC and 2-3 memcpy's at best. Another issue is that you can't directly use image_transport to provide compressed topics anymore, because image_transport currently understands only sensor_msgs/Image.

A different approach is to write your camera driver and processing nodes as nodelets, and load them all in the same process. In that case you skip the serialization bottleneck (steps 2 and 3) entirely. The driver publishes a shared_ptr<sensor_msgs::Image>, and that gets passed directly to the in-process subscriber nodelets. You still pay the cost of the initial memcpy, but that's it.

There's a tutorial on porting nodes to nodelets that needs a little love, but gives you the idea. For a complete example of nodelet-ized camera driver, see Diamondback camera1394.

So my advice is: live with the memcpy, and consider turning your driver into a nodelet if (and only if) message serialization is causing performance problems.

edit flag offensive delete link more

Comments

Side note: The memcopy for interprocess transport won't happen between nodelets if boost::shared_ptr is used.
Asomerville gravatar image Asomerville  ( 2011-05-12 08:54:38 -0600 )edit
0

answered 2011-03-11 06:14:52 -0600

I am not sure if I got your question right. For what it's worth: There is a function "fill(...)" see here but I do not know what it does internally. Probably memcpy...

edit flag offensive delete link more

Comments

Source link: http://www.ros.org/doc/api/sensor_msgs/html/fill__image_8h_source.html#l00042 . Short answer is yes, it does a memcpy.
Eric Perko gravatar image Eric Perko  ( 2011-03-11 07:25:57 -0600 )edit
0

answered 2011-03-16 04:24:27 -0600

Nicolas Turro gravatar image

updated 2011-03-16 04:30:27 -0600

You are right, the fill function also does a memcpy :/

I was hopping for some mechanism using : http://www.ros.org/wiki/roscpp/Overview/MessagesCustomAllocators

on how to 'build' a vector using a custom allocator and a pointer to the data.

edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2011-03-08 01:01:57 -0600

Seen: 3,280 times

Last updated: Apr 01 '11