aledalgrande
aledalgrande

Reputation: 5217

What does this particular use of the () operator mean?

I have this expression:

M(:,[[3,6,9,12]]) =  M(:,[3,6,9,12]) .* (U * ones(1,4));

I checked in the Matlab docs, but there are no examples like this. Trying to translate it to OpenCV C++. This is my code:

  cv::Mat temp(M.rows, 4, CV_64F);
  M.col(2).copyTo(temp(cv::Rect(0,0,1,M.rows)));
  M.col(5).copyTo(temp(cv::Rect(1,0,1,M.rows)));
  M.col(8).copyTo(temp(cv::Rect(2,0,1,M.rows)));
  M.col(11).copyTo(temp(cv::Rect(3,0,1,M.rows)));
  temp = temp.mul(U * cv::Mat::ones(1,4,CV_64F));
  temp.col(0).copyTo(M(cv::Rect(2,0,1,M.rows)));
  temp.col(1).copyTo(M(cv::Rect(5,0,1,M.rows)));
  temp.col(2).copyTo(M(cv::Rect(8,0,1,M.rows)));
  temp.col(3).copyTo(M(cv::Rect(11,0,1,M.rows)));

Is it correct? To my knowledge, there is no way I can change those columns directly in OpenCV, maybe it would be possible with Eigen. Also don't understand the double bracket in the left part of the assignment.

Upvotes: 3

Views: 143

Answers (2)

Amro
Amro

Reputation: 124563

OpenCV

You can write the statement concisely in OpenCV, in a somewhat vectorized form:

for (int i=2; i<12; i+=3) {
    Mat(M.col(i).mul(U)).copyTo(M.col(i));
}

MATLAB

For what it's worth, the MATLAB code can also be written with broadcasting:

M(:,[3 6 9 12]) = bsxfun(@times, M(:,[3 6 9 12]), U);

This avoids replicating the vector U in memory. It is the same as:

for i=3:3:12
    M(:,i) = M(:,i) .* U;
end

which resembles the above C++ code.

Unfortunately over the years, MATLAB has gotten a bad reputation for being slow with loops, and that one should always prefer fully vectorized code over loops. But that is no longer true in all cases, ever since the improvements made in JIT.

In fact, that last for-loop is very fast, even slightly faster than bsxfun or the original code!

Upvotes: 1

Nicu Stiurca
Nicu Stiurca

Reputation: 8677

In Matlab, the code you give is well vectorized because that's the only way to get good performance without using Mex. In c++ however, you are better off expanding it into for loops for both readability and performance.

for(int i=0; i<M.rows; ++i) {
    for(int j=2; j<12; j+=3) {    // start from 2 due to 0-based indexing
        M.at<double>(i,j) *= U.at<double>(i);
    }
}

Note the use of the *= operator, which is not available in Matlab.

Oh, and [[3,6,9,12]] is equivalent to [3,6,9,12] (and to 3:3:12).

Upvotes: 3

Related Questions