【问题标题】:Rotate image math (C#)旋转图像数学 (C#)
【发布时间】:2009-01-23 10:11:06
【问题描述】:

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

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

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

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

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

【问题讨论】:

标签: c# math image rotation


【解决方案1】:

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

希望对你有帮助。

【讨论】:

    【解决方案2】:

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

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

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

    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)
    

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

    【讨论】:

    • 如果 Color.Transparent 越界,您应该返回它
    【解决方案3】:

    以下代码有效

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

    【讨论】:

      【解决方案4】:

      先找到中心点:

      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 旋转。

      Wikipedia for trigonometric functions reference

      【讨论】:

        【解决方案5】:

        执行一般的 2D 变换涉及求解一对具有 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 变化来优化内部循环中的乘法。

        【讨论】:

          【解决方案6】:

          您需要查找几何旋转矩阵:See this site for an detailed explanation

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2017-04-01
            • 2022-07-11
            • 2015-07-20
            • 2011-01-17
            • 2018-10-14
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多