这可能是一个奇怪的问题,因为许多人会想,既然有.'
运算符,为什么要使用像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( , )
中交换r
和c
(像这样: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
和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)
这里的问题是,函数返回的输出形状与给定的输入形状不同。尽管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);
输出:(不是函数的输出值。这些是使用disp
在bsxfuntest.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
这里, 无效的输出维度。 这也是我在上面的代码中替换 所以我试着把结果转置,得到这样的列向量: 该代码与Edrics的解决方案完全相同,并给出了预期的结果。bsxfun
期望一个列向量,而输出是行向量r
和c
时没有得到任何错误的原因,比如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