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

Sha*_*awn 17 c++ opencv

我知道,opencv矩阵中包含的数据不保证是连续的.为了清楚起见,这是Opencv文档中的一段:

在此输入图像描述

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

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

Mat img = cv::imread(img_name)
Run Code Online (Sandbox Code Playgroud)

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

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

cv::Mat small_mat = large_mat.col(0);
Run Code Online (Sandbox Code Playgroud)

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

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

cv::Mat mat(nRows, nCols, CV_32FC1);
Run Code Online (Sandbox Code Playgroud)

Mik*_*iki 20

您可以在OpenCV doc中看到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.

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

是的,构造函数内部调用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;
}
Run Code Online (Sandbox Code Playgroud)


her*_*tao 5

OpenCV 中存储的数据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);                            
Run Code Online (Sandbox Code Playgroud)