3

ctypes を使用して共有ライブラリ (.so) を Python にロードし、OpenCV フィルター エンジン (cvErode や cvDilate など) を使用するそのプロシージャの 1 つを呼び出すと、インタープリターは OpenCV コードの奥深くでセグメンテーション違反を起こします。C プログラム内で dlopen を使用して同じライブラリをロードし、同じプロシージャを呼び出すと、すべて正常に動作します。

別の投稿で、gcc が利用する ABI に関係している可能性があり、これを機能させるには、python インタープリターがコンパイルされたのと同じバージョンの gcc で python をコンパイルする必要があることを読みました。ただし、私の場合は両方とも 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) を使用してソースからビルドされました。

4

1 に答える 1

0

私は解決策を見つけました。SSE 命令では、スタックを 16 バイトに再調整する必要があります。-mstackrealign を使用して共有ライブラリをビルドすると、Python から完全に読み込まれて呼び出されます。

Qt、GCC、SSE、およびスタック アライメント

于 2012-04-29T20:32:45.520 に答える