una transformaciones señales rotar procesamiento para mosaico lineal interpolacion imagenes imagen geometricas cuadratica codigo algoritmo math rotation interpolation

math - transformaciones - mosaico e interpolacion



Interpolación de rotación (6)

Lo siento, eso fue un poco intrincado, aquí hay una versión más concisa:

public static float LerpDegrees(float start, float end, float amount) { float difference = Math.Abs(end - start); if (difference > 180) { // We need to add on to one of the values. if (end > start) { // We''ll add it on to start... start += 360; } else { // Add it on to end. end += 360; } } // Interpolate it. float value = (start + ((end - start) * amount)); // Wrap it.. float rangeZero = 360; if (value >= 0 && value <= 360) return value; return (value % rangeZero); }

¿Alguien tiene una versión más optimizada?

NB: Presentaré esta pregunta en grados puramente por simplicidad, radianes, grados, diferentes tolerancias cero, el problema es esencialmente el mismo.

¿Alguien tiene alguna idea sobre el código detrás de la interpolación rotacional? Dada una función de interpolación lineal: Lerp (de, a, cantidad), donde la cantidad es 0 ... 1, que devuelve un valor entre from y to, por cantidad. ¿Cómo podría aplicar esta misma función a una interpolación rotacional entre 0 y 360 grados? Dado que los grados no se deben devolver fuera de 0 y 360.

Dado este círculo unitario para grados:

donde desde = 45 y hasta = 315, el algoritmo debe tomar el camino más corto al ángulo, es decir, debe ir a través de cero, a 360 y luego a 315, y no a la vuelta de 90, 180, 270 a 315.

¿Hay una buena manera de lograr esto? ¿O va a ser simplemente un horrible lío de bloques ()? ¿Me estoy perdiendo alguna forma estándar bien entendida de hacer esto? Cualquier ayuda sería apreciada.


Mi forma preferida de lidiar con el ángulo es usar unidades con una potencia de 2 por revolución. Por ejemplo, si utilizas enteros con signo de 16 bits para representar -180 a +180 grados, puedes simplemente tomar (de-a) / pasos_num para hacer tu interpolación. Sumar y restar ángulos siempre funciona, ya que los valores binarios se desbordan justo en el punto donde se pasa de 360 ​​a 0.

Lo que probablemente quiera hacer en su caso es módulo matemático 360. Por lo tanto, las diferencias de ángulo se calculan como (de-a)% 360. Todavía hay algunos problemas con los signos que se han abordado en otras preguntas de SO.


NB: usando el código C #

Después de algunas locas hurgando en mi cerebro, esto es lo que se me ocurrió. Básicamente, la premisa es realizar la envoltura 0-360 en el último minuto. Trate internamente con valores fuera de 0-360 y luego envuélvalos dentro de 0-360 en el punto en que se solicita un valor de la función.

En el punto donde elige un punto de inicio y un final, realiza lo siguiente:

float difference = Math.Abs(end - start); if (difference > 180) { // We need to add on to one of the values. if (end > start) { // We''ll add it on to start... start += 360; } else { // Add it on to end. end += 360; } }

Esto le proporciona los valores reales de inicio y fin, que pueden estar fuera de 0-360 ...

Tenemos una función de ajuste para garantizar que el valor esté entre 0 y 360 ...

public static float Wrap(float value, float lower, float upper) { float rangeZero = upper - lower; if (value >= lower && value <= upper) return value; return (value % rangeZero) + lower; }

Luego, en el punto en que solicita el valor actual de la función:

return Wrap(Lerp(start, end, amount), 0, 360);

Es casi seguro que esta no es la solución más óptima para el problema, sin embargo, parece funcionar de manera consistente. Si alguien tiene alguna forma más óptima de hacer esto, sería genial.


Quería volver a escribir mi respuesta para explicar mejor la respuesta a la pregunta. Estoy usando EXCEL para mis fórmulas y grados para mis unidades.

Para simplificar, B es el mayor de los dos valores, y A es el menor de los dos valores. Puede usar MAX() y MIN() respectivamente en su solución más tarde.

PARTE 1: ¿QUÉ MANERA DE IR?

Lo que queremos hacer primero es calcular en qué dirección queremos realizar el cálculo, en sentido horario o antihorario. Usamos una declaración IF() para eso:

IF( (B-A)<=180, (Clockwise_Formula), (AntiClockwise_Formula) )

La fórmula anterior comprueba si ir en sentido antihorario de B a A (que es lo mismo que ir en sentido horario de A a B ) es menor o igual a 180 grados. Si no, va a ser más corto para ir en la otra dirección.

Para comprobar esto funciona: 90 - 45 = 45 (que es menor o igual que 180) hace que la instrucción IF sea TRUE, por lo que la dirección horaria es más corta, pero 315 - 45 = 270 (que es mayor que 180) hace la instrucción if FALSO, entonces la fórmula antihoraria sería más corta.

PARTE 2 - FÓRMULA EN EL SENTIDO DE LAS AGUJAS DEL RELOJ

Ahora quiere interpolar N veces entre A y B , ya sea en sentido horario o antihorario. La fórmula a la derecha es relativamente simple.

Clockwise_Formula: ((B-A)/N*S)+A

Donde S es un recuento del número de interpolaciones, comenzando en 1 y terminando en N-1 (Si S = N , su respuesta será B )

Ejemplo: A = 90, B = 270, N = 4

S=1: ((270-90)/4*1)+90 = 135 S=2: ((270-90)/4*2)+90 = 180 S=3: ((270-90)/4*3)+90 = 225

PARTE 3 - FÓRMULA DE ANTICUERPOS

La fórmula a la izquierda será un poco más compleja, porque tendremos que cruzar en sentido antihorario en un ángulo de 360 ​​grados. El método más sencillo que puedo pensar es agregar 360 a A , luego modular la respuesta en 360 usando la función MOD(FORMULA,VALUE) .

También tendrá que intercambiar A y B en la fórmula porque B es ahora el número más pequeño. (Eso puede sonar un poco confuso, pero funciona!)

(Unmodulated) AntiClockwise_Formula: (((A+360)-B)/N*S)+B

Ejemplo: A = 60, B = 300, N = 4

S=1: (((60+360)-300)/4*1)+300 = 330 S=2: (((60+360)-300)/4*2)+300 = 360 S=3: (((60+360)-300)/4*3)+300 = 390

PARTE 4: RESTRINGIR RESPUESTAS ENTRE 0 Y 360

Vea cómo a veces (pero no siempre) las respuestas van a ser mayores que 360? Aquí es donde entra la envoltura de su Anticlockwise_formula en una función MOD() :

AntiClockwise_Formula: MOD((((A+360)-B)/N*S)+B,360)

La modulación del ejemplo utilizado en la Parte 3 le dará:

S=1: 330 S=2: 0 S=3: 30

PARTE 5: PONER TODO JUNTOS

Al combinar todos los elementos de las Partes 1-4, la respuesta es:

IF((B-A)<=180,((B-A)/N*S)+A,MOD((((A+360)-B)/N*S)+B,360))

Dónde:

A = El menor de los dos valores (puede reemplazar A con MIN ())

B = El mayor de los dos valores (puede reemplazar B con MAX ())

N = El número de interpolaciones que desea hacer (por ejemplo, 2 es la mitad, 3 está en tercios, etc.)

S = Un conteo incrimental hasta un máximo de N-1 (ver Parte 2 para explicación)


Creo que un mejor enfoque es interpolar el pecado y el cos porque no sufren una forma definida de manera múltiple. Deje w = "cantidad" de modo que w = 0 es el ángulo A y w = 1 es el ángulo B. Luego

CS = (1-w)*cos(A) + w*cos(B); SN = (1-w)*sin(A) + w*sin(B); C = atan2(SN,CS);

Uno tiene que convertir a radianes y grados según sea necesario. Uno también tiene que ajustar la rama. Para atan2 C vuelve en el rango -pi a pi. Si quiere 0 a 2pi, simplemente agregue pi a C.


Sé que tengo 2 años, pero recientemente he estado buscando el mismo problema y no veo una solución elegante sin ifs aquí, así que aquí va:

shortest_angle=((((end - start) % 360) + 540) % 360) - 180; return shortest_angle * amount;

Eso es

ps: por supuesto,% es el significado de módulo y el más corto_angulo es la variable que contiene todo el ángulo de interpolación