0

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.

5
  • 1
    I don't see you decoding the base64 on the c++ side. Commented Nov 3, 2016 at 17:51
  • @DanMašek Fixed, the error is still the same and the out.jpg is 4 bytes (was ~ half-size of the original) Commented Nov 3, 2016 at 18:15
  • 2
    strlen(str3); This will treat it as a c-string, with NULL byte acting as a terminator. You definitely don't want that, as the JPEG data is bound to contain many NULL bytes -- it's a binary format. You should use s.size() to get the correct length. Commented Nov 3, 2016 at 18:31
  • @DanMašek I fixed the main part (except cout that still writes 4 bytes), now I get additional error before OpenCV exception: Corrupt JPEG data: 423 extraneous bytes before marker 0xfe. Commented Nov 3, 2016 at 18:45
  • @DanMašek Oops, looks like I a bit overdid with that. Now everything works at last! Thank you very much! Commented Nov 3, 2016 at 18:49

0

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.