【问题标题】:What is the fastest method for rotating an image without clipping its edges with GDI+?在不使用 GDI+ 剪裁边缘的情况下旋转图像的最快方法是什么?
【发布时间】:2011-04-14 23:49:15
【问题描述】:

有一些冗长而饥饿的算法可以做到这一点,但到目前为止我还没有想出或发现任何特别快的东西。

【问题讨论】:

  • 您好!有后续吗?你最终使用的是什么?你测量过翻转的时间吗?您是否将其与 EmguCV 进行了比较?我正在寻找在 C# 中将图像旋转 90 度和 180 度的最快方法。
  • 对于简单的 90 度和 180 度旋转,绝对使用 GDI+。它内置 90 度旋转。对于任意角度,请使用 LockBits。

标签: c# .net visual-studio-2008 gdi+ transformation


【解决方案1】:

最快的方法是使用不安全的调用来直接使用LockBits 来操作图像内存。这听起来很可怕,但它很简单。如果您搜索 LockBits,您会发现很多示例,例如 here

有趣的是:

BitmapData originalData = originalBitmap.LockBits(
     new Rectangle(0, 0, originalWidth, originalHeight), 
     ImageLockMode.ReadOnly, 
     PixelFormat.Format32bppRgb);

获得 BitmapData 后,您可以传递像素并将它们映射到新图像中(再次使用 LockBits)。这比使用Graphics API 快得多。

【讨论】:

  • 顺便说一句,使用 Graphics API 而不进行剪辑的正确(和较慢)方法是 stackoverflow.com/questions/2352804/…
  • 第一个(不被接受的)答案是我假设你指的是什么?
  • 我将赏金奖励给了你,因为你让我得到了最终的答案,尽管不是 LockBits。原来我只能使用安全代码......嗯。
  • @Bloodyaugust 我的意思是如何在不使用图形 API 剪辑的情况下实现旋转。我没有直接指前面的答案:)
【解决方案2】:

这是我最终做的事情(经过大量的持续研究,以及 TheCodeKing 提供的有用链接):

public Image RotateImage(Image img, float rotationAngle)
    {
        // When drawing the returned image to a form, modify your points by 
        // (-(img.Width / 2) - 1, -(img.Height / 2) - 1) to draw for actual co-ordinates.

        //create an empty Bitmap image 
        Bitmap bmp = new Bitmap((img.Width * 2), (img.Height *2));

        //turn the Bitmap into a Graphics object
        Graphics gfx = Graphics.FromImage(bmp);

        //set the point system origin to the center of our image
        gfx.TranslateTransform((float)bmp.Width / 2, (float)bmp.Height / 2);

        //now rotate the image
        gfx.RotateTransform(rotationAngle);

        //move the point system origin back to 0,0
        gfx.TranslateTransform(-(float)bmp.Width / 2, -(float)bmp.Height / 2);

        //set the InterpolationMode to HighQualityBicubic so to ensure a high
        //quality image once it is transformed to the specified size
        gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;

        //draw our new image onto the graphics object with its center on the center of rotation
        gfx.DrawImage(img, new PointF((img.Width / 2), (img.Height / 2)));

        //dispose of our Graphics object
        gfx.Dispose();

        //return the image
        return bmp;
    }

干杯!

【讨论】:

  • 您将位图旋转为原始大小的两倍。这可以优化。支持旋转而不剪裁所需的位图大小取决于旋转角度。
【解决方案3】:
void Graphics.RotateTransform(float angle);

这应该在 C# 中旋转图像。它在做什么呢?

我没有对 GDI+ 进行过多的试验。记得在画完图像后反转旋转。

【讨论】:

  • 可以,但不是没有剪辑。
  • 其中一个 cmets 解决了裁剪问题,但不(准确)围绕中心点旋转。请参阅anonymous 在 03/23/2009 - 22:23 发表的评论。
  • @Michael:您可能希望将其作为答案,而不是对我的错误答案的评论。 ^^()
  • @Michael 链接已失效
【解决方案4】:

这个答案返回它应该绘制的偏移量和已经旋转的图像。它通过将新图像重新创建到它应该的大小而不剪裁角度来工作。最初由 Hisenburg 从 #C# IRC 聊天室和 Bloodyaugust 编写。

   public static double NormalizeAngle(double angle)
    {
        double division = angle / (Math.PI / 2);
        double fraction = Math.Ceiling(division) - division;

        return (fraction * Math.PI / 2);
    }


    public static Tuple<Image,Size> RotateImage(Image img, double rotationAngle)
    {

        double normalizedRotationAngle = NormalizeAngle(rotationAngle);

        double widthD = img.Width, heightD = img.Height;
        double newWidthD, newHeightD;



        newWidthD = Math.Cos(normalizedRotationAngle) * widthD + Math.Sin(normalizedRotationAngle) * heightD;
        newHeightD = Math.Cos(normalizedRotationAngle) * heightD + Math.Sin(normalizedRotationAngle) * widthD;

        int newWidth, newHeight;
        newWidth = (int)Math.Ceiling(newWidthD);
        newHeight = (int)Math.Ceiling(newHeightD);

        Size offset = new Size((newWidth - img.Width) / 2,(newHeight - img.Height) / 2);

        Bitmap bmp = new Bitmap(newWidth, newHeight);
        Graphics gfx = Graphics.FromImage(bmp);
        //gfx.Clear(Color.Blue);
        gfx.TranslateTransform((float)bmp.Width / 2, (float)bmp.Height / 2);
        gfx.RotateTransform((float)(rotationAngle / Math.PI * 180));
        gfx.TranslateTransform(-(float)bmp.Width / 2, -(float)bmp.Height / 2);
        gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
        gfx.DrawImage(img, new PointF((bmp.Width / 2 - img.Width / 2), (bmp.Height / 2 - img.Height / 2)));
        gfx.Dispose();  
        return new Tuple<Image,Size>(bmp,offset);
    }

【讨论】:

  • John Thompson,@Bloodyaugust - 我很好奇是什么让你使用归一化角度方法而不是在这里使用度数到弧度的转换?
  • 这是教我如何做的方式。
【解决方案5】:
System.Drawing.Image imageToRotate = System.Drawing.Image.FromFile(imagePath);
switch (rotationAngle.Value)
{
    case "90":
        imageToRotate.RotateFlip(RotateFlipType.Rotate90FlipNone);
        break;
    case "180":
        imageToRotate.RotateFlip(RotateFlipType.Rotate180FlipNone);
        break;
    case "270":
        imageToRotate.RotateFlip(RotateFlipType.Rotate270FlipNone);
        break;
    default:
        throw new Exception("Rotation angle not supported.");
}
imageToRotate.Save(imagePath, ImageFormat.Jpeg);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-02
    • 2010-12-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-25
    • 1970-01-01
    • 1970-01-01
    • 2017-10-20
    相关资源
    最近更新 更多