这个()操作符的特定用法是什么意思?

3

我有这个表达式:

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

我查阅了Matlab文档,但是没有类似这样的示例。尝试将其翻译为OpenCV C++。这是我的代码:

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

这正确吗?据我所知,在OpenCV中无法直接更改这些列,也许可以使用Eigen实现。左侧赋值的双括号我也不理解。


我假设 U 是一个标量(即 size 为 1-by-1)?还是一个列向量,大小为 M,1(即与 M 具有相同的行数)? - Shai
2
@Shai U 必须是大小为 size(M,1) x 1 才能使用 .* 运算符;(U * ones(1,4)) 基本上等同于 repmat(U, 1,4),我想。 - Nicu Stiurca
U是列向量size(2*N, 1),与M具有相同的行大小,如果不清楚,很抱歉。 - aledalgrande
2个回答

3

在Matlab中,你提供的代码已经很好地向量化了,因为这是在不使用Mex的情况下获得良好性能的唯一途径。然而,在C++中,为了可读性和性能,最好将其展开为for循环。

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

注意使用*=操作符,在Matlab中无法使用。
哦,还有[[3,6,9,12]]等同于[3,6,9,12](也等同于3:3:12)。

2
谢谢,看起来很不错。有一个澄清:我认为Matlab从索引1开始,所以在C++中它应该是索引:2、5、8、11? - aledalgrande
最后一个问题:如果两个方括号的用法是等价的,你能猜测开发者为什么会同时使用它们吗? - aledalgrande
@aledalgrande 没有想法。 - Nicu Stiurca
@aledalgrande:这里使用的双方括号是多余的,所以你可以像 [1 2; 3 4][[1 2]; [3 4]] 这样创建一个矩阵,结果是相同的。 - Amro

1

OpenCV

您可以在OpenCV中以一种略微矢量化的形式简洁地编写语句:

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

MATLAB

就算这样说可能没什么价值,但是MATLAB代码也可以使用广播编写:

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

这样可以避免在内存中复制向量U。这与以下代码相同:

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

这段代码类似于上面的C ++代码。

不幸的是,多年来,MATLAB因循环速度慢而声名狼藉,人们总是应该优先选择完全向量化的代码而非循环。但自从JIT改进后,这种说法已经不再适用于所有情况。

事实上,最后一个for循环非常快,甚至比bsxfun或原始代码稍微快一点!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接