I am trying to send an image from Python program that returns ndarray
to C++ (OpenCV Mat
) in the simple way: saving image to the buffer and then passing the buffer contents as string to C++ and using cv::imdecode
there.
The error is thrown in c++ by cv::imshow
:
OpenCV Error: Assertion failed (size.width>0 && size.height>0) in imshow,
file /home/hcl/opencv-3.1.0/modules/highgui/src/window.cpp, line 281
terminate called after throwing an instance of 'cv::Exception'
what(): /home/hcl/opencv-3.1.0/modules/highgui/src/window.cpp:281:
error: (-215) size.width>0 && size.height>0 in function imshow
Aborted (core dumped)
EDIT: it works.
Before this I've read a number of approaches of sending ndarray
from Python to C++ here on StackOverflow and didn't manage them to work. Also I checked two advised converters on Github (1,2), but unfortunately they are incompatible with OpenCV 3. Being unable to troubleshoot problems, I wish to make it working just in this simplest possible way to avoid possible porting problems in the future.
Python script that returns image(imgread.py
):
import scipy.misc
import click as _click
import base64
from io import BytesIO
def get_my_image(image_name):
# using click package to make sure that path is interpreted correctly
_click.command()
_click.argument('image_name',type=_click.Path(exists=True,
dir_okay=True, readable=True))
# just reading some image (ndarray format is essential)
image = scipy.misc.imread(image_name)
# processing data ....
# sending it back-----------------------------------
# I've heard that scipy version started to normalize all images,
# but at the moment I just want to start it working
img_to_send = scipy.misc.toimage(image)
# https://stackoverflow.com/questions/31826335/
# how-to-convert-pil-image-image-object-to-base64-string
# preparing buffer and writing image to it
mybuffer = BytesIO()
img_to_send.save(mybuffer, format="JPEG")
# converting buffer contents to string
img_str = base64.b64encode(mybuffer.getvalue())
return(img_str)
The original working *.cpp example is here and I have only changed the part that corresponds to processing the data.
Main C++ program : (EDITED. base64 conversion code taken from here)
// call_function.c - A sample of calling
// python functions from C code
// original code from
// https://stackoverflow.com/questions/215752/
// python-embedded-in-cpp-how-to-get-data-back-to-cpp
#include <Python.h>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
#include <iostream>
#include <string>
#include "base64.cpp"
using namespace cv;
using namespace std;
int
main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pArg, *pResult;
int i;
Py_Initialize();
pName = PyString_FromString("imgread");
// (no .py, error "ImportError: No module named py" otherwise)
/* Error checking of pName left out as exercise */
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, "get_my_image");
/* pFunc is a new reference */
if (pFunc) {
pArgs = PyTuple_New(1);
pArg = PyString_FromString("1.jpg");
/* pArg reference stolen here: */
PyTuple_SetItem(pArgs, 0, pArg);
pResult = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pResult != NULL) {
//------------------------------- my part
// see https://stackoverflow.com/questions/14727267/
// opencv-read-jpeg-image-from-buffer
char* str = PyString_AsString(pResult);
// converting back from base64
const std::string base64_chars = string(str);
string s = base64_decode(base64_chars);
char* str3 = (char*)s.c_str();
//taking NULLs into account and using s.size()
size_t len = s.size();
uchar* str2 = reinterpret_cast<unsigned char*>(str3);
//attempting to display the image
Mat rawData(1, len*sizeof(uchar), CV_8UC1, str2);
Mat decodedImage = imdecode(rawData,CV_LOAD_IMAGE_COLOR);
imshow( "Display window", decodedImage );
//-------------------------------
Py_DECREF(pResult);
}
else {
Py_DECREF(pFunc);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr,"Call failed\n");
return 1;
}
}
else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function");
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load module");
return 1;
}
Py_Finalize();
waitKey(0);
return 0;
}
EDIT: To get rid of normalization performed by scipy.misc.toimage
I try to use img_to_send = scipy.misc.toimage(image,high=np.max(image), low=np.min(image))
, but I don't know whether it works as intended or not.