jeff
jeff

Reputation: 13673

tile image with MATLAB imrotate

When I use the imrotate function of MATLAB, output image has missing parts which are filled with zeros.

Can I somehow make it so the triangles in the corners (i.e. the missing parts) are filled with the opposite edge of the image? So it will be like I have tiled the image with 8 neighbors around itself, and then rotated and cropped the bigger image?

Thanks for any help,

Upvotes: 2

Views: 441

Answers (2)

beaker
beaker

Reputation: 16811

The most direct way, using the Image Processing Toolbox, is to use padarray. Given an image:

>> img = reshape(1:25, 5, 5)
img =

    1    6   11   16   21
    2    7   12   17   22
    3    8   13   18   23
    4    9   14   19   24
    5   10   15   20   25

Then you can replicate the image on all sides:

>> padarray(img, size(img), 'circular')
ans =

    1    6   11   16   21  |  1    6   11   16   21  |  1    6   11   16   21
    2    7   12   17   22  |  2    7   12   17   22  |  2    7   12   17   22
    3    8   13   18   23  |  3    8   13   18   23  |  3    8   13   18   23
    4    9   14   19   24  |  4    9   14   19   24  |  4    9   14   19   24
    5   10   15   20   25  |  5   10   15   20   25  |  5   10   15   20   25
   --------------------------------------------------------------------------
    1    6   11   16   21  |  1    6   11   16   21  |  1    6   11   16   21
    2    7   12   17   22  |  2    7   12   17   22  |  2    7   12   17   22
    3    8   13   18   23  |  3    8   13   18   23  |  3    8   13   18   23
    4    9   14   19   24  |  4    9   14   19   24  |  4    9   14   19   24
    5   10   15   20   25  |  5   10   15   20   25  |  5   10   15   20   25
   --------------------------------------------------------------------------
    1    6   11   16   21  |  1    6   11   16   21  |  1    6   11   16   21
    2    7   12   17   22  |  2    7   12   17   22  |  2    7   12   17   22
    3    8   13   18   23  |  3    8   13   18   23  |  3    8   13   18   23
    4    9   14   19   24  |  4    9   14   19   24  |  4    9   14   19   24
    5   10   15   20   25  |  5   10   15   20   25  |  5   10   15   20   25

(Lines added to show the original matrix in the center and the padded copies.) Once you're done rotating, you can crop the middle of the matrix for your final image.

Note that this method also works on 3-channel images.


As @Suever and @BlackAdder note in the comments, this padding can be insufficient for images with large aspect ratio (greater than 25.456:9), particularly for rotations near odd multiples of 45°. You can make the padding more accurate by calculating the maximum you might need.

s = size(img);
s = s(1:2);                      % account for multi-channel images

maxext = sqrt(s * s.');          % calculate length of image diagonal
padsize = ceil((maxext - s)/2);  % find amount of padding needed for each side

padarray(img, padsize, 'circular');

Upvotes: 2

Suever
Suever

Reputation: 65460

I think that the best (and most memory efficient) way of doing this, would be to use interp2 to sample the original image at the new pixel centers (the original pixel centers "rotated" by the opposite of the desired angle). And then to use mod on these sample points to ensure that they fall within the dimension of the original image. And the added benefit of mod is that the new x,y coordinates that are out of range, simply "wrap around" to the other side of the image.

% Load some sample image
load mri 
im = double(D(:,:,12));
[rows, cols] = size(im);

% The original pixel centers
[xx,yy] = meshgrid(1:cols, 1:rows);

% Setup the rotation matrix
theta = pi/4;
R = [cos(-theta), -sin(-theta);
     sin(-theta), cos(-theta)];

% Center of Rotation (center of the image)
center = [cols/2, rows/2];

% Determine the new pixel centers (rotated)
xy = bsxfun(@minus, [xx(:), yy(:)], center) * R;
xy = bsxfun(@plus, xy, center);

% Mod these using the dimensions of the image to "wrap" around
x = mod(xy(:,1) - 1, cols - 1) + 1;
y = mod(xy(:,2) - 1, rows - 1) + 1;

% Sample the original image at the new pixel centers
im2 = interp2(xx, yy, im, x, y);
im2 = reshape(im2, [rows, cols])

Rotation = 45 degrees

enter image description here

This will work with any arbitrary aspect ratio (below is an image demonstrating the issue brought up by @BlackAdder where a repmat [3,3] wouldn't work due to the image being tall and narrow).

Rotation = 90 degrees

enter image description here

This also has the added benefit that it doesn't rely on the Image Processing Toolbox.

Upvotes: 3

Related Questions