转置矩阵/无法理解 bsxfun 的工作原理

Transposing matrix / Trouble understanding how bsxfun works

这可能是一个奇怪的问题,因为许多人会想知道为什么在拥有 .' 运算符的情况下使用像 bsxfun 这样复杂的函数进行转置。

但是,移调对我来说不是问题。我提出自己的问题并尝试使用特定函数来解决,以便我了解该函数的实际工作原理。我尝试使用 bsxfun 解决一些示例,并成功获得了预期的结果。但是我的想法,我已经理解这个函数是如何工作的,当我尝试这个例子时改变了。

我拍摄的示例图像是方形 2D 图像,因此我不会尝试访问不可用的索引。

这是我的代码:

im = imread('cameraman.tif');
imshow(im);
[rows,cols] = size(im);

imout = bsxfun(@(r,c) im(c,r),(1:rows).',1:cols);

我得到的错误:

Error using bsxfun
Invalid output dimensions.

Error in test (line 9)
imout = bsxfun(@(r,c) im(c,r),(1:rows).',1:cols);

PS: 我尝试在 im( , ) 中交换 rc(像这样:bsxfun(@(r,c) im(r,c),(1:rows).',1:cols) ) 没有造成任何错误,我得到了与输入完全相同的图像。


我也尝试过使用循环和使用 .' 运算符的简单转置,效果很好。

这是我的循环代码:

imout(size(im)) = 0;

for i = 1:rows
    for j = 1:cols
        imout(i,j) = im(j,i);
    end
end

我期待的答案是,我的代码有什么问题,错误意味着什么以及如何修改代码以使其工作。

你可以像这样使用anonymous function with bsxfun -

%// Create the tranposed indices with BSXFUN
idx = bsxfun(@(r,c) (c-1)*size(im,1)+r,1:rows,(1:cols).') %//'

%// Index into input array with those indices for the final transposed output
imout = im(idx)

这里的问题是您的函数 return 输出的形状与给定的输入的形状不同。尽管 bsxfun 的要求是该函数按元素运行,但不使用标量元素调用它。所以,你需要这样做:

x = randi(5, 4, 5)
[m, n] = size(x);
bsxfun(@(r, c) transpose(x(c, r)), (1:n)', 1:m)

我想知道 bsxfun 是如何工作的,所以我创建了一个这样的函数:

bsxfun 测试函数:

function out = bsxfuntest(r,c)
    disp([size(r) , size(c)]);
    out = r + c;  // just normal addition so that it works fine.
end

我的脚本:

im = magic(5);

[rows,cols] = size(im);

bsxfun(@bsxfuntest ,(1:rows).',1:cols);

输出:(不是函数的输出值。这些是使用 dispbsxfuntest.m 函数中打印的值)

 5     1     1     1

 5     1     1     1

 5     1     1     1

 5     1     1     1

 5     1     1     1

结论:

bsxfun passes each column into the function instead of each element.

If either one of the input is a scalar, then the function is called only one time i.e the matrix whether it is 2D or 3D or nD, is passed in one go.

试试这个:

bsxfun(@bsxfuntest , repmat(5,[5 5 5]) ,1);

Also if both the inputs are of same dimensions, then also the function is called only one time.

试试这个:

bsxfun(@bsxfuntest , repmat(5,[5 5 2]) , repmat(2,[5 5 2]))  

If none of them is a scalar, and both the inputs are of different dimensions, then The inputs are passed as column vectors.

试试这个:

bsxfun(@bsxfuntest , repmat(5,[5 5 1]) ,permute(1:3,[1 3 2]));

和这个:

bsxfun(@bsxfuntest , repmat(5,[5 5 2]) ,permute(1:2,[1 3 2]));    

问题来了

>> im

im =

17    24     1     8    15
23     5     7    14    16
 4     6    13    20    22
10    12    19    21     3
11    18    25     2     9

取题中代码:

imout = bsxfun(@(r,c) im(c,r),(1:rows).',1:cols);

当我尝试 im(c,r)im(1,(1:5).')

>> im(1,(1:5).')

ans =

17    24     1     8    15   

此处,bsxfun 需要一个 列向量 ,而输出是一个 行向量 。我想这就是 MatLab 产生错误

的原因

Invalid output dimensions.

这也是为什么当我像这样 bsxfun(@(r,c) im(r,c),(1:rows).',1:cols) 替换上面代码中的 rc 时没有出现任何错误的原因。因为在这里,输出本身就是一个列向量。

所以我尝试转置结果以获得这样的列向量:

>> imout = bsxfun(@(r,c) (im(c,r)).',(1:rows).',1:cols)

imout =

17    23     4    10    11
24     5     6    12    18
 1     7    13    19    25
 8    14    20    21     2
15    16    22     3     9

代码与 完全相同,并且给出了预期的结果。