opencv矩阵数据是否保证连续?

时间:2015-11-12 05:53:57

标签: c++ opencv

我知道,opencv矩阵中包含的数据不保证是连续的。为了清楚起见,这里有一段Opencv documentation

enter image description here

Opencv提供了一个名为 isContinuous() 的函数来测试给定矩阵的数据是否是连续的。我的问题是

(1)如果我按如下方式创建新矩阵

Mat img = cv::imread(img_name)

img 中的数据是否保证是连续的?

(2)我知道通过从现有矩阵借用数据来创建新矩阵会导致不连续的数据

cv::Mat small_mat = large_mat.col(0);

上面的代码通过借用 large_mat 的第0列创建了一个新矩阵 small_mat ,导致 small_mat 中的不连续数据。所以问题是,如果我在不借用现有矩阵的数据的情况下创建一个全新的矩阵,那么全新的矩阵是否会有不间断的数据?

(3)以下代码是否可以保证创建具有连续数据的矩阵?

cv::Mat mat(nRows, nCols, CV_32FC1);

3 个答案:

答案 0 :(得分:17)

您可以在OpenCV文档中看到isContinuous

  

如果矩阵元素连续存储,并且每行末尾没有间隙,则该方法返回true。否则,它返回false。显然,1x1或1xN矩阵始终是连续的。 使用Mat :: create()创建的矩阵始终是连续的。但是如果使用Mat :: col(),Mat :: diag()等提取矩阵的一部分,或者构造外部分配数据的矩阵标头,这样的矩阵可能不再具有此属性。

因此,只要您创建一个新矩阵(即您正在调用create),您的矩阵将是连续的。

create的作用类似于:

  1. 如果当前数组形状和类型与新数组匹配,请立即返回。否则,通过调用Mat :: release()来取消引用先前的数据。
  2. 初始化新标题。
  3. 分配total()* elemSize()字节的新数据。
  4. 分配新数据,与数据相关联,引用计数器并将其设置为1.
  5. 这意味着当您(隐式)调用create时,矩阵将是连续的(步骤3)。

    您的问题

      

    如果我使用imread创建一个新矩阵,则数据保证是连续的

    ,因为imread内部调用了create

      

    我知道通过从现有矩阵借用数据来创建新矩阵会导致数据不连续。

    正确,数据将非连续。要使新矩阵连续,您可以调用clone(),调用create来创建新矩阵。

      

    如果我在不借用现有矩阵的数据的情况下创建一个全新的矩阵,那么全新的矩阵是否会有不间断的数据?

    ,构造函数在内部调用create

      

    矩阵构造函数可以保证创建一个包含连续数据的矩阵吗?

    ,构造函数在内部调用create

    这是一个总结的小例子:

    #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;
    }
    

答案 1 :(得分:2)

使用Mat创建Mat::create时,它是连续的。此类操作类似于Mat::create,或隐式Mat::cloneMat::Mat(...)

答案 2 :(得分:2)

OpenCV cv::Mat中存储的数据在内存中并不总是连续的,可以通过API Mat::isContinuous()进行验证。而是遵循以下规则:

  1. imread() clone() 构造函数创建的矩阵将始终是连续的。
  2. 只有当矩阵从现有矩阵借入数据(即从大垫子的ROI中创建)时,矩阵才不会是连续的,唯一的例外是借入的数据是连续的在大矩阵中,包括
    • 借一行;
    • 借用多行但具有完整的原始宽度。

来自my blog的以下代码以更好的方式对此进行了演示(有关更多说明,请参见内联注释)。

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);