Calling OpenCV functions via Cython from Python 3.X.
I have managed to run OpenCV function from Python3 via Cython today, so I want to write about it.
Before you start something like this, you should know you have to read at least header files of C library
to write right definition in Cython,because Cython does not do that for you.
I am using virtualenv, python from pythonz, and home-brewed OpenCV.
Almost everything of C++ works just fine with Cython, but still, you should do some Voodoo things like for integer
template argument.
---------
update: Mar 3 '14 <unsinged int> was missing. Thank you, Andrey.
ctypedef void* int_parameter ctypedef int_parameter two "2" ctypedef Point_[float, two] Point2fNow, main sample Cython code is following.
#===== testopencv.pyx ======== import numpy as np cimport numpy as np # for np.ndarray from libcpp.string cimport string from libc.string cimport memcpy cdef extern from "opencv2/core/core.hpp": cdef int CV_WINDOW_AUTOSIZE cdef int CV_8UC3 cdef extern from "opencv2/core/core.hpp" namespace "cv": cdef cppclass Mat: Mat() except + void create(int, int, int) void* data cdef extern from "opencv2/highgui/highgui.hpp" namespace "cv": void namedWindow(const string, int flag) void imshow(const string, Mat) int waitKey(int delay) cdef void ary2cvMat(np.ndarray ary, Mat& out): assert(ary.ndim==3 and ary.shape[2]==3, "ASSERT::3channel RGB only!!") ary = np.dstack((ary[...,2], ary[...,1], ary[...,0])) #RGB -> BGR cdef np.ndarray[np.uint8_t, ndim=3, mode = 'c'] np_buff = np.ascontiguousarray(ary, dtype = np.uint8) cdef unsigned int* im_buff = <unsigned int*> np_buff.data cdef int r = ary.shape[0] cdef int c = ary.shape[1] out.create(r, c, CV_8UC3) memcpy(out.data, im_buff, r*c*3) cdef showMat(Mat m): namedWindow( "WIN", CV_WINDOW_AUTOSIZE ) imshow( "WIN", m ) waitKey(0) def openImage(pil_img): cdef Mat m ary2cvMat(np.array(pil_img), m) showMat(m)The last function openImage(pil_image) will open pil_image in different window. (I know you can do this without OpenCV. Just for a sample.) This sample changes pil_image to numpy array and then convert it to OpenCV's cv::Mat. To compile this, you need a setup file like this.
#======== setup.py =========== from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext from Cython.Build import cythonize import numpy import subprocess proc_libs = subprocess.check_output("pkg-config --libs opencv".split()) proc_incs = subprocess.check_output("pkg-config --cflags opencv".split()) libs = [lib for lib in str(proc_libs, "utf-8").split()] #print("OPENCV LIBS=", libs) setup( cmdclass = {'build_ext': build_ext}, ext_modules = cythonize(Extension("opencvsample", sources = ["opencvsample.pyx"], language = "c++", include_dirs=[numpy.get_include(), "/usr/local/Cellar/opencv/2.4.5/include/"], extra_link_args=libs ) ) )To compile and execute, you should do
python setup.py build_ext --inplace python -c "import testopencv as to; from PIL import Image; to.openImage(Image.open('test.jpg'))"I spent several days to work this all through, so I hope this might be helpful to somebody. Feedbacks are always appreciated.
---------
update: Mar 3 '14 <unsinged int> was missing. Thank you, Andrey.
Comments
testopencv.pyx:28:38: Cannot assign type 'char *' to 'unsigned int *'
at:
cdef unsigned int* im_buff = np_buff.data
Do you know how I can fix this error?
The correct code should be
cdef unsigned int* im_buff = <unsigned int*> np_buff.data
<...> was omitted by tag-thing. I'll fix it.
Thanks for the comment!