opencv矩阵数据是不是保证是连续的?
Posted
技术标签:
【中文标题】opencv矩阵数据是不是保证是连续的?【英文标题】:Is opencv matrix data guaranteed to be continuous?opencv矩阵数据是否保证是连续的? 【发布时间】:2015-11-12 05:53:56 【问题描述】:我知道,opencv 矩阵中包含的数据不能保证是连续的。为了清楚起见,这里有一段来自Opencv documentation:
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);
【问题讨论】:
我猜如果你使用像 IPP 这样的奇数图像尺寸的东西,它不能保证是连续的。因此,它可能取决于您特定的 OpenCV 构建。 【参考方案1】:您可以在 OpenCV 文档中看到isContinuous:
如果矩阵元素在每一行的末尾没有间隙地连续存储,则该方法返回 true。否则,它返回 false。显然,1x1 或 1xN 矩阵总是连续的。 使用 Mat::create() 创建的矩阵总是连续的。 但是如果您使用 Mat::col()、Mat::diag() 等提取矩阵的一部分,或者构造外部分配数据的矩阵头,这样的矩阵可能不再有这个属性。
因此,只要您正在创建一个新矩阵(即您正在调用create),您的矩阵就会是连续的。
create
的作用类似于:
-
如果当前数组形状和类型与新的匹配,则立即返回。否则,通过调用 Mat::release() 取消引用之前的数据。
初始化新标头。
分配total()*elemSize()字节的新数据。
分配新的、与数据关联的引用计数器并将其设置为 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;
【讨论】:
【参考方案2】:当您使用Mat::create
创建Mat
时,它是连续的。这样的操作比如显式Mat::create
,或者隐式Mat::clone
,Mat::Mat(...)
。
【讨论】:
【参考方案3】:存储在 OpenCV cv::Mat
s 中的数据在内存中并不总是连续的,这可以通过 API Mat::isContinuous()
进行验证。相反,它遵循以下规则:
-
由
imread()
、clone()
或 构造函数 创建的矩阵将始终是连续的。
矩阵不连续的唯一情况是它从现有矩阵借用数据(即从大矩阵的 ROI 创建),但借用的数据是连续的在大矩阵中,包括
借用一行;
借用多行但具有完整的原始宽度。
来自my blog 的以下代码以更好的方式演示了这一点(请参阅内联 cmets 以获得进一步的解释)。
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);
【讨论】:
以上是关于opencv矩阵数据是不是保证是连续的?的主要内容,如果未能解决你的问题,请参考以下文章