Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Circular shift of patches in matrix in MATLAB

Tags:

matrix

matlab

How do I cycle elements through each index of patches of a matrix without explicitly iterating through each patch?

Example

The iterative way I can think to perform this cycling is with MATLAB's circshift function. I could iterate through each MxN patch in my matrix, and perform a circular shift on the elements of that patch.

(NOTE: circshift takes an array and moves the first (or k-th) index to the back, shifting everything forward to make room. With a matrix, you just vectorize it, shift it, and reshape back, taking advantage of MATLAB's column-major linear indexing)

That would be great if I were to iterate through every MxN window of my larger (j*M x k*N for integers j,k) matrix. However, I'd like to be able to avoid for loops and take advantage of MATLAB's vectorized code to do this in one fell swoop.

One full iteration through an example (2x2 patches in some matrix B) would be:

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 ]

Any ideas how to make this shift work without explicitly iterating through every patch? I feel like linear indexing is the key here, but I'm not sure why. I also don't care about the order of rotation as long as every patch element ends up in every patch index.

Thanks in advance!

EDIT: Here's a copy-and-paste-able toy implementation using for loops to demonstrate what I'm looking for. The only for loop that should be included in an answer is the k-iterator (controls how many shifts ultimately need to be made)

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
like image 458
marcman Avatar asked May 02 '15 04:05

marcman


People also ask

How do you shift a circle in Matlab?

Y = circshift( A , K ) circularly shifts the elements in array A by K positions. If K is an integer, then circshift shifts along the first dimension of A whose size does not equal 1. If K is a vector of integers, then each element of K indicates the shift amount in the corresponding dimension of A .

How do you shift dimensions in Matlab?

B = shiftdim( A , n ) shifts the dimensions of an array A by n positions. shiftdim shifts the dimensions to the left when n is a positive integer and to the right when n is a negative integer. For example, if A is a 2-by-3-by-4 array, then shiftdim(A,2) returns a 4-by-2-by-3 array.

What is the Reshape command in Matlab?

The reshape function changes the size and shape of an array. For example, reshape a 3-by-4 matrix to a 2-by-6 matrix.

How do you create a circulant matrix in Matlab?

You can create circulant matrices using toeplitz . Circulant matrices are used in applications such as circular convolution. Create a circulant matrix from vector v using toeplitz. Perform discrete-time circular convolution by using toeplitz to form the circulant matrix for convolution.


1 Answers

A simple way to do this would be to use the blockproc function from the Image Processing Toolbox. blockproc divides an image (or in general: a matrix) into blocks of a defined size and applies a function to each of these blocks:

B = blockproc(A,blockSize,fun);

Using blockproc, we can divide the matrix A into 2 x 2 patches and apply the circular shift to each of those patches. Note that blockproc creates a block_struct datatype and calls fun(block_struct). To get the data, simply use the data field of the struct. This will lead to

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

Or with the provided example code:

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

which creates the desired output

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

You can also define, how to handle cases where the matrix can not be divided into 2 x 2 blocks, e.g. if it has dimension 5 x 7 (as mentioned in comments). By setting the PadPartialBlocks to true, all partial blocks will be padded so they form full 2 x 2 blocks. You can set the PadMethod property to one of the following values, depending on what you need:

  • x where x is a number, which all additional points will be set to.
  • replicate will repeat the border elements of the matrix A
  • symmetric will pad A with symmetric reflections of itsself
like image 106
hbaderts Avatar answered Oct 31 '22 04:10

hbaderts