让我们说,A
并且B
是相同大小的矩阵.在Matlab
,我可以使用如下的简单索引.
idx = A>0;
B(idx) = 0
Run Code Online (Sandbox Code Playgroud)
我怎么能这样做OpenCV
?我应该使用
for (i=0; ... rows)
for(j=0; ... cols)
if (A.at<double>(i,j)>0) B.at<double>(i,j) = 0;
Run Code Online (Sandbox Code Playgroud)
这样的事情?是否有更好(更快,更有效)的方式?
而且,在OpenCV
我尝试的时候
Mat idx = A>0;
Run Code Online (Sandbox Code Playgroud)
变量idx
似乎是一个CV_8U
矩阵(不是布尔而是整数).
您可以轻松转换此MATLAB代码:
idx = A > 0;
B(idx) = 0;
// same as
B(A>0) = 0;
Run Code Online (Sandbox Code Playgroud)
到OpenCV:
Mat1d A(...)
Mat1d B(...)
Mat1b idx = A > 0;
B.setTo(0, idx) = 0;
// or
B.setTo(0, A > 0);
Run Code Online (Sandbox Code Playgroud)
关于性能,在C++中,它通常更快(取决于启用的优化)来处理原始指针(但不太可读):
for (int r = 0; r < B.rows; ++r)
{
double* pA = A.ptr<double>(r);
double* pB = B.ptr<double>(r);
for (int c = 0; c < B.cols; ++c)
{
if (pA[c] > 0.0) pB[c] = 0.0;
}
}
Run Code Online (Sandbox Code Playgroud)
还要注意,在OpenCV中没有任何布尔矩阵,但它是一个CV_8UC1
矩阵(也就是单个通道矩阵unsigned char
),其中0
是均值false
,任何值>0
都是真的(通常255
).
评估
请注意,这可能会因 OpenCV启用的优化而有所不同.您可以在PC上测试以下代码以获得准确的结果.
以毫秒计的时间:
my results my results @AdrienDescamps
(OpenCV 3.0 No IPP) (OpenCV 2.4.9)
Matlab : 13.473
C++ Mask: 640.824 5.81815 ~5
C++ Loop: 5.24414 4.95127 ~4
Run Code Online (Sandbox Code Playgroud)
注意:我不完全确定OpenCV 3.0的性能下降,所以我只想说:在PC上测试下面的代码以获得准确的结果.
正如@AdrienDescamps在评论中所述:
看起来OpenCV 3.0的性能下降与OpenCL选项有关,现在在比较运算符中启用了该选项.
C++代码
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
// Random initialize A with values in [-100, 100]
Mat1d A(1000, 1000);
randu(A, Scalar(-100), Scalar(100));
// B initialized with some constant (5) value
Mat1d B(A.rows, A.cols, 5.0);
// Operation: B(A>0) = 0;
{
// Using mask
double tic = double(getTickCount());
B.setTo(0, A > 0);
double toc = (double(getTickCount()) - tic) * 1000 / getTickFrequency();
cout << "Mask: " << toc << endl;
}
{
// Using for loop
double tic = double(getTickCount());
for (int r = 0; r < B.rows; ++r)
{
double* pA = A.ptr<double>(r);
double* pB = B.ptr<double>(r);
for (int c = 0; c < B.cols; ++c)
{
if (pA[c] > 0.0) pB[c] = 0.0;
}
}
double toc = (double(getTickCount()) - tic) * 1000 / getTickFrequency();
cout << "Loop: " << toc << endl;
}
getchar();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
Matlab代码
% Random initialize A with values in [-100, 100]
A = (rand(1000) * 200) - 100;
% B initialized with some constant (5) value
B = ones(1000) * 5;
tic
B(A>0) = 0;
toc
Run Code Online (Sandbox Code Playgroud)
UPDATE
OpenCV 3.0在函数中使用IPP优化setTo
.如果你启用了(你可以查看cv::getBuildInformation()
),你将有一个更快的计算.
Miki的回答非常好,但我只是想补充一些关于性能问题的说明,以避免任何混乱。
确实,使用 OpenCV 实现图像过滤器(或任何算法)的最佳方法是使用原始指针,如 Miki 的第二个 C++ 示例(C++ 循环)所示。使用 at 函数也是正确的,但速度明显慢。
然而,大多数时候,您不需要担心这一点,您可以简单地使用 OpenCV 的高级功能(Miki 的第一个示例,C++ Mask)。它们经过了很好的优化,通常几乎与指针上的低级循环一样快,甚至更快。
当然,也有例外(我们刚刚发现了一个),您应该始终针对您的具体问题进行测试。
现在,关于这个具体问题:
这里的示例中,高级函数比低级循环慢得多(慢 100 倍),这不是正常情况,因为 OpenCV 其他版本/配置的时间要低得多,这表明了这一点。问题似乎是,当使用 OpenCL 编译 OpenCV3.0 时,第一次调用使用 OpenCL 的函数时会产生巨大的开销。如果您使用 OpenCV3.0,最简单的解决方案是在编译时禁用 OpenCL(如果您感兴趣,另请参阅此处了解其他可能的解决方案)。
归档时间: |
|
查看次数: |
2504 次 |
最近记录: |