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

24

我知道 OpenCV 矩阵中包含的数据不保证连续。为了让自己清楚,以下是 OpenCV 文档 中的一段话:

enter image description here

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

  1. 如果我像下面这样创建一个新矩阵
cv::Mat img = cv::imread(img_name)

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

  1. 我知道通过从现有矩阵中借用数据创建新矩阵会导致不连续的数据。
cv::Mat small_mat = large_mat.col(0);

上面的代码通过从large_mat中借用第0列创建一个新的矩阵small_mat,导致small_mat中的数据不连续。因此问题是,如果我创建一个全新的矩阵而不是从现有矩阵中借用数据,那么这个全新的矩阵会具有连续数据还是不连续数据?

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

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

我猜如果你使用像IPP这样的东西并且图像尺寸是奇数,那么连续性就不能得到保证。因此,这可能取决于你具体的OpenCV构建。 - Micka
3个回答

28

根据OpenCV文档中的isContinuous函数说明:

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

因此,只要创建一个新的矩阵(即调用create),就可以保证矩阵是连续的。

create的工作方式如下:

  1. 如果当前数组形状和类型与新的匹配,则立即返回。否则,通过调用Mat :: release()取消引用先前的数据。
  2. 初始化新标题。
  3. 分配total()* elemSize()字节的新数据。
  4. 分配与数据相关联的新引用计数器并将其设置为1。

这意味着当您(隐式地)调用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;
}

4

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

  1. imread()clone()构造函数创建的矩阵始终是连续的。
  2. 仅当矩阵从现有矩阵中借用数据(即从大型矩阵的ROI创建)时,矩阵才不连续,但所借用的数据在大矩阵中是连续的,包括:
    • 借用单行;
    • 借用多行但具有完整的原始宽度。

以下来自我的博客示例代码更好地演示了这一点(有关进一步说明,请参见内联注释)。

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

4
当您使用Mat::create创建一个Mat时,它是连续的。这样的操作包括显式使用Mat::create,或隐式地使用Mat::cloneMat::Mat(...)等方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接