【问题标题】:Circular shift of patches in matrix in MATLABMATLAB中矩阵中补丁的循环移位
【发布时间】:2015-05-02 04:26:37
【问题描述】:

如何在不显式迭代每个补丁的情况下循环遍历矩阵补丁的每个索引?

我认为执行此循环的迭代方式是使用 MATLAB 的 circshift 函数。我可以遍历矩阵中的每个 MxN 补丁,并对该补丁的元素执行循环移位。

(注意:circshift 接受一个数组并将第一个(或第 k 个)索引向后移动,将所有内容向前移动以腾出空间。使用矩阵,您只需对其进行矢量化、移动并重新整形,利用 MATLAB 的列优先线性索引)

如果我要遍历较大的 (j*M x k*N for integers j,k) 矩阵的每个 MxN 窗口,那就太好了。但是,我希望能够避免 for 循环并利用 MATLAB 的矢量化代码一举完成此操作。

一个完整的迭代示例(某些矩阵 B 中的 2x2 个补丁)将是:

B =           -->   B =           -->   B =           -->   B =
[ 5 6 7 8 ]   -->   [ 5 6 7 8 ]   -->   [ 6 5 8 7 ]   -->   [ 6 5 8 7 ]
[ 5 6 7 8 ]   -->   [ 6 5 8 7 ]   -->   [ 6 5 8 7 ]   -->   [ 5 6 7 8 ]
[ 5 6 7 8 ]   -->   [ 5 6 7 8 ]   -->   [ 6 5 8 7 ]   -->   [ 6 5 8 7 ]
[ 5 6 7 8 ]   -->   [ 6 5 8 7 ]   -->   [ 6 5 8 7 ]   -->   [ 5 6 7 8 ]

任何想法如何在不明确迭代每个补丁的情况下使这种转变发挥作用?我觉得线性索引是这里的关键,但我不知道为什么。只要每个补丁元素都在每个补丁索引中结束,我也不关心旋转顺序。

提前致谢!

编辑:这是一个可以复制和粘贴的玩具实现,使用 for 循环来演示我在寻找什么。答案中应该包含的唯一 for 循环是 k-iterator(控制最终需要进行多少次转换)

A = repmat(1:4, 4, 1); % Input matrix

% k represents the total number of shifts to be made
for k = 1:4

    % Iterate through each patch
    for i = 1:2:size(A,1)
        for j = 1:2:size(A,2)
            tmp = A(i:i+1,j:j+1); % Isolate specific patch

            % Circularly shift the vectorized patch, reshape it to a matrix
            % and insert it back into the original matrix
            A(i:i+1,j:j+1) = reshape(circshift(tmp(:),1), 2, 2);
        end
    end
    display(A) % Display each completely shifted iteration
end

【问题讨论】:

  • 这是一个有趣的问题。你一般可以认为你想要的一切都可以做到。但至少我没有动力去思考你的输入和输出应该如何安排。请发布您准备好复制和粘贴的确切输入以及您希望为该输入获得的输出(也准备好复制和粘贴)。有很多事情要澄清。例如你喜欢单元格数组作为输出吗?还是 3D 矩阵?
  • @thewaywewalk 我添加了一个用于复制/粘贴的玩具示例,希望可以演示我正在寻找的内容。输出应该是与输入相同维度的矩阵。我想避免使用元胞数组,除非它们可以很容易地转换回来。我也考虑过使用元胞数组,因为它们对于将矩阵划分为块很有用,但即便如此,据我所知,它也无助于进行转变。

标签: matlab matrix


【解决方案1】:

一个简单的方法是使用图像处理工具箱中的blockproc 函数。 blockproc 将图像(或通常:矩阵)划分为定义大小的块,并将函数应用于每个块:

B = blockproc(A,blockSize,fun);

使用blockproc,我们可以将矩阵A 划分为2 x 2 块,并对每个块应用循环移位。请注意blockproc 创建一个block_struct 数据类型并调用fun(block_struct)。要获取数据,只需使用结构的data 字段。这将导致

B = blockproc(A, [2,2], @(x)reshape(circshift(x.data(:),1),2,2));

或者使用提供的示例代码:

A = repmat(1:4, 4, 1);
for k=1:4
    A = blockproc(A, [2,2], @(x)reshape(circshift(x.data(:),1),2,2));
    display(A);
end

创建所需的输出

[ 1 2 3 4 ]      [ 2 1 4 3 ]      [ 2 1 4 3 ]      [ 1 2 3 4 ] 
[ 1 2 3 4 ]  ->  [ 1 2 3 4 ]  ->  [ 2 1 4 3 ]  ->  [ 2 1 4 3 ]  -> ...
[ 1 2 3 4 ]      [ 2 1 4 3 ]      [ 2 1 4 3 ]      [ 1 2 3 4 ] 
[ 1 2 3 4 ]      [ 1 2 3 4 ]      [ 2 1 4 3 ]      [ 2 1 4 3 ]

您还可以定义如何处理无法将矩阵划分为2 x 2 块的情况,例如如果它的尺寸为5 x 7(如 cmets 中所述)。通过将PadPartialBlocks 设置为true,将填充所有部分块,以便它们形成完整的2 x 2 块。您可以根据需要将PadMethod 属性设置为以下值之一:

  • x 其中x 是一个数字,所有附加点都将设置为该数字。
  • replicate 会重复矩阵A 的边框元素
  • symmetric 将用自身的对称反射填充 A

【讨论】:

  • blockproc 如何处理边缘情况?例如,如果输入矩阵不是 jM x kN,而是 2x2 块的 5x7?
  • @marcman 我也添加了一些东西。如果您定义所需的行为,我可能会展示如何完成。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多