2009-01-23 29 views
10

tengo una imagen con dos puntos, alineado algo como esto:Girar imagen matemáticas (C#)

|----------------| 
|    | 
| .   | 
|    | 
|   .  | 
|    | 
|----------------| 

tengo tanto coordenadas X, Y de los dos puntos y necesito para hacer girar los grados de imagen X por lo que se ve así en su lugar:

|----------------| 
|    | 
|    | 
| .  .  | 
|    | 
|    | 
|----------------| 

Básicamente, así que se alinean uno al lado del otro, ¿cuál es la matemática de esto? (Un ejemplo de código en C# sería aún mejor, pero no es obligatorio)

+0

Se trata de un viejo hilo, pero sólo voy a mencionar que he publicado un método de C# WinForms rotación de imagen aquí: http://stackoverflow.com/questions/2163829/how-do-i-rotate-a-picture-in-c-sharp – RenniePet

Respuesta

14

Depende de qué punto desea utilizar como un "centro" para su rotación. Llamemos el punto hacia arriba y el punto izquierdo A y el que está a la derecha y debajo del punto B. Si desea girar alrededor del punto A de modo que el punto B se alinea con ella, calculando el ángulo de rotación en radianes iría así:

double angle = Math.Atan2(pointB.Y - pointA.Y, pointB.X - pointA.X); 

no me cómo se está manejando su imagen, por lo que el siguiente se aplica solo si está utilizando System.Drawing.Graphics:

myImage.TranslateTransform(-pointA.X, -pointA.Y); 
myImage.RotateTransform((float) angle, MatrixOrder.Append); 
myImage.TranslateTransform(pointA.X, pointA.Y, MatrixOrder.Append); 

Espero que ayude.

2

Es necesario mirar hacia arriba matrices de rotación geométricas: See this site for an detailed explanation

Sin embargo, para obtener mejores resultados, es necesario transformar desde el destino al origen y luego utilizar la transformación para cada píxel de destino:

m = rotation matrix 

for each point p in destination 
    p' = p.m 
    get pixel p' from source 
    set pixle p in destination 

No hay, de los métodos de .NET Framework para hacer todo esto: System.Drawing.Graphics.RotateTransform y System.Drawing.Graphics.TranslateTransform. Tendrá que configurar una traducción para mover el punto de rotación de la imagen al origen, luego aplicar la rotación y luego otra traducción para devolverla a la posición original. Necesitarás experimentar con estas funciones para descubrir cómo se comportan. Estoy trabajando en este momento y no tengo tiempo para obtener un código que funcione. :-(

5

Sin código, lo siento, pero un stratagy.

Tienes que ser capaz de crear la imagen resultante mediante el muestreo de la imagen de la fuente. Usted sabe que el ángulo de rotación, por lo que ahora necesita crear una función de asignador que mapea desde el resultado de nuevo a la original

el código simplemente escanear cada fila de la imagen resultante, y el mapa de píxel de nuevo a la imagen original puede hacer una simple;..

for (int plotY = 0; plotY < resultHeight; plotY++) 
{ 
    for (int plotX = 0; plotX < resultWidth; plotX++) 
    { 
     resultImage.PlotPixel(getOriginalPixel(plotX, plotY, angleOfRotation)); 
    } 
} 

Así que ahora solo necesitamos el método mágico "getOriginalPixel" d, y aquí es donde entra la matemática.

Si rotamos la imagen 0 grados, entonces plotX, plotY es solo la X/Y de la imagen original. Pero eso no es divertido.

pickX = x * cos(angle) - y * sin(angle) 
pickY = y * cos(angle) + x * sin(angle) 

Creo que se asignará al píxel fuente. Usted tendrá que comprobar si está fuera de los límites y simplemente volver negro o algo :)

+0

Deberías devolver Color.Transparent si está fuera de los límites – MrFox

2

En primer lugar encontrar el punto central:

Point p = new Point((x1-x2)/2, (y1-y2)/2) 

A continuación, utilice trigonomentry para resolver el ángulo. Voy a suponer que hemos cambiado el origen de nuestro punto central, así que ahora tengo un nuevo x3 e y3 en uno de los puntos.

hypotenuse = SqrRt(x3^2 + y3^2) 

Estamos resolviendo para el ángulo desconocido TH

Sin(TH) = opposite/hypotenuse 

Así que para resolver TH necesitamos:

TH = Asin(y3/hypotenuse) 

Girar TH.

Ver Wikipedia for trigonometric functions reference

2

Realizar una transformación general en 2D implica resolver un par de ecuaciones con 6 incógnitas.

'x = xA + yB + C

' y = xD + yE + D

dado 3 puntos correspondientes, que tendrán 6 datos conocidos y el sistema puede ser resuelto. Solo tienes 4 puntos en este caso, ya que no te importa el corte, pero podrías imaginar introducir un tercer punto a 90 grados con respecto a la línea formada por los otros dos puntos. La creación de una imagen rotada está a continuación (pseudo codedily) simplemente algo como:

for (y = 0; y < height; y++) 
for (x = 0; x < width; x++) 
    { 
    newx = x*A + y*B + C; 
    newy = x*D + y*D + E; 
    newimage(x,y) = oldimage(newx, newy); 
    } 
} 

Si el rendimiento es importante, los multiplica en el bucle interior se puede optimizar distancia observando que y * sólo B cambia en el aspecto exterior y que las newx, newy cambio por constantes A y D en el bucle interno.

4

El código siguiente funciona

Matrix mRotate = new Matrix(); 
    mRotate.Translate(Convert.ToInt32(Width.Value)/-2, Convert.ToInt32(Height.Value)/-2, MatrixOrder.Append); 
    mRotate.RotateAt(theta, new Point(0, 0), MatrixOrder.Append); 

    using (GraphicsPath gp = new GraphicsPath()) 
    { // transform image points by rotation matrix 
     gp.AddPolygon(new Point[] { new Point(0, 0), new Point(Convert.ToInt32(Width.Value), 0), new Point(0, Convert.ToInt32(Height.Value)) }); 
     gp.Transform(mRotate); 
     PointF[] pts = gp.PathPoints; 

     // create destination bitmap sized to contain rotated source image 
     Rectangle bbox = boundingBox(bmpSrc, mRotate); 
     Bitmap bmpDest = new Bitmap(bbox.Width, bbox.Height); 


     using (Graphics gDest = Graphics.FromImage(bmpDest)) 
     { // draw source into dest 


      Matrix mDest = new Matrix(); 
      mDest.Translate(bmpDest.Width/2, bmpDest.Height/2, MatrixOrder.Append); 
      gDest.Transform = mDest; 
      gDest.DrawImage(bmpSrc, pts); 
      gDest.DrawRectangle(Pens.Transparent, bbox); 
      //drawAxes(gDest, Color.Red, 0, 0, 1, 100, ""); 
      return bmpDest; 
     } 
    }