2012-04-25 71 views
3

每当我用ctypes将共享库(.so)加载到Python中并调用其中一个使用OpenCV过滤器引擎的过程(如cvErode或cvDilate)时,解释器段错误深入OpenCV代码。 如果我在C程序中加载与dlopen相同的库,并调用相同的过程,一切正常。在共享库中调用opencv通过python ctypes使用时的段错误

我读过另一篇文章,它可能与gcc使用的ABI有关,python必须使用与编译python解释器的gcc相同版本进行编译才能正常工作。但在我的情况下,它都是4.4.5,所以这不应该是一个问题。 OpenCV库也用相同版本的gcc编译。

如何共享库建:

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 

如何共享库被包裹:

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); 

    //drawDebugLines(rows, cols, width, height); 

    vector<Box> boxes = createBoxes(rows,cols,width,height); 
    //printBoxes(boxes); 
    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; 
} 

} // C 

如何共享库的程序被加载在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") # this segfaults 

GDB输出:

$ 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://gnu.org/licenses/gpl.html> 
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://www.gnu.org/software/gdb/bugs/>... 
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 ++版本:

$ 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的是2.3.1版和使用该版本的gcc从源建(4.4.5-8)

+1

你确实知道,有OpenCV的Python绑定? http://code.google.com/p/pyopencv/ – vartec 2012-04-25 14:07:39

+0

是的,但我宁愿为了速度的原因而在c/C++中执行所有图像处理。并非全部都是在OpenCV内部完成的。 – Rolf 2012-04-25 15:00:25

+0

如果你编写一个C程序来加载和使用你的库,你会知道这个问题是在你的OpenCV代码中,还是在用Python加载库的代码中。 – karlphillip 2012-04-25 15:00:38

回答

0

我找到解决方案。对于SSE指令,堆栈需要重新排列为16个字节。如果我使用-mstackrealign构建共享库,它将完美加载并从python调用。

Qt, GCC, SSE and stack alignment