I am trying to pass a numpy array to a customized C++ extension but somehow I got a segmentation fault. Here I made a simplified version of my code.
On the C++ side, I simply parse a bytes object using "s#", copy the data into an opencv Mat then write it into a png file:
#include <Python.h>
#include <iostream>
#include <memory>
#include <opencv2/opencv.hpp>
static PyObject* renderer_savePNG(PyObject *self,PyObject *args,PyObject *keywds)
{
const char *tex;
int buf_size;
int texSize=256;
static char *kwlist[]={"tex",NULL};
if(!PyArg_ParseTupleAndKeywords(args,keywds,"s#",kwlist,&tex,&buf_size)){
assert(buf_size==tex_size*tex_size*3);
std::cout<<"Parse failed"<<std::endl;
return NULL;
}
cv::Mat texRGB;texRGB.create(texSize,texSize,CV_8UC3);
memcpy(texRGB.data,tex,texSize*texSize*3*sizeof(char));
cv::Mat texBGR; cv::cvtColor(texRGB,texBGR,CV_RGB2BGR);
cv::imwrite("test.png",texBGR);
Py_RETURN_NONE;
}
static PyMethodDef eglrendererMethods[]={
{"save_png",(PyCFunction)renderer_savePNG,METH_VARARGS|METH_KEYWORDS,"save png"},
{NULL,NULL,0,NULL}
};
static struct PyModuleDef eglrenderer_module={
PyModuleDef_HEAD_INIT,
"eglrenderer",
NULL,-1,
eglrendererMethods
};
extern "C"{
PyMODINIT_FUNC PyInit_eglrenderer()
{
return PyModule_Create(&eglrenderer_module);
}
};
On the python side, I first read an image, convert it to a numpy array then convert to a bytes object.
from PIL import Image
import numpy as np
import eglrenderer
tex_size=256
tex=Image.open("tex.png")
tex=tex.resize((tex_size,tex_size))
tex=np.array(tex).tostring()
eglrenderer.save_png(tex=tex)
I am able to build and install this module using distutils without any problems. But when I run it, I got "Segmentation fault (core dumped)". When I built the extesion with "-ggdb" and tried to debug with gdb, it breaks at the following line:
Thread 1 "python" received signal SIGSEGV, Segmentation fault.
0x00007fffe6f37fcb in cv::cvtColor(cv::_InputArray const&, cv::_OutputArray const&, int, int) () from /usr/lib/x86_64-linux-gnu/libopencv_imgproc.so.2.4
(gdb) up
#1 0x00007fffe969acad in renderer_savePNG (self=<optimized out>, args=<optimized out>, keywds=<optimized out>) at renderer.cpp:61
61 cv::Mat texBGR; cv::cvtColor(texRGB,texBGR,CV_RGB2BGR);
(gdb)
However if this is a subtle memory issue, this error message from gdb might not be informative.
What is the problem with this code? Any idea how to find the problem? Also what are the best practices of passing a bytes array into C extension module? Any suggestion is appreciated. Thanks!