Reputation: 13673
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
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
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
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
This also has the added benefit that it doesn't rely on the Image Processing Toolbox.
Upvotes: 3