旋转图像数学 (C#)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/472428/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 04:46:29  来源:igfitidea点击:

Rotate image math (C#)

c#mathimagerotation

提问by thr

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:

我有两个点的 X、Y 坐标,我需要旋转图像 X 度,所以它看起来像这样:

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

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)

基本上,它们彼此对齐,这有什么数学方法?(C# 中的代码示例会更好但不是必需的)

采纳答案by Vojislav Stojkovic

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:

这取决于您想将哪个点用作旋转的“中心”。让我们将点称为上左点 A 和右下点 B 的点。如果您想围绕 A 点旋转以使 B 点与其对齐,则以弧度为单位计算旋转角度将如下所示:

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:

我不知道您如何处理图像,因此以下内容仅适用于您使用 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.

希望能帮助到你。

回答by Skizz

You need to look up geometric rotation matrices: 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.RotateTransformand 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. :-(

在 .net 框架方法中可以完成所有这些:System.Drawing.Graphics.RotateTransformSystem.Drawing.Graphics.TranslateTransform. 您需要设置一个平移以将图像的旋转点移动到原点,然后应用旋转,然后再应用另一个平移以将其返回到原始位置。您需要对这些函数进行试验以了解它们的行为方式 - 我目前正在工作,没有时间整理一些有效的代码。:-(

回答by Dead account

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.

所以现在我们只需要神奇的“getOriginalPixel”方法,这就是数学的用武之地。

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

如果我们将图像旋转 0 度,则 plotX,plotY 只是原始图像的 X/Y。但这并不好玩。

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 :)

我认为将映射到源像素。你需要检查它是否越界,然后返回黑色或其他东西:)

回答by Sam Meldrum

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.

然后用三角函数求解角度。我假设我们已经将原点重新定位到我们的中心点,所以我现在有一个新的 x3 和 y3 到其中一个点。

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

We are solving for the unknown angle TH

我们正在求解未知角度 TH

Sin(TH) = opposite / hypotenuse

So to solve for TH we need:

所以要解决 TH 我们需要:

TH = Asin(y3 / hypotenuse)

Rotate by TH.

旋转TH

See Wikipedia for trigonometric functions reference

有关三角函数参考,请参阅维基百科

回答by Tom Grove

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

执行一般的 2D 变换涉及解决一对具有 6 个未知数的方程。

'x = xA + yB + C

'x = xA + yB + C

'y = xD + yE + D

'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:

给定 3 个对应点,您将有 6 个已知值,系统可以求解。在这种情况下,您只有 4 个点,因为您不关心剪切,但是您可以想象在与其他两个点形成的线成 90 度的位置引入第三个点。创建一个旋转的图像然后(伪编码)就像这样:

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.

如果性能很重要,则可以通过注意 y*B 仅在外观上发生变化,而 newx,newy 在内循环中通过常量 A 和 D 变化来优化内循环中的乘法。

回答by Vani

The below code works

下面的代码有效

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