无需从其他OpenCV Matrix复制到cv :: Mat和cv :: UMat的数据分配

时间:2018-05-17 13:24:59

标签: c++ opencv

我没有使用C ++ OpenCV(版本3.4.1)进行数据分配。

请查看以下示例代码:

std::cout << "test cv::Mat" << std::endl;
cv::Mat a(2, 2, CV_32FC1, cv::Scalar(1.));
cv::Mat b(2, 2, CV_32FC1, cv::Scalar(5.));
std::cout << "a:" << std::endl << a << std::endl;
std::cout << "b:" << std::endl << b << std::endl;

a.col(0) = b.col(0);
std::cout << "a:" << std::endl << a << std::endl;
std::cout << "b:" << std::endl << b << std::endl;

a.col(0) = b.row(0).t();
std::cout << "a:" << std::endl << a << std::endl;
std::cout << "b:" << std::endl << b << std::endl;

std::cout << "test cv::UMat" << std::endl;
cv::UMat c(2, 2, CV_32FC1, cv::Scalar(1.));
cv::UMat d(2, 2, CV_32FC1, cv::Scalar(5.));
std::cout << "c:" << std::endl << c << std::endl;
std::cout << "d:" << std::endl << d << std::endl;

c.col(0) = d.col(0);
std::cout << "c:" << std::endl << c << std::endl;
std::cout << "d:" << std::endl << d << std::endl;

c.col(0) = d.row(0).t();
std::cout << "c:" << std::endl << c << std::endl;
std::cout << "d:" << std::endl << d << std::endl;

这给出了以下输出:

test cv::Mat
a:
[1, 1;
1, 1]
b:
[5, 5;
5, 5]
a:
[1, 1;
1, 1]
b:
[5, 5;
5, 5]
a:
[5, 1;
5, 1]
b:
[5, 5;
5, 5]
test cv::UMat
[ INFO:0] Initialize OpenCL runtime...
c:
[1, 1;
1, 1]
d:
[5, 5;
5, 5]
c:
[1, 1;
1, 1]
d:
[5, 5;
5, 5]
c:
[1, 1;
1, 1]
d:
[5, 5;
5, 5]

如果是cv :: Mat,为什么a.col(0) = b.col(0); 的分配不起作用

为什么a.col(0) = b.row(0).t(); 的分配工作

为什么cv :: UMat会有所不同?

所有这一切背后的目标是从多个其他OpenCV矩阵连接cv :: Mat(或更好的cv :: UMat),而不复制数据(由于数量可能很昂贵数据)。

这有可能吗?

2 个答案:

答案 0 :(得分:0)

使用a.row()a.col()时,不会复制a中的数据 到新阵列。像d = b.col(0);:这个表达式 意味着创建一个新的数组头d,并安排其数据指针,步骤数组等,以便它将访问d中col 0中的数据。 所以这就是为什么它看起来不起作用,当你向它添加转置.t()时,你就不会出现同样的情况。

对于CPU版本,在.t()中,您没有应用与.col()相同的规则,只是将向量分配给另一个矩阵,因此其值已被复制/修改。

对于UMat,我没有足够的信息确切地使用GPU或CPU来执行任务。对我而言,它正在使用我的GPU,但对你来说它似乎并不是:

test cv::UMat
[ INFO:0] Initialize OpenCL runtime...
[ INFO:0] Successfully initialized OpenCL cache directory: /home/jdros/.cache/opencv/3.4.1-dev/opencl_cache/
[ INFO:0] Preparing OpenCL cache configuration for context: NVIDIA_Corporation--GeForce_930MX--384_81

<强>建议: 使用较新版本的OpenCV,您可以获得更优化的代码并且更快。因此,我建议您阅读有关在内存中复制数据的每个特定功能和/或自己尝试一些代码,您可以使用.clone()copyTo()等功能。例如,一个简单的赋值不是矩阵复制的最佳方式,这是你真正需要的,但是.clone()实际上是在内存中复制数据。但是要研究一下你正在使用的每个函数,它是值得的

我在一本名为Learning OpenCV 3: Computer Vision in C++ with the OpenCV Library

的书中找到了更多信息

了解数组中的数据并非严格附加到数组对象是至关重要的。 cv::Mat对象实际上是数据区域的标头,原则上它是完全独立的。例如,可以将一个矩阵n分配给另一个矩阵m(即m=n)。在这种情况下,m内的数据指针将更改为指向与n相同的数据。先前由m(如果有)的数据元素指向的数据将被解除分配(从技术上讲,如果m是指向该特定数据的最后一个cv::Mat,它将仅被解除分配)。同时,它们现在共享的数据区域的参考计数器将递增。最后但并非最不重要的是,表征其数据的m成员(例如rowscolsflags)将更新为 准确描述m中数据现在指向的数据。这一切都导致了非常方便的行为,其中数组可以彼此分配,并且在幕后自动执行此操作以获得正确的结果。

答案 1 :(得分:0)

不,如果不复制数据,就无法将多个OpenCV矩阵连接成一个。

cv::Mat仅包含指向数据的单个指针,不允许处理多个内存区域。

datastart中还有指针dataenddatalimitcv::Mat,但这些只是支持感兴趣区域的助手。它们有助于处理较小的矩阵而无需复制数据,而不是更大。