2009-01-23 9 views
10

J'ai une image avec deux points, quelque chose aligné comme ceci:Rotation mathématiques d'image (C#)

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

J'ai deux coordonnées X, Y pour les deux points, et je dois faire pivoter l'image de X degrés il ressemble à la place:

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

Fondamentalement, ils s'alignent les uns à côté des autres, quel est le calcul pour cela? (Un exemple de code en C# serait encore mieux, mais pas nécessaire)

+0

Ceci est un vieux fil, mais je vais juste mentionner que j'ai posté une méthode de rotation d'image C# WinForms ici: http://stackoverflow.com/questions/2163829/how-do-i-rotate-a-image-in-c-sharp – RenniePet

Répondre

14

Cela dépend de quel point vous voulez utiliser comme pour votre rotation « centre ». Appelons le point vers le haut et le gauche A et vers le haut et le bas B. Si vous voulez tourner autour du point A de sorte que le point B aligne avec elle, le calcul de l'angle de rotation en radians irait comme ceci:

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

Je ne sais pas comment vous manipulez votre image, de sorte que le suivant s'applique uniquement si vous utilisez System.Drawing.Graphics:

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

Espérons que cela aide.

2

Vous devez rechercher des matrices de rotation géométrique: See this site for an detailed explanation

Cependant, pour de meilleurs résultats, vous avez besoin de transformer de la destination à la source, puis utiliser la transformation pour chaque pixel de destination:

m = rotation matrix 

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

Il y a, dans les méthodes de .NET Framework pour faire tout cela: System.Drawing.Graphics.RotateTransform et System.Drawing.Graphics.TranslateTransform. Vous devrez configurer une translation pour déplacer le point de rotation de l'image vers l'origine, puis appliquer la rotation, puis une autre translation pour la ramener à la position d'origine. Vous aurez besoin d'expérimenter avec ces fonctions pour voir comment elles se comportent - je suis au travail en ce moment et je n'ai pas le temps d'écrire un code qui fonctionne. :-(

5

Aucun code, désolé, mais stratagy.

Vous devez être en mesure de créer l'image de résultat par échantillonnage de la l'image source. Vous connaissez l'angle de rotation, de sorte que vous devez maintenant créer

for (int plotY = 0; plotY < resultHeight; plotY++) 
{ 
    for (int plotX = 0; plotX < resultWidth; plotX++) 
    { 
     resultImage.PlotPixel(getOriginalPixel(plotX, plotY, angleOfRotation)); 
    } 
} 
, un Vous pouvez faire une simple fonction de mappeur qui mappe du résultat à l'original

le code serait tout simplement balayer chaque ligne de l'image résultat, et cartographier le pixel retour à l'image originale..

Alors maintenant, nous avons juste besoin de la méthode magique "getOriginalPixel" d, et c'est là que les maths entre en jeu.

Si nous faisons pivoter l'image de 0 degrés, alors plotX, plotY est juste le X/Y de l'image originale. Mais ce n'est pas amusant.

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

Je pense que mappera au pixel source. Vous aurez besoin de vérifier si elle est en dehors des limites et juste retour noir ou quelque chose :)

+0

Vous devriez retourner Color.Transparent s'il est hors limites – MrFox

2

d'abord trouver le point central:

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

Utilisez ensuite trigonomentry pour résoudre l'angle. Je vais supposer que nous avons rebasé l'origine à notre point central, donc j'ai maintenant un nouveau x3 et y3 à l'un des points.

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

Nous résolvons l'angle inconnu TH

Sin(TH) = opposite/hypotenuse 

Donc, pour résoudre TH nous avons besoin:

TH = Asin(y3/hypotenuse) 

Rotation par TH.

Voir Wikipedia for trigonometric functions reference

2

L'exécution d'une transformation 2D générale implique la résolution d'une paire d'erreurs avec 6 inconnues.

'x = xA + yB + C

' y = xD + D + yE

Compte tenu de 3 points correspondants, on aura 6 knowns et le système peut être résolu. Vous n'avez que 4 points dans ce cas, puisque vous ne vous souciez pas du cisaillement, mais vous pouvez imaginer l'introduction d'un 3e point à 90 degrés par rapport à la ligne formée par les deux autres points. Création d'une image pivotée est alors (pseudo codedily) juste quelque chose comme:

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 la performance est importante, les multiplications dans la boucle interne peut être optimisé loin en notant que y * B seulement des changements dans l'apparence extérieure et que newx, newy change par les constantes A et D dans la boucle interne.

4

Le code ci-dessous fonctionne

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; 
     } 
    }