Best way to index a matrix in opencv

Say A and B are matrices of the same size. In Matlab I could use simple indexing, as shown below.

 idx = A>0; B(idx) = 0 

How to do it in OpenCV ? Should i just use

 for (i=0; ... rows) for(j=0; ... cols) if (A.at<double>(i,j)>0) B.at<double>(i,j) = 0; 

something like that? Is there a better (faster and more efficient) way?

Also in OpenCV when I try

 Mat idx = A>0; 

the idx variable is represented by the matrix CV_8U (not logical, but integer).

+5
source share
2 answers

You can easily convert this MATLAB code:

 idx = A > 0; B(idx) = 0; // same as B(A>0) = 0; 

in opencv like:

 Mat1d A(...) Mat1d B(...) Mat1b idx = A > 0; B.setTo(0, idx) = 0; // or B.setTo(0, A > 0); 

As for performance, in C ++ it is usually faster (depending on the allowed optimizations) working on raw pointers (but less readable):

 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; } } 

Also note that there is no logical matrix in OpenCV, but it is a CV_8UC1 matrix (aka single-channel matrix unsigned char ), where 0 means false , and any value >0 (usually 255 ).

Rating

Please note that this may vary according to the optimization included in OpenCV. You can check the code below on your PC to get accurate results.

Time in ms:

  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 

Note. I'm not quite sure about performance degradation with OpenCV 3.0, so I just notice: check the code below on your PC to get accurate results.

Like @AdrienDescamps in the comments:

It seems that the drop in performance with OpenCV 3.0 is due to the OpenCL option, which is now included in the comparison operator.

C ++ code

 #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 Code

 % 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 

UPDATE

OpenCV 3.0 uses IPP optimization in the setTo function. If you have this (you can check with cv::getBuildInformation() ), you will get a faster calculation.

+5
source

Miki's answer is very good, but I just want to add some clarification to the performance issue to avoid confusion.

It is true that the best way to implement an image filter (or any algorithm) with OpenCV is to use raw pointers, as shown in the second C ++ Miki (C ++ Loop) example. Using the at function is also correct, but much slower.

However, most of the time you don’t need to worry about this, and you can just use the high-level features of OpenCV (the first Miki example, C ++ Mask). They are well optimized and usually will be almost as fast as the low-level loop on pointers, or even faster.

Of course, there are exceptions (we just found them), and you should always check your specific problem.

Now, regarding this particular problem:

An example here, where a high-level function was much slower (100 times slower) than a low-level loop, is not a normal case, as it is demonstrated by timings with a different version / configuration of OpenCV, which are much lower. The problem is that when OpenCV3.0 is compiled with OpenCL, there is a huge overhead when you call a function using OpenCL for the first time. The easiest solution is to disable OpenCL at compile time if you are using OpenCV3.0 (see also here for other possible solutions if you are interested).

+3
source

Source: https://habr.com/ru/post/1236115/


All Articles