Image rotation by Matlab without using imrotate

匿名 (未验证) 提交于 2019-12-03 02:11:02

问题:

I am trying to rotate an image with Matlab without using imrotate function. I actually made it by using transformation matrix.But it is not good enough.The problem is, the rotated image is "sliding".Let me tell you with pictures.

This is my image which I want to rotate:

But when I rotate it ,for example 45 degrees, it becomes this:

I am asking why this is happening.Here is my code,is there any mathematical or programming mistakes about it?

image=torso;  %image padding [Rows, Cols] = size(image);  Diagonal = sqrt(Rows^2 + Cols^2);  RowPad = ceil(Diagonal - Rows) + 2; ColPad = ceil(Diagonal - Cols) + 2; imagepad = zeros(Rows+RowPad, Cols+ColPad); imagepad(ceil(RowPad/2):(ceil(RowPad/2)+Rows-1),ceil(ColPad/2):(ceil(ColPad/2)+Cols-1)) = image;  degree=45;  %midpoints midx=ceil((size(imagepad,1)+1)/2); midy=ceil((size(imagepad,2)+1)/2);  imagerot=zeros(size(imagepad));  %rotation for i=1:size(imagepad,1)     for j=1:size(imagepad,2)           x=(i-midx)*cos(degree)-(j-midy)*sin(degree);          y=(i-midx)*sin(degree)+(j-midy)*cos(degree);          x=round(x)+midx;          y=round(y)+midy;           if (x>=1 && y>=1)               imagerot(x,y)=imagepad(i,j); % k degrees rotated image                   end      end end   figure,imagesc(imagerot);  colormap(gray(256));

回答1:

The reason you have holes in your image is because you are computing the location in imagerot of each pixel in imagepad. You need to do the computation the other way around. That is, for each pixel in imagerot interpolate in imagepad. To do this, you just need to apply the inverse transform, which in the case of a rotation matrix is just the transpose of the matrix (just change the sign on each sin and translate the other way).

Loop over pixels in imagerot:

imagerot=zeros(size(imagepad)); % midx and midy same for both  for i=1:size(imagerot,1)     for j=1:size(imagerot,2)           x= (i-midx)*cos(rads)+(j-midy)*sin(rads);          y=-(i-midx)*sin(rads)+(j-midy)*cos(rads);          x=round(x)+midx;          y=round(y)+midy;           if (x>=1 && y>=1 && x<=size(imagepad,2) && y<=size(imagepad,1))               imagerot(i,j)=imagepad(x,y); % k degrees rotated image                   end      end end

Also note that your midx and midy need to be calculated with size(imagepad,2) and size(imagepad,1) respectively, since the first dimension refers to the number of rows (height) and the second to width.

NOTE: The same approach applies when you decide to adopt an interpolation scheme other than nearest neighbor, as in Rody's example with linear interpolation.

EDIT: I'm assuming you are using a loop for demonstrative purposes, but in practice there is no need for loops. Here's an example of nearest neighbor interpolation (what you are using), keeping the same size image, but you can modify this to produce a larger image that includes the whole source image:

imagepad = imread('peppers.png'); [nrows ncols nslices] = size(imagepad); midx=ceil((ncols+1)/2); midy=ceil((nrows+1)/2);  Mr = [cos(pi/4) sin(pi/4); -sin(pi/4) cos(pi/4)]; % e.g. 45 degree rotation  % rotate about center [X Y] = meshgrid(1:ncols,1:nrows); XYt = [X(:)-midx Y(:)-midy]*Mr; XYt = bsxfun(@plus,XYt,[midx midy]);  xout = round(XYt(:,1)); yout = round(XYt(:,2)); % nearest neighbor! outbound = yout<1 | yout>nrows | xout<1 | xout>ncols; zout=repmat(cat(3,1,2,3),nrows,ncols,1); zout=zout(:); xout(xout<1) = 1; xout(xout>ncols) = ncols; yout(yout<1) = 1; yout(yout>nrows) = nrows; xout = repmat(xout,[3 1]); yout = repmat(yout,[3 1]); imagerot = imagepad(sub2ind(size(imagepad),yout,xout,zout(:))); % lookup imagerot = reshape(imagerot,size(imagepad)); imagerot(repmat(outbound,[1 1 3])) = 0; % set background value to [0 0 0] (black)

To modify the above to linear interpolation, compute the 4 neighboring pixels to each coordinate in XYt and perform a weighted sum using the fractional components product as the weights. I'll leave that as an exercise, since it would only serve to bloat my answer further beyond the scope of your question. :)



回答2:

The method you are using (rotate by sampling) is the fastest and simplest, but also the least accurate.

Rotation by area mapping, as given below (this is a good reference), is much better at preserving color.

But: note that this will only work on greyscale/RGB images, but NOT on colormapped images like the one you seem to be using.

image = imread('peppers.png');  figure(1), clf, hold on subplot(1,2,1) imshow(image);  degree = 45;  switch mod(degree, 360)     % Special cases     case 0         imagerot = image;     case 90         imagerot = rot90(image);     case 180         imagerot = image(end:-1:1, end:-1:1);     case 270         imagerot = rot90(image(end:-1:1, end:-1:1));      % General rotations     otherwise          % Convert to radians and create transformation matrix         a = degree*pi/180;         R = [+cos(a) +sin(a); -sin(a) +cos(a)];          % Figure out the size of the transformed image         [m,n,p] = size(image);         dest = round( [1 1; 1 n; m 1; m n]*R );         dest = bsxfun(@minus, dest, min(dest)) + 1;         imagerot = zeros([max(dest) p],class(image));          % Map all pixels of the transformed image to the original image         for ii = 1:size(imagerot,1)             for jj = 1:size(imagerot,2)                 source = ([ii jj]-dest(1,:))*R.';                 if all(source >= 1) && all(source <= [m n])                      % Get all 4 surrounding pixels                     C = ceil(source);                     F = floor(source);                      % Compute the relative areas                     A = [...                         ((C(2)-source(2))*(C(1)-source(1))),...                         ((source(2)-F(2))*(source(1)-F(1)));                         ((C(2)-source(2))*(source(1)-F(1))),...                         ((source(2)-F(2))*(C(1)-source(1)))];                      % Extract colors and re-scale them relative to area                     cols = bsxfun(@times, A, double(image(F(1):C(1),F(2):C(2),:)));                      % Assign                                          imagerot(ii,jj,:) = sum(sum(cols),2);                  end             end         end         end  subplot(1,2,2) imshow(imagerot);

Output:



回答3:

Rotates colored image according to angle given by user without any cropping of image in matlab.

Output of this program is similar to output of inbuilt command "imrotate" .This program dynamically creates background according to angle input given by user.By using rotation matrix and origin shifting, we get relation between coordinates of initial and final image.Using relation between coordinates of initial and final image, we now map the intensity values for each pixel.

img=imread('img.jpg');   [rowsi,colsi,z]= size(img);   angle=45;  rads=2*pi*angle/360;    %calculating array dimesions such that  rotated image gets fit in it exactly. % we are using absolute so that we get  positve value in any case ie.,any quadrant.  rowsf=ceil(rowsi*abs(cos(rads))+colsi*abs(sin(rads)));                       colsf=ceil(rowsi*abs(sin(rads))+colsi*abs(cos(rads)));                       % define an array withcalculated dimensionsand fill the array  with zeros ie.,black C=uint8(zeros([rowsf colsf 3 ]));  %calculating center of original and final image xo=ceil(rowsi/2);                                                             yo=ceil(colsi/2);  midx=ceil((size(C,1))/2); midy=ceil((size(C,2))/2);  % in this loop we calculate corresponding coordinates of pixel of A  % for each pixel of C, and its intensity will be  assigned after checking % weather it lie in the bound of A (original image) for i=1:size(C,1)     for j=1:size(C,2)                                                                  x= (i-midx)*cos(rads)+(j-midy)*sin(rads);                                                 y= -(i-midx)*sin(rads)+(j-midy)*cos(rads);                                       x=round(x)+xo;          y=round(y)+yo;           if (x>=1 && y>=1 && x<=size(img,1) &&  y<=size(img,2) )                C(i,j,:)=img(x,y,:);            end      end end  imshow(C);


回答4:

Check this out.

this is fastest way that you can do.

img = imread('Koala.jpg');  theta = pi/10; rmat = [ cos(theta) sin(theta) 0 -sin(theta) cos(theta) 0 0           0          1];  mx = size(img,2); my = size(img,1); corners = [     0  0  1     mx 0  1     0  my 1     mx my 1]; new_c = corners*rmat;  T = maketform('affine', rmat);   %# represents translation img2 = imtransform(img, T, ...     'XData',[min(new_c(:,1)) max(new_c(:,1))],...     'YData',[min(new_c(:,2)) max(new_c(:,2))]); subplot(121), imshow(img); subplot(122), imshow(img2);


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!