views:

122

answers:

3

Hi everyone,

I would like to transfer an image from a Java application to a C++ application. I am using sockets as the communication method, and for now this works good with strings.

I want to be able to transmit it both way (Java <-> C++).

The image is NOT a file, this is a memory object/structure. So my main problem is how to encode the image for the transmission, so that it can be used in Java and in C++.

The transfer is on the same machine (no network, so the speed isn't critical), but still the faster/more efficient, the better.

Thank you

Note : I am using OpenCV in C++, and the main goal is to process a webcam stream. I don't / can't use JavaCV or something like that !

+3  A: 

How about sending the RGB bytes. You can get the RGB bytes from BufferedImage and then send it to your C++ layer as a byte array. And then in the C++ layer construct back the the image using that byte array.

Faisal Feroz
Yes this seems like the simple way, but I thought maybe there is a faster/more efficient way. Because this would imply to go through every pixel of the image in Java and in C++.
Matthieu
@Matthieu: How many times per second does this need to happen? You can't transmit an image without some bit of code, somewhere, visiting every pixel. I guess in theory your Java program could (perhaps with JNI) write a complete image buffer into shared memory in the format needed by the C++ program, then the C++ program could pass that directly to the graphics API it's using (as a screen buffer, texture, etc).
Steve Jessop
RGB size can be reduced somewhat with run length encoding. Instead of sending 230 zeros you might send 230 send whichever is smaller - RLE or raw data }. More complex would be to feed the whole lot into a zip stream from Java and use zlib in C++ to decompress.
locka
@Steve : the faster the better, this is for "real time", like a webcam stream.
Matthieu
Take a look at BWT (Burrows Wheeler Transform). I was compressing XML-like files for sending across a wide area network and the compression/decompression was around 3000bytes where the time taken to compress/uncompress outweighed the transmit time. In my case a homespun BWT outperformed ZLib.
graham.reeds
+1  A: 

You should either use a common portable image format (such as .png, .gif, .jpg, .bmp), bearing in mind that some of those are lossy, or else you should send raw pixel data. If you send raw data, then you'll also have to make sure both ends know the image height and width, and the pixel format (that is, the order of channels R, G, B and possibly A, and the number of bits for each). Maybe you need to communicate that as part of the message, but maybe for your application some of those things are always the same.

Steve Jessop
If I use an image format (png, gif, jpg...), I will have to encode, transmit and decode, wich (I guess) is too long. The connection is on the same machine (so fast transmission), so I think the problem here is the time to encode/decode.
Matthieu
You may well be right, but what is the encode/decode time for images of the size you're interested in, compared with the data speed you're getting over a loopback socket?
Steve Jessop
I'm not sur I understand : do you suggest to encode, and then transmit via socket, or encode and write on disk ? (I absolutely don't want to write on disk, because this is a really dirty way and this is too slow)
Matthieu
I'm not suggesting that you change the socket. How much slower is the disk than the socket, btw?
Steve Jessop
I don't understand what you are suggesting
Matthieu
+1  A: 

Using an efficient, cross-language data interchange format like Google protobuf, might be a solution. protobuf allows you to interchange image objects like this:

// Java image class

class Image {
    // ...
    byte[] getImageData() {
        return imageData_;
    }

    int getVersion() {
        return version_;
    }
    // ...
}

Image objects could be serialized using the following protobuf message:

message ImageMsg {
    required int32 version = 1;
    required bytes imageData = 2;
}

The protobuf compiler will generate Java and C++ classes from this definition. From Java you serialize an Image as an ImageMsg object:

Image img;
// ...
ImageMsg.Builder msg = ImageMsg.newBuilder();
msg.setVersion(img.getVersion());
msg.setImageData(img.getImageData());
// The output stream could point to a file, socket, pipe or something else.
msg.writeTo(someOutputStream);

On the C++ side, read back the object from the stream:

std::istream* is;
// initialize istream

ImageMsg msg;    
msg.ParseFromIstream(istream);
Image img(msg.getVersion(), msg.getImageData());

It is also possible to do the reverse, i.e, send the image object from C++ to Java.

Vijay Mathew
That is a good idea for structures, but it doesn't seem like it can handle images.
Matthieu
@Matthieu Of course it can handle images, if the image is contained in a byte buffer within the structure.
Vijay Mathew
Yes well I don't see the point of using that then, I can transmit a byte buffer via a Socket easily. What I'm looking for is what do I put in this byte buffer.
Matthieu
@Matthieu I have extended the answer to show how you can transfer a Java object directly to C++.
Vijay Mathew