I\'m trying to create Python/Cython wrapper for C++ library that uses cv::Mat class from OpenCV. In official Python wrapper all functions take
It turns out that there's no simple way to convert (any) np.ndarray into corresponding cv::Mat. Basically, one needs to do only 2 things:
cv::Mat of corresponding size and type.However, devil hides in details. Both ndarray and Mat may hold quite varying data formats. For instance, data in NumPy arrays may be in C or in Fortran order, array object may own its data or keep a view to another array, channels may go in a different order (RGB in NumPy vs. BGR in OpenCV), etc.
So instead of trying to solve generic problem I decided to stay with simple code that fits my needs and may be easily modified by anyone interested.
Following code in Cython works with float32/CV_32FC1 images with default byte order:
cdef void array2mat(np.ndarray arr, Mat& mat):
cdef int r = arr.shape[0]
cdef int c = arr.shape[1]
cdef int mat_type = CV_32FC1 # or CV_64FC1, or CV_8UC3, or whatever
mat.create(r, c, mat_type)
cdef unsigned int px_size = 4 # 8 for single-channel double image or
# 1*3 for three-channel uint8 image
memcpy(mat.data, arr.data, r*c*px_size)
To use this code in Cython one also needs to declare some types and constants, e.g. like this:
import numpy as np
# Cython makes it simple to import NumPy
cimport numpy as np
# OpenCV's matrix class
cdef extern from "opencv2/opencv.hpp" namespace "cv":
cdef cppclass Mat:
Mat() except +
Mat(int, int, int, void*) except +
void create(int, int, int)
void* data
int type() const
int cols
int rows
int channels()
Mat clone() const
# some OpenCV matrix types
cdef extern from "opencv2/opencv.hpp":
cdef int CV_8UC3
cdef int CV_8UC1
cdef int CV_32FC1
cdef int CV_64FC1
Opposite conversion (from cv::Mat to np.ndarray) may be achieved in a similar way.
Bonus: there's also nice blog post describing same kind of conversion for RGB/BGR images.