What is the easiest way to convert ndarray into cv::Mat?

前端 未结 5 1568
悲&欢浪女
悲&欢浪女 2020-12-05 12:31

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

5条回答
  •  陌清茗
    陌清茗 (楼主)
    2020-12-05 12:54

    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:

    1. Create empty cv::Mat of corresponding size and type.
    2. Copy data.

    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.

提交回复
热议问题