Sending an image over Connext

8 posts / 0 new
Last post
Offline
Last seen: 5 years 3 weeks ago
Joined: 02/27/2014
Posts: 15
Sending an image over Connext

With G-d's assistance

How could I send an image over Connext middleware?

(I'm new in RTI, aswell as being new to dealing with images in code)

Thanks!

Organization:
Offline
Last seen: 1 month 1 week ago
Joined: 01/15/2013
Posts: 88

Hi,

An image is just like any other type, and for using it with Connext, you'll have to define a type according to your format/encoding. With RTI Connext, you can define your types in IDL, a programming language-independent type-definition language.

Why don't you take a look at this RTI video use-case? You can download it for both Linux and Windows, and browse the code, play with it, and learn.

I hope this helps shed some light.

Thanks,

Juanlu

Offline
Last seen: 1 month 1 week ago
Joined: 01/15/2013
Posts: 88

Side note: I pointed you to this example as dealing with video is like dealing with sending images every certain period of time.

Offline
Last seen: 5 years 3 weeks ago
Joined: 02/27/2014
Posts: 15

Thanks!

I actually did get a look at that use-case previously,

though it's quite complicated for me to fathom.

I need a very simple template-like example of an idl-made type for generating the code,

and then a c++ example of how to read binarily from an image file and sending-off the data that was read via the type which was defined for this purpose.

Offline
Last seen: 1 month 1 week ago
Joined: 01/15/2013
Posts: 88

Hi Oriel,

So, how I would proceed (I'm going to asume a raw image type, no compression) is this way. The examples below are not tested, I'm writing them as I go, just ideas on how to do what you want.

Usually you wouldn't work without compression. I think there are many image processing libraries, like Boost's GIL libraries, but there are others.

1) Create an IDL representation of the type, something like

struct RGB {
    octet r;
    octet g;
    octet b;
};

const short SIZE_HORIZONTAL = ...;
const short SIZE_VERTICAL = ...;

struct Image {
    RGB matrix[SIZE_HORIZONTAL][SIZE_VERTICAL];
};

2) With this, you need to generate C++ code to be used by your application linking against the RTI Connext Libraries. For that, RTI Connext includes a tool called RTI DDS Code Generator. Given a type described in IDL (or, for extension, in XML or XSD) it can generate code in various programming languages. Take a look at section 3.3 in the RTI Connext Core Libraries and Utilities User's Manual.

3) RTI DDS Code Generator (rtiddsgen) will generate code. Your application will need to include and compile the generated code, as well as link against the RTI DDS Core Libraries. If you use the "-example" option in RTI DDS Code Generator, it will also generate example Publisher and Subscriber application stubs. It will also generate Visual Studio projects (if you're using Windows) and makefiles (for other platforms).

What type of templatisation are you looking for? Based, for example, on the compression mechanism / encoding?

Thanks,

Juanlu

Offline
Last seen: 5 years 3 weeks ago
Joined: 02/27/2014
Posts: 15

Thanks, really!

I was wondering - can't I just read the image file binarily and send it over Connext in an array<char* buffer, size>   ?

Anyway, I ran the rtiddsgen - and now I have a whole solution for this image.

I want to test it on a specific image: 451x600, .jpg, 794 KB.

First, how do I tell the publisher to get hold of this image --> place it in the RGB matrix???

And second, how do I tell the subscriber to get the image out of the buffer --> show it to the user window???

 

 

Offline
Last seen: 1 month 1 week ago
Joined: 01/15/2013
Posts: 88

Hi Oriel,

In order to send your image file, you have to create a sample of the Image type. With RTI DDS Gen, the type will be defined for you. To create the sample in the Stack, you can declare it normally. DDS Gen also provides some helper methods to create a sample in the heap. Take a look at class FooTypeSupport in the DDS C++ API reference. Here, Foo is a metaphor representing your type. In your case, to create a sample of the type you could call:

 Image * myImage = ImageTypeSupport::create_data();

Now, to fill that sample with the image data, you have to loop through the two dimensions in the matrix field, and copying from the origin:

for (int i = 0; i < SIZE_HORIZONTAL; ++i) {
    for (int j = 0; j < SIZE_VERTICAL; ++j) {
        myImage->matrix[i][j].r = ...; // red component
        myImage->matrix[i][j].g = ...; // green component
        myImage->matrix[i][j].b = ...; // blue component
    }
}

Once you have a valid sample that you want to send, you can call the write() operation on your DataWriter to send the sample over on DDS. The following code sets up the infrastructure to be able to publish your image type:

// Create a Domain Participant in the domain ID you need to send data to or receive data from
DDSDomainParticipant * domainParticipant = DDSDomainParticipantFactory::create_participant(DDSDomainParticipantFactory::get_instance(), id, ...);
// Don't forget to check errors on return codes
// Register the Image type with the Domain Participant just created
ImageTypeSupport::register_type(domainParticipant, ImageTypeSupport::get_type_name());
// Don't forget to check errors on return codes
// Create a topic for the image type. Images will be published under this topic.
Topic * imageTopic = domainParticipant->create_topic("ImageTopic", ...);
// Don't forget to check errors on return codes
DDSDataWriter * genericWriter = domainParticipant->create_datawriter(imageTopic, ...);
// Don't forget to check errors on return codes
// We want to use the generated DataWriter type (ImageDataWriter) to publish our type
ImageDataWriter * imageWriter = ImageDataWriter::narrow(genericWriter);
// Don't forget to check errors on return codes

Then, once you have a valid Image sample filled up, you can send it by calling:

...
imageWriter->write(myImage, DDS_HANDLE_NIL);
...

For reading, there are many choices, but they all end up calling the method  ImageDataReader::read() or ImageDataReader::take() and their variations. The easiest (although not efficient) way to read samples is to poll for data on a loop:

while (keepReadingImages) {
    ...
    Image myReadImage;
    SampleInfo mySampleInfo;
    retCode = myImageReader->take_next_sample(myReadImage, mySampleInfo);
    if (retCode == DDS_RETCODE_OK) {
        if (mySampleInfo.valid_data) {
            // Process the image sample
            for (i = 0; i < HORIZONTAL_SIZE; ++i) {
                for (j = 0; j < VERTICAL_SIZE; ++j) {
                    // process components r, g and b of the received image
                }
            }
        }
    }
}

I would suggest that you check the API reference and documentation for FooDataWriter, FooDataReader and FooTypeSupport. Chapter 6 (Sending Data) and 7 (Receiving Data) of the RTI Connext Core Libraries and Utilities User's Manual may help you understanding more specific details about writing and receiving data over DDS.

Thanks,

Juanlu

Offline
Last seen: 5 years 3 weeks ago
Joined: 02/27/2014
Posts: 15

Thank-you very much for the post above, it certainly comes in handy.

I did not know how to get hold of the image file

in-order to fill in the specific R-G-B information appropriately.

 

Still, I preferred tried first a simpler solution:

Passing the whole image file binarily with a char array via connext...

Something went wrong...

I attached the file of the code for putting the image file in a char[] buffer and back

which seemed to work outside of RTI.

Somewhere while the information was changing it's types to "DDS_Types",

or something like that, errors were encountered...

 

I'd be happy to understand what's wrong in-order to face the problem,

and get it behind me,

G-d willing.

File Attachments: