matlab rotation translation image-rotation

I imrotate() una imagen, dibujar dos líneas, rotar las líneas hacia atrás y dibujarlas en una imagen original, pero ¿no obtienes el resultado esperado en MATLAB?



rotation translation (5)

Puede que no lo arregle, pero intente definir su matriz como:

R=[ ... cosd(t) -sind(t) -sind(t) -cosd(t) ];

Al trazar una imagen, debe cuidar el eje Y, que pasa automáticamente de arriba hacia abajo.

Lo que quiero hacer :

Supongamos que tengo una imagen I que giro -45 ° usando imrotate (obtengo I_R ). Luego dibujo dos líneas AB y CD (paralelos). Finalmente, giro las dos líneas hacia atrás ( 45 ° ) y las dibujo en la imagen original I

Cómo hago eso ##

imrotate() I usando la función MATLAB imrotate() :

I_R = imrotate(I,-45);

De la ayuda de Matlab, obtengo: B = imrotate (A, ángulo) gira la imagen A en grados en sentido antihorario alrededor de su punto central.

¡Pero parece que imrotate agrega una traducción a la imagen! He leído el código de la función incorporada de matlab, parece que usa una función llamada getOutputBound para comprobar si la imagen girada cabe en la figura. ¡Esta traducción es lo que estoy buscando!

Los cuatro puntos A,B,C,D forman dos líneas paralelas AB y CD .

A = [x_A; u]; B = [x_B; u]; C = [x_A; d]; D = [x_B; d];

Así que ahora, giro las dos líneas, utilizo mi función rotateTwoPoints() , simplemente llamando a las dos líneas siguientes:

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

Donde O es el origen alrededor del cual la rotación será.

  • He intentado O = [0;0] Quiero decir que es el origen de la trama. Sin éxito !
  • Entonces elijo O el centroide de la imagen I usando regionprops(I,"Centroid") . Estaba mal porque el centroide no es un centro.
  • Ahora, uso el centro de la imagen O = floor(size(I)/2+0.5)'' o usando ceil !

Pero cuando dibujo las líneas resultantes AfBf y CfDf en la imagen I gusta esto:

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

¡Obtuve un resultado que no es correcto!

Problema : En I_R , AB & CD contiene lo que yo llamo BlueZone (ver imagen 3). ¡Pero las líneas posteriores giradas AfBf y CfDf no lo cubren!

Los resultados en Imágenes

Aquí está la imagen girada I_R y las dos líneas dibujadas (las dos líneas rojas medias corresponden a AB y CD ):

Luego dibujo las líneas giradas AfBf y CfDf en la imagen original I (el punto negro en negrita corresponde al centro en el que hice la rotación):

IMAGEN ACTUALIZADA

Problema : Como puede ver, BlueZone estaba dentro de las dos líneas AB y CD . Pero cuando se gira hacia atrás, queda afuera, como se muestra en la siguiente imagen (las flechas rojas apuntan a BlueZone ):

ACTUALIZACIÓN AGREGADA un SNIPPET

Como mi problema aún no se resolvió, seleccioné el código que causa el problema y lo agregué como el siguiente fragmento (hay una variable almacenada en un archivo que puede descargar aquí ):

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

PD: estoy usando MATLAB R2012b


Como dices, la rotación se calcula correctamente, como se muestra en el primer gráfico. El problema entonces es solo con la visualización final de los resultados. Cuando haces esto

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

tiene un error tipográfico en la segunda línea (segundo elemento del segundo argumento) - está trazando Bf(2) como el final de la segunda línea en lugar de Df(2) . Cuando reemplacé esto con Df(2) trazó líneas paralelas como se esperaba.

ACTUALIZAR:

En los comentarios sugerí refactorizar este código para usar matrices de transformación para todo, de modo que el mismo conjunto de transformaciones se pueda aplicar tanto a la imagen como a las superposiciones. Aquí hay un resumen genérico de cómo puede configurarlo.

Hay dos puntos principales a tener en cuenta.

  1. La convención de Matlab con imágenes es que y = 0 es la parte superior. imshow y related then pon y = 0 en la parte superior yy aumentando en la gráfica. Esta es la convención opuesta a la plot , por lo que cuando superpone tramas e imágenes, una de ellas debe invertirse. Esto tiene consecuencias para el uso de matrices de transformación, la principal es que el ángulo de rotación debe invertirse.

  2. Las imágenes en matlab se pueden considerar como los datos z para una cuadrícula regular de píxeles. Sin embargo, esas coordenadas de píxeles no se almacenan, solo se deducen cuando muestra la imagen. En consecuencia, cuando imshow una imagen y luego la imshow a imshow , la traducción no es evidente, ya que vuelve a infundir un nuevo conjunto de coordenadas de píxeles que son las mismas que las de la imagen no transformada. Para evitar esto, debemos arreglar referencias espaciales a una imagen.

Además de esto, las transformaciones 2d se llevan a cabo utilizando matrices de 3 espacios, por lo que necesitamos definir puntos de salida en 3space (pero luego truncarlos para visualizarlos en diagramas 2d).

Así que vamos a ponerlo todo junto.

% get an image I = imread(''cameraman.tif''); % get spatial referencing information Rcb = imref2d(size(I)); % define some test points in 3space pta = [10; 10; 0]; ptb = [ 50; 10; 0]; % construct a test line in 2space from our test points testline = [pta(1:2) ptb(1:2)]; % overlay line on plot figure(90); clf imshow(I,Rcb); truesize; hold on; plot(testline(1, :), testline(2, :), ''y'', ''linewidth'', 4) % define our transforms % rotation angle (deg) t = 45; % a transform suitable for images Rimage=[ ... cosd(t) -sind(t) 0 sind(t) cosd(t) 0 0 0 1 ]; % the same transform suitable for points Rpoints=[ ... cosd(-t) -sind(-t) 0 sind(-t) cosd(-t) 0 0 0 1 ]; % make tform object suitable for imwarp tform = affine2d(Rimage); % transform image and spatial referencing with tform [Ir, Rr] = imwarp(I, tform); % transform points directly using matrix multplication ptar = Rpoints*pta; ptbr = Rpoints*ptb; % construct the rotated line for plotting newline = [ptar(1:2) ptbr(1:2)]; % the results figure(91); clf imshow(Ir, Rr); truesize; hold on; plot(testline(1, :), testline(2, :), ''y'', ''linewidth'', 4) plot(newline(1, :), newline(2, :), ''g'', ''linewidth'', 4)

En el segundo gráfico, tracé la línea transormada en verde y la línea original en amarillo, para comparar.

Puntos a tener en cuenta:

  1. La función imwarp no usa la matriz de rotación directamente, primero tiene que construir un objeto tform y luego suministrar eso. Por supuesto, puede hacer todo esto en una sola línea.

  2. Tener dos matrices es un poco poco elegante. Aquí está bien, donde solo tenemos que preocuparnos por una sola rotación, pero el objetivo de usar matrices de transformación es que puedes encadenar una secuencia de transformaciones simplemente multiplicando las matrices. Si tiene que hacer esto dos veces, estropearía una pieza de código que de otro modo sería elegante, y eso nunca funcionaría, así que probablemente la forma más limpia de hacerlo sería voltear sus imágenes al inicio de todo el proceso, y luego voltearlas de nuevo al al final si es necesario (para exportar, por ejemplo).

  3. La contabilidad para los datos de puntos es algo tediosa. Hay muchas maneras de hacerlo, dependiendo de las convenciones que elija adoptar con respecto a qué coordenada se mantiene en qué posición en los vectores de columna. Nunca he encontrado un conjunto que funcione bien con las transformaciones y el plot 3space, y lo que funciona mejor cambia según la aplicación. Las funciones de ayuda pueden ahorrarle algunos dolores de cabeza, si no es el próximo mantenedor, y envolverlo todo en una clase es lo mejor, si puede justificar el tiempo.

ACTUALIZACIÓN2:

Para minimizar el uso de las coordenadas de 3 espacios, simplemente usaría vectores de 2 espacios para describir todos sus puntos, como es normal, y luego agregaría la coordenada z ficticia solo cuando necesite realizar la transformación.

Entonces podrías tener

testpoint = [1; 5]; % x and y xoordinates only trpoint = Rpoints*[testpoint; 1]; trpoint = trpoint(1:2);

Puedes poner esto en un contenedor, pero no hay forma de imwarp el hecho de que necesitas usar una matriz de 3x3 para la sección imwarp , lo que significa que necesitas especificar tus coordenadas en 3space también.

Alternativamente, podría truncar la matriz de rotación para la transformación de coordenadas:

trpoint = Rpoints(1:2, 1:2)*testpoint;

pero de una manera u otra tendrás que hacer cierta contabilidad de índices.

ACTUALIZACIÓN3:

El OP no tiene acceso a imref2d , por lo que aquí hay una forma estrafalaria de lograr el mismo resultado. La línea importante es esta

imshow(Ir, Rr);

donde Rr es el objeto de referencia spstial emitido por la función imwarp . Si no tiene esto, puede proporcionar referencias espaciales para imshow manualmente con los ''XData'' e ''YData'' . Primero debe calcular las extensiones y decidir una convención. imref2d utiliza la convención de (0,0) como superior izquierda y cuando se gira la imagen, esta esquina de la imagen original permanece como coordenada (0,0), de modo que la imagen girada ahora se extiende desde y = [- 181: 181] y x = [0: 363]. Para obtener estos valores, debe transformar las cuatro esquinas de la imagen y luego calcular los máximos y mínimos.

xmax = size(I,2); ymax = size(I,2); corner1 = [xmax; 0; 0]+0.5; corner2 = [xmax; ymax; 0]+0.5; corner3 = [0; ymax; 0]+0.5; corner4 = [0; 0; 0]+0.5; tc1 = Rpoints*corner1; tc2 = Rpoints*corner2; tc3 = Rpoints*corner3; tc4 = Rpoints*corner4; corners = [tc1 tc2 tc3 tc4]; xlims = minmax(corners(1,:)); ylims = minmax(corners(2,:));

a continuación, puede reemplazar la línea imshow con este

imshow(Ir, ''xdata'', xlims, ''ydata'', ylims);

todo lo demás debería ser igual.

Tenga en cuenta que, cuando hice todo esto, hubo una ligera diferencia entre los valores que obtuve arriba y los producidos por imwarp en el objeto imref2d . Esa función regresó

XWorldLimits: [0.2264 363.2264] YWorldLimits: [-181.5000 181.5000]

Mientras que el mío da

xlims: [0.7071 362.7458]; ylims: [-181.0193 181.0193];

No puedo explicar esto sin buscar en la fuente de imwarp e, incluso si no es MEX en ese nivel, no estoy seguro de qué tan lejos podrías llegar antes de que puedas ser acusado de infracción de la propiedad intelectual.

Estos números representan la ubicación de la imagen en los ejes, por lo que si usa la imagen para elegir puntos, puede que estén desactivados unas décimas de píxel. Si solo está usando la imagen como referencia, entonces debería estar lo suficientemente cerca.


Puede que esté malinterpretando algo, pero lo que quiere hacer es girar una imagen, dibujar dos líneas y luego volver a girar todo, incluidas las dos líneas, ¿verdad?

Si es así, supongo que la forma más fácil de convertir las dos líneas sería traducirlas a coordenadas polares usando car2pol. http://se.mathworks.com/help/matlab/ref/cart2pol.html

Entonces debería ser fácil girar las líneas. Avísame si malinterpreté algo.

editar: Intenté hacer un código de ejemplo, aparentemente estoy demasiado cansado para pensar correctamente y hay algún error, pero creo que la idea es clara. Además, por favor, no use estructuras como lo hice, solo pensé que sería la manera más fácil de nombrar las variables.

%% Load picture close all [pic] = dicomread(''C0011866_00094.DCM''); %% Get four points figure, imshow(pic,[]); title(''Select four points''); hold on; [x,y] = ginput; %% Plot the lines on top of the figure hold on plot(x(1:2),y(1:2),''b''); hold on plot(x(3:4),y(3:4),''r''); %% Define the lines %In cartesian coordinates line1.start.cart = [x(1),y(1)]; line1.end.cart = [x(2),y(2)]; line2.start.cart = [x(3),y(3)]; line2.end.cart = [x(4),y(4)]; %Middle of picture axises=axis; center = [mean(axises(1:2)),mean(axises(3:4))]; plot(center(1),center(2),''ro'') %In polar coordinates from center [angle,radius] [line1.start.pol(1),line1.start.pol(2)] = cart2pol(line1.start.cart(1)-center(1),line1.start.cart(2)-center(2)); [line1.end.pol(1),line1.end.pol(2)] = cart2pol(line1.end.cart(1)-center(1),line1.end.cart(2)-center(2)); [line2.start.pol(1),line2.start.pol(2)] = cart2pol(line2.start.cart(1)-center(1),line2.start.cart(2)-center(2)); [line2.end.pol(1),line2.end.pol(2)] = cart2pol(line2.end.cart(1)-center(1),line2.end.cart(2)-center(2)); %% Rotate the image a degrees a = 10; newpic = imrotate(pic,a); %% Rotate the lines line1.start.pol(1) = line1.start.pol(1) + a; line1.end.pol(1) = line1.end.pol(1) + a; line2.start.pol(1) = line2.start.pol(1) + a; line2.end.pol(1) = line2.end.pol(1) + a; %% Transform the coordinates back to cartesian [line1.start.cart(1), line1.start.cart(2)] = pol2cart(line1.start.pol(1),line1.start.pol(2)); line1.start.cart = line1.start.cart+center; line1.end.cart = line1.end.cart+center; [line1.end.cart(1), line1.end.cart(2)] = pol2cart(line1.end.pol(1),line1.end.pol(2)); line2.start.cart = line2.start.cart+center; line2.end.cart = line2.end.cart+center; [line2.start.cart(1), line2.start.cart(2)] = pol2cart(line2.start.pol(1),line2.start.pol(2)); [line2.end.cart(1), line2.end.cart(2)] = pol2cart(line2.end.pol(1),line2.end.pol(2)); %% Plot it again figure imshow(newpic,[]); hold on plot([line1.start.cart(1),line1.end.cart(1)],[line1.start.cart(2),line1.end.cart(2)]) hold on plot([line2.start.cart(1),line2.end.cart(1)],[line2.start.cart(2),line2.end.cart(2)]) hold on plot(center(2),center(1),''ro'')


¡Encontré la solución!

Bueno, lo que sucede es que la función imrotate no solo rota por defecto la imagen, sino que también hace una traducción para que la imagen girada encaje en la figura.

la solución es usar:

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

el parámetro importante aquí es ''crop'' (bbox):

B = imrotate (A, ángulo, método, bbox) gira la imagen A, donde bbox especifica el tamaño de la imagen devuelta. bbox es una cadena de texto que puede tener uno de los siguientes valores. El valor predeterminado está entre llaves ({}).

''recortar'' Hace que la imagen de salida B tenga el mismo tamaño que la imagen de entrada A, recortando la imagen girada para que quepa

{''loose''} Hace que la imagen de salida B sea lo suficientemente grande como para contener toda la imagen girada. B es generalmente más grande que A.

de la ayuda de la función imrotate aquí .


1) tienes imagen I

2) rotó la imagen I sobre su centro (-45 grados) => I_R está girando la imagen

3) dibujas dos líneas paralelas en I_R (línea 1 y línea 2)

4) rotar líneas con respecto al centro de imge I

El paso número 4 es incorrecto, debes elegir el centro de la imagen I_R para el centro de rotación .

Desde Matlab Docs: por defecto, imrotate crea una imagen de salida lo suficientemente grande como para incluir toda la imagen original. los píxeles que quedan fuera del límite de la imagen original se establecen en 0 y aparecen como fondo negro en la imagen de salida.

>

de los comentarios: 1) rotó la imagen sobre el punto central de "I" (-45degree)

2) cuando haces esto usando imrotate, la función gira y traduce la imagen principal y genera "I_R",

3) ¡ entonces el punto central de I_R es el punto central de "I" + alguna traducción! .

4) entonces el principal problema es calcular la cantidad de traducción ,

5) para hacer esto puede usar esto: Cálculo del valor de traducción y el ángulo de rotación de una imagen 2D rotada o esta: http://angeljohnsy.blogspot.com/2011/06/image-rotation.html o

6) simplemente puede usar algunas marcas en su imagen original (por ejemplo, marcar en el centro de la imagen original) para ver cuánto se tradujo (o para ver el centro de I_R directamente) y utilizar este centro para la rotación hacia atrás de las líneas.

Espero que encuentres una buena forma de calcular la traducción, incluso si puedes escribir tu propio script "image_rotation", no es tan difícil.