views:

5278

answers:

6

I have an image with two points, aligned something like this:

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

I have both X, Y coordinates for both points and I need to rotate the image X degrees so it looks like this instead:

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

Basically so they align next to eachother, what's the math for this? (A code example in C# would be even better but not required)

+1  A: 

You need to look up geometric rotation matricies: See this site for an detailed explanation

However, for best results, you need to transform from the destination to the source and then use the transformation for each destination pixel:

m = rotation matrix

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

There is, in the .net framework methods to do all this: System.Drawing.Graphics.RotateTransform and System.Drawing.Graphics.TranslateTransform. You will need to set up a translation to move the rotation point of the image to the origin, then apply the rotation and then another translation to return it to the original position. You'll need to experiment with these functions to work out how they behave - I'm at work at the moment and haven't the time to hand to get some code together that works. :-(

Skizz

Skizz
+2  A: 

No code, sorry, but a stratagy.

You need to be able to create the result image by sampling the the source image. You know the angle of rotation, so you now need to create a mapper function which maps from the result back to the original.

The code would simply scan each row of the result image, and map the pixel back to the original image. You can do a simple;

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

So now we just need the magical "getOriginalPixel" method, and this is where the maths comes in.

If we rotate the image 0 degrees, then plotX, plotY is just the X/Y of the original image. But that's no fun.

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

I think will map to the source pixel. You'll need to check if it's out of bounds and just return black or something :)

Dead account
+1  A: 

First find the centre point:

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

Then use trigonomentry to solve for the angle. I'm going to assume we have rebased the origin to our central point so I now have a new x3 and y3 to one of the points.

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

We are solving for the unknown angle TH

Sin(TH) = opposite / hypotenuse

So to solve for TH we need:

TH = Asin(y3 / hypotenuse)

Rotate by TH.

See Wikipedia for trigonometric functions reference

Sam Meldrum
+9  A: 

It depends on which point you want to use as a "center" for your rotation. Let's call the point to the up and left pointA and the one to the right and below pointB. If you want to rotate around the point A so that point B aligns with it, calculating the rotation angle in radians would go like this:

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

I don't how you're handling your image, so the following applies only if you're using System.Drawing.Graphics:

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

Hope it helps.

Vojislav Stojkovic
+1  A: 

Performing a general 2D transformation involves solving a pair of eqautions with 6 unknowns.

'x = xA + yB + C

'y = xD + yE + D

Given 3 corresponding points, you will have 6 knowns and the system can be solved. You only have 4 points in this case, since you don't care about shear, but you could imagine introducing a 3rd point at 90 degrees to the line formed by the other two points. Creating a rotated image is then ( pseudo codedily ) just something like:

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

If performance is important, the multiplies in the inner loop can be optimised away by noting that y*B only changes in the outer look and that newx,newy change by constants A and D in the inner loop.

Tom Grove
+1  A: 

I am working on something similar. The problem i am encountering is that the image gets cropped. I want the whole image to be saved after rotation. Any idea of how to achieve this? This is the code i am using for rotation...

public void RotateImageByAngle(Bitmap oldBitmap, float angle) {

        //int h = oldBitmap.Height;
        //int w = oldBitmap.Width;
        //double x1, x2, y1, y2;
        //double rad = -angle * Math.PI / 180;
        //x1 = (-w / 2 * Math.Cos(rad)) - (h / 2 * Math.Sin(rad));
        //x2 = (w / 2 * Math.Cos(rad)) - (-h / 2 * Math.Sin(rad));
        //y1 = (-w / 2 * Math.Cos(rad)) - (-h / 2 * Math.Sin(rad));
        //y2 = (w / 2 * Math.Cos(rad)) - (h / 2 * Math.Sin(rad));
        //Bitmap newBitmap = new Bitmap(System.Convert.ToInt32(Math.Abs(x1 )*2 + oldBitmap.Width), System.Convert.ToInt32(Math.Abs(y1)*2 + oldBitmap.Height));
        Bitmap newBitmap = new Bitmap(oldBitmap.Width,oldBitmap.Height);
        var graphics = Graphics.FromImage(newBitmap);

        graphics.TranslateTransform((float)newBitmap.Width / 2, (float)newBitmap.Height / 2);
        graphics.RotateTransform(angle);
        graphics.TranslateTransform(-(float)newBitmap.Width / 2, -(float)newBitmap.Height / 2);
        graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
        graphics.DrawImage(oldBitmap, new Point(0, 0));
        pictureBox1.Image = newBitmap;

        newBitmap.Save("C:\\Users\\laptop\\Documents\\Open CV\\skewbysimple.bmp");
    }

Regards,

Vikas