[C con Clase] [Windows API] Transformación Afín

Steven Davidson srd4121 en njit.edu
Sab Abr 14 06:09:22 CEST 2012


Hola Lourdes,

On 4/12/2012 11:32 PM, Lourdes Celene Haros Becerra wrote:
> Muchas gracias Steven, pero tal vez no me di a entender, trataré de
> detallar más mi pregunta:
>
> Creo que lo de checar si hay pixel ahí, si no para pintar negro, el
> programa ya lo hace porque sí estamos manejando coordenadas y tenemos
> una imagen que estamos repintando cada vez que se mueve, por tanto
> con los pixeles no tenemos problemas.
>
> Entonces especificamente queremos saber el orden de la multiplicacion
> de las matrices de transformación para que la imagen se pueda
> trasladar arriba-abajo-izquierda-derecha pero tambien pueda rotar con
> respecto a un punto fuera de la imagen sin que éste se desplace al
> realizar la traslacion.
>

En principio, deberás aplicar una o varias traslaciones. Posteriormente, 
la rotación centrada en un punto en particular equivale a una traslación 
de tal centro, C, al origen: T(-Cx,-Cy), la rotación: R(alfa), seguida 
de una traslación desde el origen a ese centro: T(Cx,Cy). Al final, 
obtendremos la siguiente matriz:

T = traslación arriba, abajo, izquierda, y/o derecha

R(C,alfa) = T(-Cx,-Cy) * R(alfa) * T(Cx,Cy)

M = T * R(C,alfa)

Esta matriz funcionará correctamente si usas "matrices-fila"; es decir, 
la información de cada vértice se guarda en una fila. Esto implicará que 
la multiplicación matricial se realizará así:

pixel_nuevo = pixel_original * M

que viene a ser,

(x' y' 1) = (x y 1) * M

De todas maneras, como expliqué en mi correo-e anterior, es mejor 
aplicar el proceso inverso y por tanto, necesitas calcular la inversa de 
la matriz resultante, M; esto es,

M' : inversa de M

(x y 1) = (x' y' 1) * M'

> Nuestro problema es el siguiente:
> Siendo:
> T: Traslación de la imagen fuente
> S: Escalación de la imagen fuente
> R: Rotación de la imagen fuente
> Tc: Traslación al centro de la imagen fuente
> Tic: Traslación inversa de la anterior
> Tcd: Traslación de la imagen fuente al centro de la imagen destino
> Ticd: Traslación inversa de la anterior Rd: Rotación de la imagen
> fuente respecto al centro de la imagen destino
>
> Tenemos:
> CMatrix3D T,R,Tc,Tic,Tcdest,Ticdest,Rdest,S,Sdest;
> CMatrix3D::Rotation(Rd, g_Thetadest); CMatrix3D::Rotation(R, g_Theta);
> CMatrix3D::Traslation(T,(int)g_Tx,(int)g_Ty);
> CMatrix3D::Traslation(Tc,-(int)g_pImagenSource->SizeX()/2,-(int)g_pImagenSource->SizeY()/2);
> CMatrix3D::Traslation(Tic,g_pImagenSource->SizeX()/2,g_pImagenSource->SizeY()/2);
> CMatrix3D::Traslation(Tcd,-(int)g_pImagen->SizeX()/2,-(int)g_pImagen->SizeY()/2);
> CMatrix3D::Traslation(Ticd,g_pImagen->SizeX()/2,g_pImagen->SizeY()/2);
> CMatrix3D::Scalation(S,g_Zoom,g_Zoom);
>

En primer lugar, no es necesario hacer un cásting a 'int', porque la 
división entre enteros resulta en otro entero. Como estás dividiendo 
entre dos, sugiero usar la operación de desplazamiento a la derecha a 
nivel de bits: >>. Como además realizas estas divisiones varias veces, 
sugiero usar una variable para guardar cada resultado en lugar de estar 
invocando 'SizeX()' y 'SizeY()' constantemente para dividirlos. Al 
final, tendrías esto,

int nMitadAnchuraOrigen = g_pImagenSource->SizeX() >> 1;
int nMitadAlturaOrigen = g_pImagenSource->SizeY() >> 1;
int nMitadAnchuraDestino = g_pImagen->SizeX() >> 1;
int nMitadAlturaDestino = g_pImagen->SizeY() >> 1;

Y ahora puedes usar estas variables para las operaciones.

> M=T*Tcd*Rd*Ticd*Tc*S*R*Tic //se desplaza el punto de rotacion
>
> y si tenemos:
> M=Tcd*Rd*Ticd*T*Tc*S*R*Tic //se giran los ejes y la traslacion que
> genera T, al rotar la imagen por ejemplo 45°, se giran los ejes 45° y
> la traslacion se hace en ese sentido de los ejes
>

Según entiendo por este código que presentas, quieres realizar unas 
transformaciones de la imagen original y luego al copiar su resultado a 
la imagen destinataria, vuelves a realizar otra serie de 
transformaciones. El problema es que estás en dos espacios (sistemas de 
coordenadas) diferentes. Tienes el S.C. de la imagen original y el S.C. 
de la imagen destinataria. En algún momento, necesitas realizar ese 
cambio de sistemas de coordenadas. Esto es casi como presentar tu imagen 
en una vista en particular; consulta el capítulo 6 acerca del tema de la 
"vista" yendo a: 
http://graficos.conclase.net/curso/index.php?cap=006c#Vista 
Posteriormente, podemos aplicar cualesquier otras transformaciones en el 
S.C. de la imagen destinataria.

Quiero advertirte que, en general, es posible que estas transformaciones 
eliminen información de tu imagen, ya que las imágenes se guardan en 
espacios limitados, como por ejemplo, de [0,511] x [0,511]. Una rotación 
de 45 grados por el centro de tal cuadrado (255,255) resultará en una 
imagen de [0,723] x[0,723] que no se puede guardar en una imagen de 512 
x 512 píxeles. Por lo tanto, sugiero que agrandes la imagen original 
para así poder guardar los resultados sin pérdida de información. Claro 
está, si sabes que el total de las operaciones resulta en una imagen sin 
pérdidas, entonces obviamente no tienes problemas de este tipo.


Espero que lo anterior te ayude.

Steven





Más información sobre la lista de distribución Cconclase