转换矩阵/难以理解bsxfun的工作原理



这可能是一个奇怪的问题,因为许多人会想,既然有.'运算符,为什么要使用像bsxfun这样复杂的函数来进行换位。

但是,转座对我来说不是问题。我提出自己的问题,并尝试使用特定的函数来解决,这样我就可以了解函数的实际工作方式。我尝试使用bsxfun解决一些例子,并成功地获得了预期的结果。但当我尝试这个例子时,我的想法发生了变化,我已经理解了这个函数是如何工作的。

我拍摄的示例图像是一个正方形的2D图像,这样我就不会试图访问不可用的索引。

这是我的代码:

im = imread('cameraman.tif');
imshow(im);
[rows,cols] = size(im);
imout = bsxfun(@(r,c) im(c,r),(1:rows).',1:cols);

我得到的错误:

使用bsxfun时出错
无效的输出维度。

测试中出错(第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 functionbsxfun

%// 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)

这里的问题是,函数返回的输出形状与给定的输入形状不同。尽管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将每一列而不是每一个元素传递到函数中。

如果输入中的任何一个是标量,则函数只被调用一次,即矩阵,无论是2D、3D还是nD,都是一次性传递的。

试试这个:

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

此外,如果两个输入的维度相同,则函数也只调用一次。

试试这个:

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

如果它们都不是标量,并且两个输入都具有不同的维度,则输入将作为列向量传递。

试试这个:

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期望一个列向量,而输出是行向量

无效的输出维度。

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

所以我试着把结果转置,得到这样的列向量:

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

该代码与Edrics的解决方案完全相同,并给出了预期的结果。

相关内容

  • 没有找到相关文章

最新更新