2011-01-31 32 views
5

De ninguna manera pretendo ser un genio a la hora de programar y mi problema actual me ha dejado perplejo.Cálculo de una matriz de transformación 2D a partir de una matriz 2D inicial y resultante

He encontrado esta pregunta Trying to derive a 2D transformation matrix using only the images que parece responder al menos parcialmente mi pregunta, pero la imagen que debe mostrar la solución ya no está disponible: S

estoy trabajando en C# y no usar WPF ya que ni mi la entrada o la salida debe mostrarse gráficamente.

En mi programa tengo 2 cuadriláteros, vamos a llamarlos un cuadrilátero de entrada y uno de salida.

El quad de entrada tiene los co-ords de (2,1), (2,3), (4,4), (3,1) desde la parte inferior izquierda en el sentido de las agujas del reloj.

El cuadrante de salida puede tener cualquier co-ords y se volverá a enumerar en orden desde la esquina inferior izquierda en el sentido de las agujas del reloj.

Dados estos 8 pares de coordenadas, ¿es posible calcular una matriz de transformación que pueda aplicar a un único par de coordenadas?

No estoy demasiado caliente en Matrices, pero estoy dispuesto a aprender si apunta en la dirección correcta.

Muchas Gracias

Josh

+1

No creo que haya demasiada participación en la matriz aquí; está pidiendo una función isomórfica para proyectar un único punto dentro de un cuadrilátero a un punto en un segundo cuadrilátero. No debería ser demasiado difícil ... solo necesitas averiguar cómo se correlacionan los puntos dentro del primer y segundo polígono. –

+0

Es posible que también desee consultar http://math.stackexchange.com/questions/13404/mapping-irregular-quadrilateral-to-a-rectangle –

Respuesta

2

Un Google rápido o un salto, omitir y google encontrado this. Creo que definitivamente resolverá tu problema.

Como mencioné en el comentario, usted está solicitando una función isomórfica para proyectar un único punto dentro de un cuadrilátero a un punto en un segundo cuadrilátero. En lugar de resolverlo manualmente, he encontrado el algoritmo siguiente.

Publicar el algoritmo aquí para la posteridad: p00

Let, p10, p11, p01 y sean los vértices del primer cuadrilátero enumerados en orden antihorario.

Sea q00, q10, q11 y q01 los vértices del segundo cuadrilátero listados en en sentido antihorario.

Definir P10 = p10-p00, P11 = p11-p00, P01 = p01-p00, Q10 = q10-Q00, Q11 = Q11-Q00, y Q01 = Q01-Q00.

Calcule a y b para que Q11 = aQ10 + bQ01.

Este es un conjunto de dos ecuaciones lineales en dos incógnitas.

De forma similar, calcule cyd de modo que P11 = cP10 + dP01.

Resulta que a> = 0, b> = 0, a + b> 1, c> = 0, d> = 0, y c + d > 1.

cualquier punto P en el cuadrilátero puede escribirse como p = (1-xy) p00 + xp10 + yp01 donde x = 0, y = 0, (1 - d) x + c (y - 1) = 0, y d (x - 1) + (1 - c) y = 0.

Cualquier punto q en el cuadrilátero se puede escribir como q = (1-uv) q00 + uq10 + vq01 donde u = 0, v = 0, (1 - b) u + a (v -1) = 0, y b (u - 1) + (1 - a) v = 0.

La asignación de perspectiva relacionada (u, v) a (x, y) es u = m0x n0 + n1x + n2y yv = m1y n0 + n1x + n2y donde m0 = ad (1 - c - d), m1 = bc (1 - c - d), n0 = cd (1 - a - b), n1 = d (a - c + bc - ad), y n2 = c (b - d - bc + ad).

eficazmente la p-cuadrilátero se asigna a un “estándar” uno, < (0, 0), (1, 0), (0, 1), (c, d)>

y la q -quadrilateral se mapea a < (0, 0), (1, 0), (0, 1), (a, b)>.

El mapeo (x, y) a (u, v) relaciona estos dos.

Puede verificar que

• (x, y) = (0, 0) se asigna a (u, v) = (0, 0)

• (x, y) = (1, 0) se asigna a (u, v) = (1, 0)

• (x, y) = (0, 1) se asigna a (u, v) = (0, 1)

• (x, y) = (c, d) se asigna a (u, v) = (a, b)

voy a dar otra respuesta que describe cómo resolvería el ejemplo en los comentarios: esta respuesta es demasiado larga.

+0

Eso es Brilliant Kirk, muchas gracias por compartir tu conocimiento. –

+0

Cosas geniales, Kirk. –

+0

Ok muchachos, he implementado esto en el código lo mejor que sé cómo y no parece funcionar para mí. Actualmente estoy usando una aplicación de muestra en la que defino manualmente todas las coordenadas y el uso de transformaciones simples, no obtengo los resultados que necesito. Si, por ejemplo, uso un cuadrado de 10x10 desde 0,0 para la inicial, y un cuadrado de 20x20 también desde 0,0 cuando ingreso los co-ords 5,5 como X e Y para la inicial, debería obtener 10, 10 para la resultante, en este momento tengo 5,5 todavía. Cuando hago esto, los valores de A, B, C, D son 1 cuando tengo la sensación de que no deberían serlo. ¿Alguien sabe dónde me he equivocado? –

2

El título de tu pregunta es engañosa, ya que implica que tiene las matrices iniciales y finales. Sin embargo, lo que realmente tienes son dos conjuntos de puntos: los puntos iniciales y los finales.

En primer lugar, como usted ha mencionado, es posible calcular una matriz de transformación , pero no necesariamente la matriz de transformación. Para cualquier transformación particular, hay múltiples (¿infinitas?) Formas de lograrlo.

Tenga en cuenta que lo siguiente es solo algunas reflexiones. Realmente no he hecho esto. Supongo que tiene dos conjuntos de puntos, A y B, y sabe con certeza que B es el resultado de aplicar alguna transformación a A.

El problema es trivial si la única transformación permitida es la traducción. En ese caso, puede tomar la distancia entre los puntos inferiores izquierdos. Es decir, si los puntos originales son A[0] hasta A[3], y los puntos nuevos son B[0] hasta B[3], entonces la transformación es solo la traducción X, Y: ((B[0].X - A[0].X), (B[0].Y - A[0].Y)).

Si también está permitido escalar, puede calcular la traducción y luego la escala. Aunque para simplificar, primero querrás traducir al origen. De hecho, la mayoría de esto se simplifica si primero traduces al origen.

Si se permite la rotación, las cosas se ponen un poco más difíciles. Dados los cuadriláteros, primero tienes que rotar la cosa para que los puntos estén en la misma orientación que el original. Esto requerirá que calcule las distancias entre los puntos y use las razones para descubrir qué punto es el inferior izquierdo. Luego gire en el lugar correcto.

El caso de rotación, escalado y traducción debe ser fácil de resolver.

La esquila es un poco más complicada. Debería poder detectar cizalla, pero no tengo una buena idea de cómo detectar la cantidad de cizallamiento. Creo, sin embargo, que si resuelves el caso de rotar/escalar/traducir, entonces la solución de corte se volverá al menos un poco más obvia.

+0

Me gusta la primera mitad de su respuesta. Mi lectura de la pregunta fue que el segundo conjunto de coordenadas podría ser * cualquier * conjunto de coordenadas; girado, escala, esquilado están todos sobre la mesa. No habrá ninguna rotación "real" (más de 90 grados), porque estos son solo dos cuadriláteros definidos por la esquina inferior izquierda. –

+0

@Kirk: es posible que desee comprobar el significado de "cuadrilátero". Es solo una forma de 4 lados. Entonces * puede * ser una rotación real. –

+0

No es justo asumir que no sé el significado de cuadrilátero, ¿o sí? Mi punto era que para 2 cuadriláteros, ambos definidos * únicamente * por 4 coordenadas, y donde las coordenadas están ordenadas en sentido horario desde 'abajo a la izquierda', ¿cómo se puede determinar una 'rotación'? Si supiera qué rincón de Q1 corresponde a qué esquina de Q2, entonces puede tener "rotación", pero cuando no tiene esa información disponible, la rotación es un concepto irrelevante. –

1

Para resolver un ejemplo de caso - transposición de un punto (5,5) de un cuadrado (0,0) - (10,10) a un cuadrado (0,0) - (20,20) - usted está en el camino correcto, pero se detuvo demasiado pronto o se perdió. El algoritmo no es el más simple, pero es bastante útil una vez que comprenda a dónde va.

Cuando se trata de 'cuadrados' que son perpendiculares a x & y ejes, entonces sí a = b = c = d = 1.

Llamemos a los puntos de su quad p1, p2, p3 y p4. Ahora piense en a como que describe una relación entre p2 y p3 (con respecto a p1), yb como que describe una relación similar entre p4 y p3 (con respecto a p1). Muy simplista, que desea trabajar a cabo a y b donde

  • la coordenada x de p1 + a * length of side p1-p2 = coordenada x de p3, y
  • la coordenada y de p1 + b * length of side p1-p4 = coordenada y p3.

es decir, comenzando desde la parte inferior izquierda, cuántos bordes inferiores necesito agregar para llegar a la coordenada x de la esquina superior derecha, y de manera similar para la coordenada y. Aunque es un bocado, cuando se trata de un cuadrado, el resultado correcto aquí es definitivamente 1 y 1. Una vez que te alejas de los cuadrados perpendiculares, no es tan simple, pero es fácil de visualizar.

Cuando a solucionar este

  • p =(1-x-y)p00 + xp10 + yp01, donde
  • x >= 0
  • y >= 0
  • (1 - d)x + c(y - 1) = 0
  • d(x - 1)+(1 - c)y = 0

usando un punto (5,5) obtendrás un valor de x = 1/2, y = 1/2. Tenga en cuenta que estas no son las coordenadas xey de su punto. En su lugar, representan dónde se ubicaría su punto si el cuadrilátero se proyectara en un cuadrado de tamaño (1,1). En este caso, significa que su punto está posicionado a medio camino (horizontalmente) y 1/2 hacia arriba (verticalmente) de su polígono, es decir, está en el medio.

¡Enchufa tus valores a,b,c,d,x y y en la ecuación grande (siguiendo el enlace en lugar de tratar de leerlo aquí!), también obtiene (u, v) = (1/2, 1/2), donde u & v representan el mismo concepto anterior pero en el segundo cuadrado. Esto es correcto porque se espera que el punto resultante esté en el medio del segundo polígono.

Por último, cuando se conecta en su u, v en la ecuación

  • q =(1-u-v)q00 + uq10 + vq01

que obtendrá el punto Q = (10,10), que es la que esperaba.

No sé & no he pensado en resolver ecuaciones simultáneas en el código, estoy seguro de que hay una manera, pero puede que no sea simple, pero lamentablemente tendré que dejarlo en tus manos. Acabo de hacer esto en una hoja de papel y todo salió bien; sin embargo, mis matemáticas están un poco oxidadas para hacer algo más que el ejemplo más trivial.

+0

Hola Kirk, creo que me perdí y me detuve temprano por ese hecho. Veré cómo implementar este código más tarde cuando mi cerebro está funcionando un poco mejor. –

+0

@Josh Te recomiendo que lo repares primero en papel para que veas cómo funciona; luego intente implementarlo en el código. –

+0

Gracias por la sugerencia, lo he analizado rápidamente en papel con un par de escenarios diferentes y parecía funcionar bien. Lo implementé en código y parece que todo me funciona para los mismos escenarios, pero el código parece fallar con variaciones más complejas de los parámetros de entrada y salida. Voy a echarle otro vistazo en un par de días cuando mi mente se sienta un poco más fresca e iré desde allí. Saludos de nuevo. –