Using imrotate without losing quality

I'm in a situation that I need to be able to randomly rotate (0-359 angle degrees) different images. I'm currently using imrotate() but considering that the images are small and the quality is important, I noticed that the images lose their qualities, specially in curve lines. I can still rotate my images 0, 90, 180 and 270 degrees without losing any qualities but I wanted to know if there is any way to rotate an image with more degrees without losing the quality.

11 comentarios

Walter Roberson
Walter Roberson el 12 de Mzo. de 2018
Is this for creating new images or is it just for display purposes?
Milad
Milad el 12 de Mzo. de 2018
Creating new images.
@milad mando: how do you define image rotation "without losing quality"? For example if I have a simple 4x4 grayscale image like this:
im = [0,0;1,1];
please rotate that image exactly 10/3 degrees "without losing quality", and show us what you would expect the output to be.
Walter Roberson
Walter Roberson el 12 de Mzo. de 2018
If the new images need to be the same size as originals then you always loose quality at the other angles. Think of the pigeon hole principle: with other rotations and the same size image, other pixels need to start entering the frame because the angled lines will lead to some pixels from outside the original bounding box to be inside the bounding box of the rotated image. But those new pixels from previously outside take up space in the representation and if you do not permit the rotated image to be larger than the original then pigeon hole principle says that the amount of space available for the original pixels has to get lower. The worst case is rotation by 45 degrees, 135 degrees, etc, in which case half of size is being occupied by information about pixels not originally in the frame.
Milad
Milad el 12 de Mzo. de 2018
My problem isn't the way the rotation work. My problem is the way some images look after the rotation. In some areas like the areas that have curve lines and letters, after the rotation some pixels look out of their places. I wanted to know if there are more good and safe angle degrees that I can use.
Walter Roberson
Walter Roberson el 12 de Mzo. de 2018
No, you always lose quality on a rotation unless you allow the rotated image to be larger than the original or you only use multiples of 90 degrees.
Did you try playing with the parameters of imrotate to choose the different methods of calculating the rotated image?
Milad
Milad el 12 de Mzo. de 2018
Yeah, of course they can't be the same size. My problem is the quality. I've tried with different methods of imrotate(). Not any improvement. I don't want any magic. Just the answer. Which I think I got because you said that the degree should only be a multiple of 90. Thanks.
Walter Roberson
Walter Roberson el 12 de Mzo. de 2018
If the rotated image is permitted to be larger then you can use subpixel type calculation to get arbitrarily good rotated versions.
If it had been a matter of display then the hgtransform functionality would permit the original data and the rotation matrix to be sent to the graphics engine which would use antialiasing techniques on output.
Shafaq
Shafaq el 4 de Jul. de 2024
Editada: Image Analyst el 5 de Jul. de 2024
I want to rotate matrix as well as image and want to show that output is inavriant. Imrotate is affecting invariance so what should I do?
% Generate a random 50x30 matrix A and a 50x1 vector b
A = rand(8, 8);
b = rand(8, 1);
% A=[1 2;3 4];
% b=[1 2]';
% Least squares solution for the original problem
x = (A' * A) \ (A' * b);
theta=90;
theta= deg2rad(theta);
% Rotation matrix for 90 degrees
R = [cos(theta), -sin(theta); sin(theta), cos(theta)];
% Extend the rotation matrix to apply to the whole problem
R_ext = blkdiag(kron(eye(1), R), eye(0)); % Adjust size accordingly
% Rotate the matrix and vector
A_rot = R_ext * A;
Error using *
Incorrect dimensions for matrix multiplication. Check that the number of columns in the first matrix matches the number of rows in the second matrix. To operate on each element of the matrix individually, use TIMES (.*) for elementwise multiplication.
b_rot= R_ext * b;
theta= rad2deg(theta);
A_rot=imrotate(A_rot,theta,'crop');
b_rot=imrotate(b_rot,theta,'crop');
% Display the original and rotated matrices using imagesc
% Least squares solution for the rotated problem
x_rot = (A_rot' * A_rot) \ (A_rot' * b_rot);
% Display results
fprintf('Original least squares solution (first 5 elements):\n');
disp(x(1:end));
fprintf('Rotated least squares solution (first 5 elements):\n');
disp(x_rot(1:end));
% Check invariance
invariance_check = norm(x )- norm(x_rot);
fprintf('Invariance check (should be close to zero): %f\n', invariance_check);
Image Analyst
Image Analyst el 5 de Jul. de 2024
Not sure what all that means. An image IS a matrix. And what do you mean by invariant? Invariant to what?
Why don't you start a new discussion thread and explain it?
If you have any more questions, then attach your data and code to read it in with the paperclip icon after you read this:

Iniciar sesión para comentar.

 Respuesta aceptada

Milad
Milad el 13 de Mzo. de 2018

1 voto

(Thanks to guys for answering and helping me with this question. To sum things up I've decided to write an answer myself.)
It seems that rotation always reduces image quality unless we allow the rotated image to be larger than the original or only use multiples of 90 degrees.
The best option in imrotate() seem to be 'bicubic'. Even without resizing the image it gives a pretty good result.

1 comentario

DGM
DGM el 5 de Jul. de 2024
Editada: DGM el 5 de Jul. de 2024
This is appropriate, but there are conceivable reasons why someone might overlook this fact or otherwise be confused to hear that it's true.
Consider the following rotation of a small test pattern
% a tiny 12x9 checkerboard
A = imread('tinycb.png'); % uint8
% rotate by 90 using two interpolation options
theta = 90;
B = imrotate(A,theta); % output is 9x12
C = imrotate(A,theta,'bilinear');
% upscale to prevent the forum display from
% doing interpolation on the tiny images
B = imresize(B,20,'nearest');
C = imresize(C,20,'nearest');
% display them side by side
montage({B,C},'border',[10 10],'backgroundcolor','m');
What if the angle were off by a small amount?
% the same tiny image
A = imread('tinycb.png');
% angle is off by the tiniest amount
theta = 90 + eps(90) % looks like 90, right?
theta = 90.0000
% rotate as before
B = imrotate(A,theta); % now the output is 10x13
C = imrotate(A,theta,'bilinear');
% upscale as before
B = imresize(B,20,'nearest');
C = imresize(C,20,'nearest');
% display them side by side
montage({B,C},'border',[10 10],'backgroundcolor','m');
% how far off was that?
format long
theta
theta =
90.000000000000014
Depending on how the angles are being obtained, it's possible to run into cases where one only assumes they're hitting 90, but aren't actually. The cause might be rounding error, or it might be as gross as an off-by-one error -- for example:
th = linspace(0,360,1001); % this will hit [0 90 180 270 360]
nnz(mod(th,90) == 0)
ans =
5
versus
th = linspace(0,360,1000); % this only hits 0 and 360
nnz(mod(th,90) == 0)
ans =
2
FWIW, in the case of 90d multiples, imrotate() internally just calls rot90(), so the interpolation options are actually circumvented.

Iniciar sesión para comentar.

Más respuestas (2)

Image Analyst
Image Analyst el 12 de Mzo. de 2018

1 voto

See if using the ‘nearest’ option of imresize gives you something you like better.

2 comentarios

Milad
Milad el 13 de Mzo. de 2018
Of course I've seen your solution! Your answers are the most respected. But as I said, I don't want to use imresize(). And if you meant imrotate(), I've tried its methods too. Which still didn't give good results. I'll try the 'nearest' option of imrotate() once again to see if anything changes.
Image Analyst
Image Analyst el 13 de Mzo. de 2018
Sorry - meant imrotate(). Let me know if that's any better. Otherwise (if not) your only option is to upsample your image like they already suggested.

Iniciar sesión para comentar.

Guillaume
Guillaume el 12 de Mzo. de 2018
As per Walter's comments, the only way you can perform arbitrary rotations without loss of quality if by increasing the number of pixels in the image, so:
supersampled = imresize(yourimage, 4); %use whatever scale you which > 1. imresize uses bicubic by default which is the best.
rotatedimage = imrotate(supersampled, someangle, 'bicubic');

6 comentarios

Milad
Milad el 12 de Mzo. de 2018
I think you misunderstood the part about resizing. He didn't mean increasing the area of the image (the number of pixels won't change).
Guillaume
Guillaume el 12 de Mzo. de 2018
I think it is you who misunderstood. Walter has repeatedly said you need more pixels.
if you do not permit the rotated image to be larger than the original then pigeon hole principle...
...unless you allow the rotated image to be larger...
In any case, what I've implemented above is basic pixel supersampling. This will result in better quality rotated image. As it's been said repeatedly, the only way you can get better quality out of a non-90 degree multiple rotation is by increasing the number of pixels, since some rotated pixels fall in between real pixels if you keep the number constant.
Stephen23
Stephen23 el 12 de Mzo. de 2018
"the number of pixels won't change"
The number of pixels must increase if you want non-90 degree rotation and a better "quality" image. There is no confusion about this.
Milad
Milad el 13 de Mzo. de 2018
imresize() changes the area of images (number of pixels). imrotate() when used with angles that are not multiples of 90 do change the number of pixels but not the actual image, It just adds zero to the areas who are not part of the actual image.
This solution just does not help.
Image Analyst
Image Analyst el 13 de Mzo. de 2018
Did you even TRY or even see my solution (below)? If you just want the image rotated but want sharp edges, not blurry edges, then it might work. Of course you will get jaggies for certain angles, but the edges will be sharper.
Guillaume
Guillaume el 13 de Mzo. de 2018
imresize is used to upsample the image. A feature that was occupying a single pixel now occupy more. Since we use 'bicubic interpolation' you also get antialising. You now have more resolution for your feature, so you loose less quality when you rotate it.

Iniciar sesión para comentar.

Categorías

Más información sobre Read, Write, and Modify Image en Centro de ayuda y File Exchange.

Preguntada:

el 12 de Mzo. de 2018

Comentada:

DGM
el 5 de Jul. de 2024

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by