Search code examples
matlabrotationtranslationimage-rotation

I imrotate() an image, draw two lines, rotate back the lines and draw them in orginal image, but don't get the expected result in MATLAB?


What I want to do :

Suppose I have an image I that I rotate -45° using imrotate (I get I_R). Then I draw two lines AB and CD (parallels). Finally, I rotate the two lines back (45°) and draw them in the original image I.

How I do that ##

I rotate I using the MATLAB function imrotate():

I_R = imrotate(I,-45);

From Matlab help, I get : B = imrotate(A,angle) rotates image A by angle degrees in a counterclockwise direction around its center point.

But it seems that imrotate add a translation to the image ! I have read the code of built-in matlab function, it seems that it uses a function called getOutputBound to check if the rotated image will fit in the figure. This translation is what I am looking for !!

The four points A,B,C,D form a two parallels lines AB & CD.

A = [x_A; u];
B = [x_B; u];

C = [x_A; d];
D = [x_B; d];

So now , I rotate the two lines, I use my function rotateTwoPoints(), by simply calling the following two lines :

[Af,Bf] = rotateTwoPoints(A,B,-45,O,true);
[Cf,Df] = rotateTwoPoints(C,D,-45,O,true);

Where O is the origin around which the rotation will be.

  • I have tried O = [0;0] I mean it is the origin of the plot. No success !
  • So I choose O the centroid of the image I using regionprops(I,"Centroid"). It was wrong because the centroid is not a center.
  • Now, I use the center of the image O = floor(size(I)/2+0.5)' or using ceil !

But when I draw the resulting lines AfBf & CfDf in image I like this :

plot([Af(1) Bf(1)],[Af(2) Bf(2)],'k');
plot([Cf(1) Df(1)],[Cf(2) Df(2)],'k'); 

I get a result that is not correct !

Problem : In I_R, the AB & CD contain what I call the BlueZone (see image 3). But the rotated back lines AfBf & CfDf do not cover it !

The results in Images

Here is the rotated image I_R and the two lines drawn (The two middle red lines correspond to AB and CD) :

The two middle lines correspond to AB and CD

I then draw the rotated lines AfBf & CfDf in original image I (the black bold point correspond to the center on which I have done the rotation) :

IMAGE UPDATED enter image description here

Problem : As you can see the BlueZone was inside the two lines AB and CD. But when rotated back it become outside, as shown in the following image (red arrows point to BlueZone) :

enter image description here


UPDATE ADDED a SNIPPET

Since my problem is not yet resolved , I selected the code that causes the problem and I add it as the following snippet (there is a variable stored in a file that you can download here) :

function Question()

% load image in I, the image is available online in the below link  
load I ;

% rotate I with -45° using imrotate
I_R = imrotate(I,-45);

% some data
x_A = 3 ;
x_B = 79;

u = 24;
d = 44;

% some meaningful Points : A,B,C and D that form two lines AB and CD
% parallels
A = [x_A; u];
B = [x_B; u];

C = [x_A; d];
D = [x_B; d];

% figure 1 contain two subplots 
figure(1);
% draw rotated image I_R
subplot(1,2,1), axis image, imagesc(I_R), hold on;
% draw two lines AB and CD in red in rotated image 
plot([A(1) B(1)],[A(2) B(2)],'r');
plot([C(1) D(1)],[C(2) D(2)],'r');
title('I_R the rotated image with the two lines AB and CD');

% draw original image I
subplot(1,2,2), axis image, imagesc(I)  , hold on;

% compute the middle of image I
axises=axis;
center = [mean(axises(1:2)),mean(axises(3:4))]';
% draw the center in red and as a point
plot(center(1),center(2),'ro');

% rotate the two lines, the result is the two lines AfBf and CfDf
[Af,Bf] = rotateTwoPoints(A,B,-45,center,true);
[Cf,Df] = rotateTwoPoints(C,D,-45,center,true);

% draw the rotated back lines in original image I
figure(1);
subplot(1,2,2);
plot([Af(1) Bf(1)],[Af(2) Bf(2)],'k');
plot([Cf(1) Df(1)],[Cf(2) Df(2)],'k');
title('the original image I with the two lines AfBf and CfDf');

function [Af,Bf] = rotateTwoPoints (A,B,t,Origin,isPlot)

% Definition of the rotation matrix (rotation around origin)
R=[ ...
    cosd(t) -sind(t)
    sind(t) cosd(t)
    ];

% translation 
At = A - Origin;
Bt = B - Origin;

% rotation of the points A and B
Ar = R*At;
Br = R*Bt;

% translation 
Af = Ar + Origin;
Bf = Br + Origin;

if isPlot == true

    figure(100)

    % Plot of the original line
    plot(A(1),A(2),'k*', B(1),B(2),'b*');
    line([A(1) B(1)],[A(2) B(2)], 'Color','r');

    grid on
    hold on

    % Plot the Origin around which the rotation will be
    plot(Origin(1),Origin(2),'k*','LineWidth',3);

    % Plot of the rotated line
    plot(Af(1),Af(2),'g*', Bf(1),Bf(2),'r*');
    line([Af(1) Bf(1)],[Af(2) Bf(2)], 'Color','b');
    legend('A','B','line AB','Origin','Af','Bf','line AfBf',['angle: ',num2str(t)],'Location','northeastoutside');
    daspect([1 1 1])

end

PS: I am using MATLAB R2012b


Solution

  • I found the solution !

    Well, what happens is that the built-in function imrotate does not only rotate by default the image, but it does also a translation so that the rotated-image fit in the figure.

    the solution is to use :

    I_R = imrotate(I,-45,'nearest','crop');
    

    the important parameter here is 'crop' (bbox) :

    B = imrotate(A,angle,method,bbox) rotates image A, where bbox specifies the size of the returned image. bbox is a text string that can have one of the following values. The default value is enclosed in braces ({}).

    'crop' Make output image B the same size as the input image A, cropping the rotated image to fit

    {'loose'} Make output image B large enough to contain the entire rotated image. B is generally larger than A.

    from the help of the function imrotate here.