Rotation de L'Image par Matlab sans imrotate

j'essaie de faire tourner une image avec Matlab sans utiliser la fonction imrotate. Je l'ai fait en utilisant la matrice de transformation.Mais il n'est pas assez bon.Le problème est que l'image pivotée est "coulissante".Laissez-moi vous dire avec des photos.

C'est mon image que je veux faire tourner:

enter image description here

Mais quand je le tourne, par exemple 45 degrés, il devient ceci:

enter image description here

je me demande pourquoi c'est happening.Voici mon code,est-il mathématique ou d'erreur de programmation?

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));
18
demandé sur chappjc 2013-10-30 18:10:37

4 réponses

la raison pour laquelle vous avez des trous dans votre image est que vous calculez l'emplacement dans imagerot de chaque pixel imagepad. Vous devez faire le calcul dans l'autre sens. C'est, pour chaque pixel imagerot interpoler dans imagepad. Pour ce faire, vous avez juste besoin d'appliquer la transformation inverse, dans le cas d'une matrice de rotation est juste la transposée de la matrice (il suffit de changer le signe sur chaque sin et traduire l'autre sens).

boucle sur les pixels 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

notez aussi que votre midx et midy doit être calculé avec size(imagepad,2) et size(imagepad,1) respectivement, puisque la première dimension se réfère au nombre de lignes (hauteur) et la seconde à la largeur.

NOTE: la même approche s'applique lorsque vous décidez d'adopter un schéma d'interpolation autre que celui du voisin le plus proche, comme dans L'exemple de Rody avec interpolation linéaire.

EDIT: je suppose que vous utilisez une boucle pour des fins de démonstration, mais dans la pratique, il n'est pas nécessaire pour les boucles. Voici un exemple d'interpolation du voisin le plus proche (ce que vous utilisez), en gardant la même image de taille, mais vous pouvez modifier ceci pour produire une image plus grande qui inclut l'image source entière:

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)

pour modifier ce qui précède en interpolation linéaire, calculer les 4 pixels voisins à chaque coordonnée dans XYt et effectuer une somme pondérée en utilisant le produit des composants fractionnels comme poids. Je vais laisser ce comme un exercice, car il ne ferait que gonfler ma réponse au-delà de la portée de votre question. :)

20
répondu chappjc 2013-10-30 18:40:10

la méthode que vous utilisez (rotation par échantillonnage) est la plus rapide et la plus simple, mais aussi la moins précise.

Rotation par cartographie de zone, comme indiqué ci-dessous ( est une bonne référence), est beaucoup mieux à la préservation de la couleur.

mais: notez que cela ne fonctionnera que sur les images à l'échelle de gris/RGB, mais pas sur les images en mode colormapped comme celle que vous semblez utiliser.

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);

Sortie:

enter image description here

11
répondu Rody Oldenhuis 2013-10-30 17:04:05

rotation de l'image colorée selon l'angle donné par l'utilisateur sans aucun recadrage de l'image dans matlab.

la sortie de ce programme est similaire à la sortie de la commande intégrée "imrotate" .Ce programme crée dynamiquement le fond en fonction de l'angle d'entrée donné par user.By en utilisant la matrice de rotation et le déplacement de l'origine, nous obtenons la relation entre les coordonnées de l'image initiale et de l'image finale.En utilisant la relation entre les coordonnées de l'image initiale et de l'image finale, nous cartographions maintenant les valeurs d'intensité pour chaque 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);
7
répondu Goutham 2014-11-18 18:14:51

Vérifier cela.

c'est le moyen le plus rapide que vous pouvez faire. this is the output

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);
1
répondu Sadegh Teimori 2015-06-08 07:13:44