Whenever I load a shared library (.so) in Python using ctypes and call one of the procedures that use the OpenCV filtering mechanism (e.g. cvErode or cvDilate), the segfaults interpreter is deep inside OpenCV code. If I load the same library with dlopen inside a C program and call the same procedure, everything works fine.
I read in another post that this could be related to the ABI that gcc uses, and that python must be compiled with the same gcc version that the python interpreter was compiled for it to work. However, in my case it is like 4.4.5, so this should not be a problem. OpenCV libraries have also been compiled with the same version of gcc.
How to create a shared library:
g++ -g -shared -lopencv_core -lopencv_imgproc -lopencv_calib3d -lopencv_video -lopencv_features2d -lopencv_ml -lopencv_highgui -lopencv_objdetect -lopencv_contrib -lopencv_legacy -o thumbsplit.so thumbsplit.cpp
How the shared library is exchanged:
extern "C" {
int is_thumbsheet(char * image_path){
Image image;
image.read(image_path);
int width = image.columns();
int height = image.rows();
int BOUND_CHANGE = 7000;
int test_height = 0;
if( width > height ){
return 0;
}else{
test_height = width;
}
vector<int> test_rows = getRows(image, width, test_height, BOUND_CHANGE);
vector<int> test_cols = getCols(image, width, test_height, BOUND_CHANGE);
vector<Box> test_boxes = createBoxes(test_rows,test_cols,width,height);
if( test_boxes.size() > 6 ){
return 1;
}else{
return 0;
}
}
int cut_thumbs(char * image_path, char * thumb_path){
Image image;
image.read(image_path);
int width = image.columns();
int height = image.rows();
int BOUND_CHANGE = 7000;
vector<int> rows = getRows(image, width, height, BOUND_CHANGE);
vector<int> cols = getCols(image, width, height, BOUND_CHANGE);
vector<Box> boxes = createBoxes(rows,cols,width,height);
char path[0x100];
for( int i=0 ; i < boxes.size() ; i++ ){
sprintf(path, "%s%d.jpg", thumb_path, i);
boxes[i].saveBox(image, path);
}
return 0;
}
}
How are shared library routines loaded in python:
import ctypes, os
def load_lib():
lib_path = "%s/%s"%(os.path.realpath(os.path.dirname(__file__)), "thumbsplit.so")
lib = ctypes.CDLL(lib_path)
return lib
def is_thumbsheet(image_path):
lib = load_lib()
if lib.is_thumbsheet(image_path):
return True
else:
return False
def cut_thumbs(image_path, thumbs_path):
lib = load_lib()
lib.cut_thumbs(image_path, thumbs_path)
is_thumbsheet("/home/rolf/test/imageproc/full9.jpg")
GDB Output:
$ gdb python
GNU gdb (GDB) 7.0.1-debian
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http:
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http:
Reading symbols from /usr/bin/python...(no debugging symbols found)...done.
(gdb) run thumbsheet.py
Starting program: /usr/bin/python thumbsheet.py
[Thread debugging using libthread_db enabled]
0xb6330a12
Program received signal SIGSEGV, Segmentation fault.
0xb76fe2dc in cv::FilterEngine::start(cv::Size_<int>, cv::Rect_<int>, int) () from /usr/local/lib/libopencv_imgproc.so.2.3
(gdb) info stack
#0 0xb76fe2dc in cv::FilterEngine::start(cv::Size_<int>, cv::Rect_<int>, int) () from /usr/local/lib/libopencv_imgproc.so.2.3
#1 0xb76feb41 in cv::FilterEngine::start(cv::Mat const&, cv::Rect_<int> const&, bool, int) ()
from /usr/local/lib/libopencv_imgproc.so.2.3
#2 0xb770a52b in cv::FilterEngine::apply(cv::Mat const&, cv::Mat&, cv::Rect_<int> const&, cv::Point_<int>, bool) ()
from /usr/local/lib/libopencv_imgproc.so.2.3
#3 0xb764bf8a in cv::morphOp(int, cv::_InputArray const&, cv::_OutputArray const&, cv::_InputArray const&, cv::Point_<int>, int, int, cv::Scalar_<double> const&) () from /usr/local/lib/libopencv_imgproc.so.2.3
#4 0xb764d2ce in cv::erode(cv::_InputArray const&, cv::_OutputArray const&, cv::_InputArray const&, cv::Point_<int>, int, int, cv::Scalar_<double> const&) () from /usr/local/lib/libopencv_imgproc.so.2.3
#5 0xb764d62e in cvErode () from /usr/local/lib/libopencv_imgproc.so.2.3
#6 0xb7fd7adb in seperate::findSeperatedBoxes (img=0x8351d70) at seperate.cpp:189
#7 0xb7fd7fcf in seperate::trySeperatedBoxes (img=0x8351d70, percentage_boxed=0xbfffefec) at seperate.cpp:202
#8 0xb7fda00c in is_thumbsheet (image_path=0xb7c1bf74 "/home/rolf/test/imageproc/full9.jpg") at thumbsplit.cpp:39
#9 0xb7a047df in ffi_call_SYSV () from /usr/lib/python2.6/lib-dynload/_ctypes.so
#10 0xb7a0461e in ffi_call () from /usr/lib/python2.6/lib-dynload/_ctypes.so
#11 0xb79ff27d in _CallProc () from /usr/lib/python2.6/lib-dynload/_ctypes.so
#12 0xb79f6d7e in ?? () from /usr/lib/python2.6/lib-dynload/_ctypes.so
#13 0x0806232a in PyObject_Call ()
#14 0x080e016b in PyEval_EvalFrameEx ()
#15 0x080e18b0 in PyEval_EvalFrameEx ()
#16 0x080e2507 in PyEval_EvalCodeEx ()
#17 0x080e2607 in PyEval_EvalCode ()
#18 0x080ffcbd in PyRun_FileExFlags ()
#19 0x080fff22 in PyRun_SimpleFileExFlags ()
#20 0x0805dd81 in Py_Main ()
#21 0x0805cf6b in main ()
(gdb) x/i 0xb76fe2dc
0xb76fe2dc <_ZN2cv12FilterEngine5startENS_5Size_IiEENS_5Rect_IiEEi+1212>: movdqa %xmm3,0x30(%esp)
(gdb)
GCC / g ++ version:
$ python
Python 2.6.6 (r266:84292, Dec 27 2010, 00:02:40)
[GCC 4.4.5] on linux2
$ gcc --version
gcc (Debian 4.4.5-8) 4.4.5
$ g++ --version
g++ (Debian 4.4.5-8) 4.4.5
OpenCV is version 2.3.1 and was built from the source using this version of gcc (4.4.5-8)