我正在尝试将numpy数组传递给自定义的C ++扩展,但是不知何故出现了分段错误。在这里,我简化了代码。
在C ++方面,我只是使用“ s#”解析一个字节对象,将数据复制到opencv Mat中,然后将其写入png文件:
#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);
}
};
在python端,我首先读取图像,将其转换为numpy数组,然后转换为bytes对象。
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)
我能够使用distutils构建和安装此模块,而不会出现任何问题。但是,当我运行它时,出现了“分段错误(核心已转储)”。当我使用“ -ggdb”构建扩展并尝试使用gdb进行调试时,它在以下行中断:
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)
但是,如果这是一个细微的内存问题,则来自gdb的此错误消息可能不会提供信息。
此代码有什么问题?任何想法如何找到问题?另外,将字节数组传递到C扩展模块的最佳实践是什么?任何建议表示赞赏。谢谢!