【问题标题】:Transposing matrix / Trouble understanding how bsxfun works转置矩阵/难以理解 bsxfun 的工作原理
【发布时间】:2015-05-01 06:59:58
【问题描述】:

这可能是一个奇怪的问题,因为很多人会想知道为什么要使用像 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

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

【问题讨论】:

  • 好问题。特别是为了正确提及.' 而不是' :-)
  • @LuisMendo 谢谢。我也做了一些测试并找到了解决方案。如果我错了,我希望你们能够验证并纠正:)
  • 我不确定我是否理解您在回答中写的内容。 bsxfun 执行单例扩展:它根据另一个数组中该维度的大小重复每个单例维度。这就是它的全部,我想
  • @LuisMendo,是的.. 文档说它实际上 沿该维度复制数组以匹配另一个数组。如果它实际上已复制,则大小会有所不同。
  • 是的,对不起。复制只是从功能的角度来看。它实际上并没有被替换(那就是repmat

标签: image matlab matrix transpose bsxfun


【解决方案1】:

您可以像这样使用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)

【讨论】:

  • hmm :) 那行得通,+1 但你还是会提到为什么我的代码不起作用?还有这个错误意味着什么?为什么当我交换rc 时,matlab 没有给我同样的错误?这会让我更了解这个功能。你会吗?
  • @SanthanSalai 我希望我对错误有一个很好的答案,不幸的是我没有。
  • 没有问题 :) 我用它做了一些测试,我想我找到了该错误的原因。我已将其作为解决方案发布,如果我错了,我希望你们验证并纠正。
【解决方案2】:

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

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

【讨论】:

  • "虽然bsxfun 的要求是函数按元素操作,但它不是用标量元素调用的"。这对我来说很有意义。我做了一些测试,发现结果和你的完全一样:) +1
【解决方案3】:

我想知道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 需要一个列向量,而输出是一个行向量。我想这就是 MatLab 产生错误说明的原因

输出尺寸无效。

这也是我在上面的代码中替换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's solution 完全相同,并且给出了预期的结果。

【讨论】:

  • 现在有点意思了!但是,仍然有几件事对我来说并不完全清楚,我认为至少对我来说需要更深入地挖掘。此外,看看这如何扩展到更多维度会很有趣。
  • @Divakar,您是否对此进行了进一步研究?有什么奇怪的结果吗?如果是肯定的,您想分享,还是可能作为新主题发布?可能对我们中的许多人有所帮助.. 热切等待:)
  • 啊,对不起,我没有。也许将来某个时候我可能会,但目前还没有计划,真的很抱歉:)
  • @Divakar 没关系.. 没有问题 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-03
  • 2015-07-11
  • 1970-01-01
  • 2021-04-24
  • 2018-06-25
  • 1970-01-01
相关资源
最近更新 更多