Reputation: 5217
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
Reputation: 124563
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));
}
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
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