11

我有一个带有两个点的图像,对齐如下:

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

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

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

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

4

6 回答 6

15

这取决于您想将哪个点用作旋转的“中心”。让我们将这个点称为左上点 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);

希望能帮助到你。

于 2009-01-23T10:30:19.733 回答
5

没有代码,对不起,但一个策略。

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

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

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)

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

于 2009-01-23T10:23:29.670 回答
4

下面的代码有效

  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;
        }
    }
于 2011-02-16T16:28:03.710 回答
2

您需要查找几何旋转矩阵:有关详细说明,请参阅此站点

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

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.RotateTransformSystem.Drawing.Graphics.TranslateTransform. 您将需要设置平移以将图像的旋转点移动到原点,然后应用旋转,然后再应用另一个平移以将其返回到原始位置。您需要对这些函数进行试验以了解它们的行为方式——我目前正在工作,没有时间将一些有效的代码放在一起。:-(

于 2009-01-23T10:22:25.977 回答
2

首先找到中心点:

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

请参阅维基百科以获取三角函数参考

于 2009-01-23T10:25:26.483 回答
2

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

'x = xA + yB + C

'y = xD + yE + D

给定 3 个对应点,您将有 6 个已知值,系统就可以求解。在这种情况下,您只有 4 个点,因为您不关心剪切,但您可以想象将第 3 个点与其他两个点形成的直线呈 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 变化来优化内循环中的乘法。

于 2009-01-23T11:22:56.807 回答