旋转图像数学 (C#)

发布于 2024-07-12 12:09:46 字数 442 浏览 6 评论 0原文

我有一个有两个点的图像,像这样对齐:

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

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

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

基本上,它们彼此相邻对齐,数学是多少为了这? (C# 代码示例会更好,但不是必需的)

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

薄荷港 2024-07-19 12:09:46

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

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

我不知道您如何处理图像,因此仅当您使用时以下内容才适用System.Drawing.Graphics:

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

希望有帮助。

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.

兲鉂ぱ嘚淚 2024-07-19 12:09:46

抱歉,没有代码,但有一个策略。

您需要能够通过对源图像进行采样来创建结果图像。 您知道旋转角度,因此现在需要创建一个映射器函数,将结果映射回原始值。

该代码将简单地扫描结果图像的每一行,并将像素映射回原始图像。 你可以做一个简单的;

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

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

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

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

我认为将映射到源像素。 您需要检查它是否超出范围,然后返回黑色或其他内容:)

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

め七分饶幸 2024-07-19 12:09:46

下面的代码有效

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

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;
        }
    }
温柔戏命师 2024-07-19 12:09:46

首先找到中心点:

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

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

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

我们正在求解未知角度 TH

Sin(TH) = opposite / hypotenuse

因此,要求解 TH,我们需要:

TH = Asin(y3 / hypotenuse)

旋转 TH

请参阅维基百科了解三角函数参考

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

划一舟意中人 2024-07-19 12:09:46

执行一般的二维变换涉及求解一对具有 6 个未知数的方程。

'x = xA + yB + C

'y = xD + yE + D

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

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

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.

比忠 2024-07-19 12:09:46

您需要查找几何旋转矩阵:请参阅此站点以获取详细说明

但是,最好结果,您需要从目标转换为源,然后对每个目标像素使用转换:

m = rotation matrix

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

.net 框架中的方法可以完成所有这些操作:System.Drawing.Graphics.RotateTransform和 System.Drawing.Graphics.TranslateTransform。 您将需要设置平移以将图像的旋转点移动到原点,然后应用旋转,然后应用另一个平移以将其返回到原始位置。 您需要试验这些函数来弄清楚它们的行为方式 - 我现在正在工作,没有时间去编写一些可以工作的代码。 :-(

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.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. :-(

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文