如何在 OpenCV Mat 中保留固定的缓冲区大小?

Posted

技术标签:

【中文标题】如何在 OpenCV Mat 中保留固定的缓冲区大小?【英文标题】:How can I reserve a fixed buffer size in OpenCV Mat? 【发布时间】:2019-06-13 22:47:54 【问题描述】:

我正在重写一些遗留代码,这些代码使用原始 C 样式数组对双精度数进行矩阵运算。由于代码已经在其他地方依赖于 OpenCV,我想改用 cv::Mat 类。

困扰我的特定代码适用于大小从 1*1 到 NN 的方阵。它通过分配一个 NN 个缓冲区并将其子集用于较小的矩阵来实现。

double* buf = new double[NxN];
for (int i = 1; i < N; ++i) 
    // Reuse buf to create a i*i matrix and perform matrix operations
    ...


delete[] buf;

基本上,我想替换该代码以在循环中使用 cv::Mat 对象。问题是,代码需要大量的循环迭代(有嵌套循环等等),如果我只是使用幼稚和干净的方法,就会有太多的分配/解除分配。因此,我想预先保留我的矩阵对象的大小并为每次迭代调整它的大小。理想情况下应该是这样的:

cv::Mat m;
m.reserveBuffer(N * N * sizeof(double));
for (int i = 1; i < N; ++i) 
    m = cv::Mat(i, i, CV_64F);
    // Perform matrix operations on m
    ...


但据我了解,这只会删除m 的先前实例,然后分配一个 i*i 矩阵。正确的方法是什么?

【问题讨论】:

您无需调整大小,而是分配一个 Mat,然后创建该 Mat 的视图 (ROIs) 以表示那些较小的子矩阵。 【参考方案1】:

您可以使用cv::Mat::operator() 为您的缓冲区创建一个子矩阵标头。为您要在当前循环迭代中处理的 ROI 传递 cv::Rect(在您的情况下为 0, 0, i, i),它将返回缓冲区的视图作为另一个 cv::Mat 实例。它不会分配新的缓冲区,而是引用原始缓冲区数据。

cv::Mat m(N, N, CV_64FC1);
for (int i = 1; i < N; ++i) 
    cv::Mat subM = m(0, 0, i*i);
    // Perform matrix operations on "subM"
    // Modifying "subM" will modify "m" buffer region that "subM" represents

请注意subM 不会be continious,因此如果您进行任何原始缓冲区处理,则需要逐行处理。

【讨论】:

有趣的拍摄,很优雅!使用非连续矩阵是否有(可测量的)性能影响,例如矩阵乘法?最初的目标是提高性能并使代码更具可读性。 @OlivierDesenfans 这取决于您如何迭代原始缓冲区。无论如何,它不会降低性能太多。在此处查看连续和非连续缓冲区上的每像素数据访问方法的性能比较:longstryder.com/2014/07/…。 @OlivierDesenfans 测量您之前的实现(在遗留代码中)和此实现执行时间,以了解性能如何变化。

以上是关于如何在 OpenCV Mat 中保留固定的缓冲区大小?的主要内容,如果未能解决你的问题,请参考以下文章

选择一个 Mat 的子集并复制它们以在 C++/Opencv 中创建一个新的 mat

OpenCV中的Mat类

opencv编程中cvMat到Mat如何进行数据转换?

如何在 Opencv 中显示一个 Mat

如何在 Python 中使用 OpenCV 创建 Mat 矩阵?

《OpenCV:访问Mat图像中每个像素值》