我没有使用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),而不复制数据(由于数量可能很昂贵数据)。
这有可能吗?
答案 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
成员(例如rows
,cols
和flags
)将更新为
准确描述m
中数据现在指向的数据。这一切都导致了非常方便的行为,其中数组可以彼此分配,并且在幕后自动执行此操作以获得正确的结果。
答案 1 :(得分:0)
不,如果不复制数据,就无法将多个OpenCV矩阵连接成一个。
类cv::Mat
仅包含指向数据的单个指针,不允许处理多个内存区域。
datastart
中还有指针dataend
,datalimit
和cv::Mat
,但这些只是支持感兴趣区域的助手。它们有助于处理较小的矩阵而无需复制数据,而不是更大。