8

Is there a way to share memory to share an openCV image (MAT in C+++ and numpy in python) image between a C/C++ and python? Multiplataform is not needed, I'm doing it in linux, I've thought share between mmap or similar think.

I have two running processes one is written in C and the other is python, and I need to share an image between them.

I will call from the c process to python via socket but I need to send and image and via memory.

Another alternative could be write in memory file, not sure if it could be more time consuming.

1
  • You could stream the frames locally. Commented Oct 7, 2017 at 11:43

2 Answers 2

3

OK, this is not exactly a memory sharing in its real sense. What you want is IPC to send image data from one process to another.

I suggestthat you use Unix named pipes. You will have to get the raw data in a string format in C/C++, send it through pipe or Unix socket to Python and there get a numpy array from the sent data. Perhaps using np.fromstring() function.

Do not worry about the speed, pipes are pretty fast. Local and Unix sockets as well. Most time will be lost on getting the string representation and turning it back to matrix.

There is a possibility that you can create real shared memory space and get the data from OpenCV in C/C++ directly into Python, and then use OpenCV in Python to get out numpy array, but it would be complicated. If you don't need speed of light your best bet are named pipes.

Sign up to request clarification or add additional context in comments.

10 Comments

Thanks, Yes I mean IPC. I think that convert to HEXASCII could be hi time consuming process, if nothing better it could be a solution, write to a in memory file (over tmpfs) could be another.
No, no, not HEXASCII, for heaven's sake! This would be terrible. Don't even think about it. Just nice clean binary data. 3 octets per RGB pixel. To get the correct matrix on the other side you just have to know the original image's dimensions. There are functions in OpenCV and any other imaging libraries letting you get the binary string out of its object. In C, if you have multidimensional array you can just cast it to char. Depends, of course, how colours are stored, but essentially it is cast and serialize.
Do: import numpy; help(numpy.fromstring) to see what fromstring() does. It is similar to struct.unpack() and array.array(). Named pipes can transmit infinite data streams. Null termination doesn't fit in that story. You can send "\0" without a problem through a pipe or socket. Null termination applies only to ASCII strings in C and it tells string manipulating functions where the end is. So that they don't have to get string's length. For all other purposes "\0" is just another valid byte stored in memory.
Excellent! But if using sockets, you should use Unix sockets instead. Unless you are planning to distribute your processes over the network. Unix sockets are fastest of their kind. All tests say that named pipes are faster than even unix sockets but I cannot confirm nor deny it. Definitely the fastest IPC method is shared memory. But you would get yourself in a lot of complications to set it up. Even if you don't plan to share internal opencv buffer (which would be a complete mess and you would lose a lot of time trying it), but use tostring() and fromstring() on shared memory.
In this case you would need a mechanism to tell you that another buffer is waiting for you in shared memory to pick up. Using socket or pipe solves this quite nicely. You can even put your socket in non-blocking mode and use select.select() to check whether you should do any reading or not. One disadvantage of named pipe (from practical point of view) is that it is one-way communication. But I think you don't need two-way com. anyway so it is all same to you. In your place, I would stick to sockets, but use Unix sockets instead. You don't have to change much the code.
|
0

It's not exactly what you're asking for, but you can use an in-memory database such as Redis as a conduit for exchanging OpenCV images between your programs. Though less direct than raw memory mapping, and while it introduces an additional application layer, the data is still manipulated strictly in RAM. In my experience, this tactic is fast enough to be near-realtime on a modern machine.

I've used such architecture for https://github.com/vmlaker/hello-websocket, albeit it uses Python at both ends.

Here's a minimalistic example of a similar protocol implementing the source in C++, and Python for the target application. The following C++ program reads an image from a file on disk using OpenCV, and stores the image in Redis under the key image:

#include <opencv4/opencv2/opencv.hpp>
#include <cpp_redis/cpp_redis>

int main(int argc, char** argv)
{
  cv::Mat image = cv::imread("input.jpg");
  std::vector<uchar> buf;
  cv::imencode(".jpg", image, buf);

  cpp_redis::client client;
  client.connect();
  client.set("image", {buf.begin(), buf.end()});
  client.sync_commit();
}

Then in Python you grab the image from the database and do what you will:

import cv2
import numpy as np
import redis

store = redis.Redis()
image = store.get('image')
array = np.frombuffer(image, np.uint8)
decoded = cv2.imdecode(array, flags=1)
cv2.imshow('hello', decoded)
cv2.waitKey()

Going the other way is pretty straightforward. You can get cpp_redis here: https://github.com/cpp-redis/cpp_redis.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.