假设A
和B
是相同大小的矩阵。
在Matlab
中,我可以使用如下的简单索引。
idx = A>0;
B(idx) = 0
我如何在OpenCV
中执行此操作?我应该只使用
for (i=0; ... rows)
for(j=0; ... cols)
if (A.at<double>(i,j)>0) B.at<double>(i,j) = 0;
这样的事情?是否有更好(更快,更有效)的方式?
此外,在OpenCV
中,当我尝试
Mat idx = A>0;
变量idx
似乎是CV_8U
矩阵(不是布尔值而是整数)。
答案 0 :(得分:6)
您可以轻松转换此MATLAB代码:
idx = A > 0;
B(idx) = 0;
// same as
B(A>0) = 0;
以OpenCV格式:
Mat1d A(...)
Mat1d B(...)
Mat1b idx = A > 0;
B.setTo(0, idx) = 0;
// or
B.setTo(0, A > 0);
关于性能,在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;
}
}
另请注意,在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
注意:我对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;
}
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
<强>更新强>
OpenCV 3.0在函数setTo
中使用IPP优化。如果您启用了该功能(可以使用cv::getBuildInformation()
查看),那么您的计算速度会更快。
答案 1 :(得分:4)
Miki的答案非常好,但我只想补充一些关于性能问题的澄清,以避免混淆。
使用OpenCV实现图像过滤器(或任何算法)的最佳方法是使用原始指针,如Miki(C ++ Loop)的第二个C ++示例所示。 使用at函数也是正确的,但速度要慢得多。
但是,大多数情况下,你不必担心,你可以简单地使用OpenCV的高级功能(Miki,C ++ Mask的第一个例子)。它们经过了很好的优化,通常几乎和指针上的低级循环一样快,甚至更快。
当然,也有例外(我们刚刚找到一个),您应该始终测试您的具体问题。
现在,关于这个具体问题:
此处高级函数比低级循环慢得多(慢100倍)的示例不是正常情况,因为OpenCV的其他版本/配置的时序要低得多。 问题似乎是当使用OpenCL编译OpenCV3.0时,第一次调用使用OpenCL的函数时会产生巨大的开销。最简单的解决方案是在编译时禁用OpenCL,如果您使用OpenCV3.0(如果您有兴趣,另请参阅here了解其他可能的解决方案。)