I exported a DLL function that returns a char* array. The Python code calls the function and converts the bytes into a 2D numpy array, and back again to bytes:
Input image:
Windows code:
#include <opencv2/opencv.hpp>
using namespace cv;
#pragma comment(lib, "opencv_world331.lib")
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <mutex>
using namespace std;
#define DLLEXPORT extern "C" __declspec(dllexport)
map<size_t, char*> ids;
mutex rw_ids;
DLLEXPORT int get_img_from_char_array(char *c, int *width, int *height)
{
Mat frame_content(*height, *width, CV_8UC1, c);
return 0;
}
DLLEXPORT char *alloc_img(const char *file_name, int *width, int *height, size_t *image_id)
{
rw_ids.lock();
Mat img = imread(file_name, IMREAD_GRAYSCALE);
if (img.empty())
{
*width = 0;
*height = 0;
rw_ids.unlock();
return nullptr;
}
*width = img.cols;
*height = img.rows;
size_t num_pixels = (*width)*(*height);
char *p = new char[num_pixels];
memcpy(p, img.data, num_pixels*sizeof(char));
ids[ids.size()] = p;
*image_id = ids.size() - 1;
cout << "Created img id " << *image_id << endl;
rw_ids.unlock();
return p;
}
DLLEXPORT int free_img(size_t *image_id)
{
rw_ids.lock();
for (map<size_t, char*>::const_iterator ci = ids.begin(); ci != ids.end(); ci++)
{
if (ci->first == *image_id)
{
cout << "Deleted img id " << *image_id << endl;
if (nullptr != ci->second)
delete[] ci->second;
ids.erase(ci);
rw_ids.unlock();
return 0;
}
}
rw_ids.unlock();
return 1;
}
Python code:
import ctypes as ct
import numpy as np
import cv2
ptr = ct.c_char_p()
s = "dove.png"
width = ct.pointer(ct.c_int())
height = ct.pointer(ct.c_int())
img_id = ct.pointer(ct.c_size_t())
lib = ct.CDLL("void_dll.dll")
alloc_img = lib.alloc_img
free_img = lib.free_img
get_img_from_char_array = lib.get_img_from_char_array
alloc_img.restype = ct.c_char_p
bytes_array = alloc_img(ct.c_char_p(s.encode("utf-8")), width, height, img_id)
numpy_array = np.frombuffer(bytes_array, dtype=np.uint8)
numpy_array.shape = (width.contents.value, height.contents.value)
cppbytes = numpy_array.tobytes()
get_img_from_char_array(cppbytes, width, height);
free_img(img_id)
I also have some extra code handy, which uses a void** pointer to allocate memory:
int func(void **ptr)
{
float *p = new float[50];
p[0] = 123.456;
*ptr = p;
return 0;
}
int main(void)
{
float *p = 0;
func(reinterpret_cast<void**>(&p));
cout << p[0] << endl;
delete[] p;
return 0;
}
Is your C++ going into a DLL? Have you tried it just to see if it works, before you get into SWIG?
Yes, the c++ is a dll. In fact it is now a .pyd since I am using SWIG. I can pass the void* (image data is unsigned char in memory) to python. But I cannot seem to find a library to construct the data from memory (in terms of void* address) to create an image (given that from python, I know the rows and column of the image). I am still exploring how to do it using numpy/opencv/PILLOW.
Do you know how to do it without swig?
This code sets up a new Mat from a void* pointer (called ptr):
Does that help?
Thanks, but Mat is not available in cv2, right? I think I need a function in python (openCV or numpy or which ever image processing library that can create the image back from the block of memory (void * from c++).
I'm not sure what OpenCV 2.x's capabilities are. Sorry about that.
... so you're looking to pass the image data from C++ to Python, right?
Thanks. Yes, both ways from C++ to python (get image from c++ app, use the image in python to do some image processing and let the C++ app pick up the latest image data) and then from python back to C++.
So, if we use the Mat mechanism, how do we expose it to python to pick it up to do processing?
That's a good question, and I'm going to look into it. Do you have any source code that I can work from? I use GitHub for sharing code.
I am using python 3.6 for 64 bit. I haven't tried to build c++ dll with OpenCV yet. Actually, right now, my cpp code does not use opencv yet. I am still finding way to expose the data to python. Looks like there is a python buffer protocol that I can make use of... I still need to explore it... have you use it?
So far, I am using opencv on the python side to try to pick up the data from memory address... no luck so far...
sorry, my source code is linking all over the places...too much dependencies that will require a lot of time to set up... thanks though!
Do you have a working example of a void** parameter function?