Not able to convert Numpy array to OpenCV Mat in Cython when trying to write c++ wrapper function (Updated)

匿名 (未验证) 提交于 2019-12-03 08:57:35

问题:

I am trying to implement cv::cuda::warpPerspective in python2, there is a very sweet post about how to do that here: link. I followed the instruction as described in that post, however, I got Segmentation fault (core dumped) error.

I was able to allocate the error in GpuWrapper.pyx file line 11:

pyopencv_to(<PyObject*> _src, src_mat) 

It seems that it fails to convert numpy array to opencv Mat.

I am not sure where is wrong and how to fix it.

The python script that got Segmentation fault (core dumped) error is in below:

import cv2 import numpy as np import csv import timeit import GpuWrapper  while (1):     start = timeit.default_timer()     eo_img = cv2.imread('./sample/eo.png', 1)     nir_img = cv2.imread('./sample/nir.png', 0)     with open('./sample/reg.csv', 'rb') as f:         line = csv.reader(f)         reg_line = list(line)     reg = np.array(reg_line[0], dtype=np.float32)     new_reg = reg.reshape((3,3))     print nir_img.shape     dist = GpuWrapper.cudaWarpPerspectiveWrapper(nir_img, new_reg, (2448,2048))     cv2.imwrite('./sample/result.png', dist)     end = timeit.default_timer()     print end-start 

Another thing to mention, when compiling cython code, it has some warnings:

[1/1] Cythonizing GpuWrapper.pyx running build_ext building 'GpuWrapper' extension x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -Wdate-time -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security -fPIC -I/home/xinyao/Tensorflow/local/lib/python2.7/site-packages/numpy/core/include -I-I/usr/local/include/opencv -I-I/usr/local/include -I/usr/include/python2.7 -c GpuWrapper.cpp -o build/temp.linux-x86_64-2.7/GpuWrapper.o cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++ In file included from /home/xinyao/Tensorflow/local/lib/python2.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1809:0,                  from /home/xinyao/Tensorflow/local/lib/python2.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:18,                  from pyopencv_converter.cpp:2,                  from GpuWrapper.cpp:544: /home/xinyao/Tensorflow/local/lib/python2.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:15:2: warning: #warning "Using deprecated NumPy API, disable it by " "#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION" [-Wcpp]  #warning "Using deprecated NumPy API, disable it by " \   ^ c++ -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -Wdate-time -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security -Wl,-Bsymbolic-functions -Wl,-z,relro -Wdate-time -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security build/temp.linux-x86_64-2.7/GpuWrapper.o -o /home/xinyao/projects/image_reg/GpuWrapper.so -L/usr/local/lib -lopencv_cudabgsegm -lopencv_cudaobjdetect -lopencv_cudastereo -lopencv_dnn -lopencv_ml -lopencv_shape -lopencv_stitching -lopencv_cudafeatures2d -lopencv_superres -lopencv_cudacodec -lopencv_videostab -lopencv_cudaoptflow -lopencv_cudalegacy -lopencv_calib3d -lopencv_features2d -lopencv_highgui -lopencv_videoio -lopencv_photo -lopencv_imgcodecs -lopencv_cudawarping -lopencv_cudaimgproc -lopencv_cudafilters -lopencv_video -lopencv_objdetect -lopencv_imgproc -lopencv_flann -lopencv_cudaarithm -lopencv_viz -lopencv_core -lopencv_cudev 

Which seems to be fine according to here.

Environment: CUDA 8.0 OpenCV 3.3 without extra modules Ubuntu 16.04 Python 2.7 Cython 0.26

I have tried cv::cuda::warpPerspective in C++ and it works fine with GPU support. I have also tried cv2.warpPerspective in python and without any issue(so my opencv for python was compiled correctly).

Another thing is I cannot compile opencv C++ code directly with g++, I need to add extra flags to do it, like in this way: g++ -o main main.cc `pkg-config opencv --cflags --libs Otherwise I will have issues on finding opencv:

main.cc:(.text+0x45): undefined reference to `cv::cuda::GpuMat::defaultAllocator()' main.cc:(.text+0x9b): undefined reference to `cv::imread(cv::String const&, int)' main.cc:(.text+0x104): undefined reference to `cv::imread(cv::String const&, int)' main.cc:(.text+0x140): undefined reference to `cv::cuda::GpuMat::defaultAllocator()' main.cc:(.text+0x1a5): undefined reference to `cv::Mat::eye(int, int, int)' main.cc:(.text+0x31f): undefined reference to `cv::cuda::Stream::Null()' main.cc:(.text+0x3d6): undefined reference to `cv::cuda::warpPerspective(cv::_InputArray const&, cv::_OutputArray const&, cv::_InputArray const&, cv::Size_<int>, int, int, cv::Scalar_<double>, cv::cuda::Stream&)' main.cc:(.text+0x487): undefined reference to `cv::imwrite(cv::String const&, cv::_InputArray const&, std::vector<int, std::allocator<int> > const&)' 

Not sure if that is a factor, but I am not able to fix it as well.

Any help will be really appreciated.

UPDATE: I was able to allocate the bug by using pdb:

>$gdb --args python opencv_reg_cuda.py >$run      Starting program: /usr/bin/python opencv_reg_cuda.py     [Thread debugging using libthread_db enabled]     Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".     [New Thread 0x7fffc6b83700 (LWP 10933)]     [New Thread 0x7fffc4382700 (LWP 10934)]     [New Thread 0x7fffc1b81700 (LWP 10935)]     [New Thread 0x7fffc1380700 (LWP 10936)]     [New Thread 0x7fffbcb7f700 (LWP 10937)]     [New Thread 0x7fffba37e700 (LWP 10938)]     [New Thread 0x7fffb7b7d700 (LWP 10939)]     (2048, 2448)      Thread 1 "python" received signal SIGSEGV, Segmentation fault.     pyopencv_to (o=o@entry=0x7fffb37e3b70, m=..., info=...) at pyopencv_converter.cpp:210     210     if( !PyArray_Check(o) )  >$bt      #0  pyopencv_to (o=o@entry=0x7fffb37e3b70, m=..., info=...) at pyopencv_converter.cpp:210     #1  0x00007fffb33c56f5 in pyopencv_to<cv::Mat> (name=0x7fffb33c98d8 "<unknown>", m=..., o=0x7fffb37e3b70) at pyopencv_converter.cpp:349     #2  __pyx_pf_10GpuWrapper_cudaWarpPerspectiveWrapper (__pyx_v(short, long double, char)=__pyx_v(short, long double, char)@entry=0x7fffb37e3b70, __pyx_v__M=__pyx_v__M@entry=0x7fffb37e3c60,          __pyx_v__size_tuple=__pyx_v__size_tuple@entry=0x7ffff7e80b90, __pyx_v__flags=<optimized out>, __pyx_self=<optimized out>) at GpuWrapper.cpp:1796     #3  0x00007fffb33c76a2 in __pyx_pw_10GpuWrapper_1cudaWarpPerspectiveWrapper (__pyx_self=<optimized out>, __pyx_args=<optimized out>, __pyx_kwds=<optimized out>) at GpuWrapper.cpp:1737     #4  0x00000000004c468a in PyEval_EvalFrameEx ()     #5  0x00000000004c2765 in PyEval_EvalCodeEx ()     #6  0x00000000004c2509 in PyEval_EvalCode ()     #7  0x00000000004f1def in ?? ()     #8  0x00000000004ec652 in PyRun_FileExFlags ()     #9  0x00000000004eae31 in PyRun_SimpleFileExFlags ()     #10 0x000000000049e14a in Py_Main ()     #11 0x00007ffff7810830 in __libc_start_main (main=0x49dab0 <main>, argc=2, argv=0x7fffffffde38, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffde28)         at ../csu/libc-start.c:291     #12 0x000000000049d9d9 in _start ()  >list      205             }     206         }     207         return true;     208     }     209      210     if( !PyArray_Check(o) )     211     {     212         failmsg("%s is not a numpy array, neither a scalar", info.name);     213         return false;     214     } 

It seems like it cannot pass o to PyArray_Check, but I have no idea what was going on and how to fix it.

回答1:

Finally I found the answer. In order to use numpy, we have to call numpy.import_array(). For detail, see Here.

It can be tricky to find where to call it, for my case, I just call in my .pyx script:

import numpy as np  # Import Python functions, attributes, submodules of numpy cimport numpy as np  # Import numpy C/C++ API  np.import_array()  def cudaWarpPerspectiveWrapper(np.ndarray[np.uint8_t, ndim=2] _src,                                np.ndarray[np.float32_t, ndim=2] _M,                                _size_tuple,                                int _flags=INTER_NEAREST):     # Create GPU/device InputArray for src      cdef Mat src_mat     cdef GpuMat src_gpu     pyopencv_to(<PyObject*> _src, src_mat)     src_gpu.upload(src_mat)      # Create CPU/host InputArray for M     cdef Mat M_mat = Mat()     pyopencv_to(<PyObject*> _M, M_mat)      # Create Size object from size tuple     # Note that size/shape in Python is handled in row-major-order -- therefore, width is [1] and height is [0]     cdef Size size = Size(<int> _size_tuple[0], <int> _size_tuple[1])      # Create empty GPU/device OutputArray for dst     cdef GpuMat dst_gpu = GpuMat()     warpPerspective(src_gpu, dst_gpu, M_mat, size, 2)      # Get result of dst     cdef Mat dst_host     dst_gpu.download(dst_host)     cdef np.ndarray out = <np.ndarray> pyopencv_from(dst_host)     return out 

Then everything is working like a magic.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!