Is opencv matrix data guaranteed to be continuous?

前端 未结 3 2184
臣服心动
臣服心动 2020-12-02 21:28

I know that, the data contained in an opencv matrix is not guaranteed to be continuous. To make myself clear, here is a paragraph from Opencv documentation:

相关标签:
3条回答
  • 2020-12-02 21:42

    You can see in the OpenCV doc for isContinuous:

    The method returns true if the matrix elements are stored continuously without gaps at the end of each row. Otherwise, it returns false. Obviously, 1x1 or 1xN matrices are always continuous. Matrices created with Mat::create() are always continuous. But if you extract a part of the matrix using Mat::col(), Mat::diag() , and so on, or constructed a matrix header for externally allocated data, such matrices may no longer have this property.

    So, as long as you are creating a new matrix (i.e. you're calling create), your matrix will be continuous.

    create works like:

    1. If the current array shape and the type match the new ones, return immediately. Otherwise, de-reference the previous data by calling Mat::release().
    2. Initialize the new header.
    3. Allocate the new data of total()*elemSize() bytes.
    4. Allocate the new, associated with the data, reference counter and set it to 1.

    This means that when you (implicitly) call create, the matrix will be continuous (step 3).


    Your questions

    If I create a new matrix with imread is the data guaranteed to be continuous

    Yes, because imread internally calls create.

    I know that creating a new matrix by borrowing data from existing matrix would result in incontinuous data.

    Correct, data will be non continuous. To make the new matrix continuous, you can call clone(), which calls create to create the new matrix.

    if I create a brand new matrix without borrowing data from existing matrix, will the brand new matrix have incontinuous data?

    Yes, the constructor internally calls create.

    Matrix constructor is guaranteed to create a matrix with continuous data?

    Yes, the constructor internally calls create.

    This is a small example to summarize:

    #include <opencv2\opencv.hpp>
    #include <iostream>
    using namespace std;
    using namespace cv;
    
    int main()
    {
        // Read image
        Mat img = imread("path_to_image");
        cout << "img is continuous? " << img.isContinuous() << endl; 
        // Yes, calls create internally
    
        // Constructed a matrix header for externally allocated data
        Mat small_mat = img.col(0);
        cout << "small_mat is continuous? " << small_mat.isContinuous() << endl; 
        // No, you're just creating a new header.
    
        // Matrix (self) expression
        small_mat = small_mat + 2;
        cout << "small_mat is continuous? " << small_mat.isContinuous() << endl; 
        // No, you're not even creating a new header
    
        // Matrix expression
        Mat expr = small_mat + 2;
        cout << "expr is continuous? " << expr.isContinuous() << endl; 
        // Yes, you're creating a new matrix
    
        // Clone
        Mat small_mat_cloned = img.col(0).clone();
        cout << "small_mat_cloned is continuous? " << small_mat_cloned.isContinuous() << endl; 
        // Yes, you're creating a new matrix
    
        // Create
        Mat mat(10, 10, CV_32FC1);
        cout << "mat is continuous? " << mat.isContinuous() << endl; 
        // Yes, you're creating a new matrix
    
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-02 21:45

    When you create a Mat with Mat::create, it is continuous. Such operation like explicitly Mat::create, or implicitly Mat::clone, Mat::Mat(...).

    0 讨论(0)
  • 2020-12-02 21:54

    Data stored in OpenCV cv::Mats are not always continuous in memory, which can be verified via API Mat::isContinuous(). Instead, it follows the following rules:

    1. Matrices created by imread(), clone(), or a constructor will always be continuous.
    2. The only time a matrix will not be continuous is when it borrows data from an existing matrix (i.e. created out of an ROI of a big mat), with the exception that the data borrowed is continuous in the big matrix, including
      • borrow a single row;
      • borrow multiple rows but with full original width.

    The following code from my blog demonstrates this in a better way (see the inline comments for further explanation).

    std::vector<cv::Mat> mats(7);
    
    // continuous as created using constructor
    mats[0] = cv::Mat::ones(1000, 800, CV_32FC3);      
    
    // NOT continuous as borrowed data is not continuous (multiple rows and not full original width)
    mats[1] = mats[0](cv::Rect(100, 100, 300, 200));     
    
    // continuous as created using clone()
    mats[2] = mats[1].clone();               
    
    // continuous for single row always    
    mats[3] = mats[2].row(10);             
    
    // NOT continuous as borrowed data is not continuous (multiple rows and not full original width)         
    mats[4] = mats[2](cv::Rect(5, 5, 100, 2));     
    
    // continuous as borrowed data is continuous (multiple rows with full original width)   
    mats[5] = mats[2](cv::Rect(0, 5, mats[2].cols, 2));
    
    // NOT continuous as borrowed data is not continuous (multiple rows and not full original width) 
    mats[6] = mats[2].col(10);                            
    
    0 讨论(0)
提交回复
热议问题