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

Filling sensor_msgs/Image with uint8_t buffer array [closed]

asked 2014-10-29 00:42:11 -0600

l0g1x gravatar image

updated 2014-10-29 07:37:23 -0600

So I'm working on making a camera driver, and the data struct contains the frame data such as the height and width, and uint8_t leftData and uint8_t rightData pointers. Ive been trying to see which way would be the best way to just fill simple fill in the sensor_msgs/Image message i create, but i cannot seem to find how to do it.

Here is what i have tried so far:

    leftImage.height                = pFrameData->height;
    leftImage.width                 = pFrameData->width;
    leftImage.encoding              = sensor_msgs::image_encodings::MONO8;
    leftImage.step                  = 64;
    leftImage.data                  = pFrameData->leftData;

But with that i get a error saying "no viable overloaded '=' "

Then after searching around i found people linking to the sensor_msgs::fillImage() header, and tried to use the memcpy method, but that did not work either (i got a seg fault)

Then i tried using the cv::Mat constructor to see if i could at LEAST somehow get a image to publish, by passing the size, type, and data pointer (pFrameData->leftData).

No luck with any of them. Im really new to opencv, cv_bridge, and camera related things in general. Would someone be able to guide me in the right direction?

Here is a example buffer for the left camera if i just print to the screen: 0x7ff7549ea800

EDIT 1:

Here is my frame callback function (after trying ahendrix's solution, which gave a malloc error which i put in comments below):

void frameCallback(const PFrame pFrameData)
{
    leftImage.header.stamp            = ros::Time::now();
    leftImage.header.frame_id       = "camera";
    leftImage.height                      = pFrameData->height;
    leftImage.width                       = pFrameData->width;
    leftImage.encoding                  = sensor_msgs::image_encodings::MONO8;
    leftImage.step                         = 64;

    const int image_size = pFrameData->height * pFrameData->width;
    leftImage.data.reserve(image_size);

    for( int i=0; i < image_size; i++ )
    {
            leftImage.data.push_back(pFrameData->leftData[i]); 
    }
 }
edit retag flag offensive reopen merge delete

Closed for the following reason the question is answered, right answer was accepted by l0g1x
close date 2015-04-02 21:58:38.224226

3 Answers

Sort by ยป oldest newest most voted
1

answered 2014-10-29 20:08:33 -0600

l0g1x gravatar image

So after @ahendrix helped explaining a few things, i ended up using the sensor_msgs::fillImage() function to store my left/right camera buffer data into a sensor_msgs::Image.

Here is my code:

    ros::Time       timeNow         = ros::Time::now();
    std::string     frame           = "camera";

    leftImage.header.stamp          = timeNow;
    leftImage.header.frame_id       = frame;

    rightImage.header.stamp         = timeNow;
    rightImage.header.frame_id      = frame;

    // Fill the left image message
    sensor_msgs::fillImage( leftImage,
                            sensor_msgs::image_encodings::MONO8,
                            240, // height
                            320, // width
                            320, // stepSize
                            pFrameData->leftData);

    // Fill the right image message
    sensor_msgs::fillImage( rightImage,
                            sensor_msgs::image_encodings::MONO8,
                            240, // height
                            320, // width
                            320, // stepSize
                            pFrameData->rightData);

    leftImagePub.publish(leftImage);
    rightImagePub.publish(rightImage);

    sensor_msgs::clearImage(leftImage);
    sensor_msgs::clearImage(rightImage);

If you look in the sensor_msgs::fillImage() the step size (in my case) was the width of the image; the total amount of columns your image has.

inside the fillImage() you will see that a size_t st0 is created by multiplying the step size (which we said is the width) * rows (height of the image), which will create a size and then allocate the total amount of pixels your image has.

edit flag offensive delete link more
2

answered 2014-10-29 01:07:15 -0600

ahendrix gravatar image

The array members in messages are std::vectors. I suspect your image data is a pointer to a buffer, and you can't assign from a pointer into a std::vector; you'll have to copy the data manually. (This is what the 'no viable overload' message is trying to tell you)

Something like this might work:

const int image_size = pFrameData->height * pFrameData->width;
leftImage.data.reserve(image_size);
for( int i=0; i < image_size; i++ ) {
    leftImage.data.push_back(pFrameData->leftData[i]); // do pixel format translation here if necessary
}

Of course, this assumes that your image buffer is in the same format as the output image. If it isn't, you'll have to do some sort of conversion.

edit flag offensive delete link more

Comments

Can i use the sensor_msgs/fillImage inline function? I tried to use that last night to, well i manually copied in the size allocation, and memcpy, but that was what i got the set fault on. Since its a inline i assumed it would've have been the same thing as just including the header. Correct?

l0g1x gravatar image l0g1x  ( 2014-10-29 07:28:50 -0600 )edit

so i just tried that and i still got a seg fault, and the next time i tried to run the node i got this error " malloc: * error for object 0x7fd0e0d12a30: pointer being freed was not allocated * set a breakpoint in malloc_error_break to debug Abort trap: 6

l0g1x gravatar image l0g1x  ( 2014-10-29 07:32:27 -0600 )edit

I hadn't seen sensor_msgs::fillImage() before. That's probably a better choice.

ahendrix gravatar image ahendrix  ( 2014-10-29 12:19:38 -0600 )edit

That said, you're setting the step size to 64, which implies that each pixel is 64 bytes. That isn't consistent with a MONO8 ecoding...

ahendrix gravatar image ahendrix  ( 2014-10-29 12:20:15 -0600 )edit

This probably might make a difference idk, but i don't think the step size should 64, in the documentation of the camera it says the leftData pointer and rightData pointer are aligned to 64 byte boundaries. Not sure what that means

l0g1x gravatar image l0g1x  ( 2014-10-29 12:56:49 -0600 )edit

64-byte aligned refers to where data is placed in memory. See: http://en.wikipedia.org/wiki/Data_str...

ahendrix gravatar image ahendrix  ( 2014-10-29 14:38:37 -0600 )edit
0

answered 2014-10-29 01:16:18 -0600

kramer gravatar image

updated 2014-10-29 01:20:21 -0600

Assuming your other data types match, data is a vector, so you can't simply set it using =. Which explains your 'overloaded =' error. Why your memcpy didn't work is difficult to say without actual code; it should look something like:

memcpy(leftImage.data.data(),
       pFrameData->leftData,
       sizeof(uint8_t)*pFrameData->height*pFrameData->width)

I may have overlooked some details, this being off the top of my head (e.g., I think you need to cast the 1st and 2nd parameters to void*).

And, after seeing @ahendrix's answer, I realize I forgot to reserve space before the memcpy. D'oh!

edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2014-10-29 00:42:11 -0600

Seen: 4,603 times

Last updated: Oct 29 '14