插值算法、C# 和 C++ 的速度一起工作

发布于 2024-08-31 01:34:41 字数 3193 浏览 3 评论 0原文

我需要快速实现流行的插值算法。我发现 C# 在如此简单的算法中会比 C++ 慢得多,所以我考虑编写一些本机代码并在我的 C# GUI 中使用它。

首先,我在 1024x1024x3 矩阵上运行了一些测试,在 C# 中花费了 32 毫秒,在 C++ 中花费了 4 毫秒,这就是我基本上需要的。

然而,插值并不是一个好词,因为我只需要它们来缩小尺寸。但问题是:它会比 Drawing2D 中的 C# 方法更快吗?

Image outputImage = new Bitmap(destWidth, destHeight, PixelFormat.Format24bppRgb);
Graphics grPhoto = Graphics.FromImage(outputImage);

grPhoto.InterpolationMode = InterpolationMode.*; //all of them

grPhoto.DrawImage(bmp, new Rectangle(0, 0, destWidth, destHeight),
Rectangle(0, 0, sourceWidth, sourceHeight), GraphicsUnit.Pixel);

grPhoto.Dispose();

其中一些方法运行时间为 20 毫秒,有些方法运行时间为 80 毫秒。有没有办法做得更快?


编辑1:

首先我在这个应用程序中使用XNA,但似乎没有办法选择不同的插值方法。当然,它的工作速度非常快。

理想的方法是在显卡上实现这些方法。


编辑2:

这是我的整个方法:

private unsafe Texture2D Scale(GraphicsDevice gd, Texture2D texture, float scale)
    {

        int sourceWidth = texture.Width;
        int sourceHeight = texture.Height;

        int destWidth = (int)(sourceWidth * scale);
        int destHeight = (int)(sourceHeight * scale);

        StopwatchEx sw = new StopwatchEx();
        sw.IntervalStart();
        //convert texture into bitmap
        byte[] textureData = new byte[4 * sourceWidth * sourceHeight];
        texture.GetData<byte>(textureData);

        System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(sourceWidth, sourceHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
        System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, sourceWidth, sourceHeight), System.Drawing.Imaging.ImageLockMode.WriteOnly,
                       System.Drawing.Imaging.PixelFormat.Format32bppArgb);

        IntPtr safePtr = bmpData.Scan0;
        System.Runtime.InteropServices.Marshal.Copy(textureData, 0, safePtr, textureData.Length);
        bmp.UnlockBits(bmpData);


        //output bitmap
        System.Drawing.Image outputImage = new System.Drawing.Bitmap(destWidth, destHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
        System.Drawing.Graphics grPhoto = System.Drawing.Graphics.FromImage(outputImage);

        grPhoto.InterpolationMode = (System.Drawing.Drawing2D.InterpolationMode)(interpolationMode);
        grPhoto.SmoothingMode = (System.Drawing.Drawing2D.SmoothingMode)smoothingMode;
        grPhoto.PixelOffsetMode = (System.Drawing.Drawing2D.PixelOffsetMode)pixelOffsetMode;

        grPhoto.DrawImage((System.Drawing.Image)bmp, new System.Drawing.Rectangle(0, 0, destWidth, destHeight),
            new System.Drawing.Rectangle(0, 0, sourceWidth, sourceHeight), System.Drawing.GraphicsUnit.Pixel);

        grPhoto.Dispose();

        textureData = new byte[4 * sourceWidth * sourceHeight];

        MemoryStream ms = new MemoryStream();
        ((System.Drawing.Bitmap)outputImage).Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);

        ms.Seek(0, SeekOrigin.Begin);
        Texture2D result = Texture2D.FromFile(gd, ms);
        ms.Dispose();
        sw.IntervalStop();
        sw.AppendResults("MEGS.txt");    

        return result;
    }

有趣的是 HighQualityBicubic 比 Bicubic 快得多。 (40 毫秒与 100 毫秒)

I need fast implementation of popular interpolation algorithms. I figured it out that C# in such simple algorithms will be much slower than C++ so i think of writing some native code and using it in my C# GUI.

First of all i run some tests and few operations on 1024x1024x3 matrix took 32ms in C# and 4ms in C++ and that's what i basicly need.

Interpolation however is not a good word because i need them only for downscaling. But the question is: Will it be faster than C# methods in Drawing2D

Image outputImage = new Bitmap(destWidth, destHeight, PixelFormat.Format24bppRgb);
Graphics grPhoto = Graphics.FromImage(outputImage);

grPhoto.InterpolationMode = InterpolationMode.*; //all of them

grPhoto.DrawImage(bmp, new Rectangle(0, 0, destWidth, destHeight),
Rectangle(0, 0, sourceWidth, sourceHeight), GraphicsUnit.Pixel);

grPhoto.Dispose();

Some of these method run in 20ms and some in 80. Is there a way to do it faster?


EDIT 1:

First of all i'm using XNA in this application but there seems to be no way to select different interpolation method. Of course it's working very fast.

Ideal way would be to implement those methods on graphic card.


EDIT 2:

Here is my whole method:

private unsafe Texture2D Scale(GraphicsDevice gd, Texture2D texture, float scale)
    {

        int sourceWidth = texture.Width;
        int sourceHeight = texture.Height;

        int destWidth = (int)(sourceWidth * scale);
        int destHeight = (int)(sourceHeight * scale);

        StopwatchEx sw = new StopwatchEx();
        sw.IntervalStart();
        //convert texture into bitmap
        byte[] textureData = new byte[4 * sourceWidth * sourceHeight];
        texture.GetData<byte>(textureData);

        System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(sourceWidth, sourceHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
        System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, sourceWidth, sourceHeight), System.Drawing.Imaging.ImageLockMode.WriteOnly,
                       System.Drawing.Imaging.PixelFormat.Format32bppArgb);

        IntPtr safePtr = bmpData.Scan0;
        System.Runtime.InteropServices.Marshal.Copy(textureData, 0, safePtr, textureData.Length);
        bmp.UnlockBits(bmpData);


        //output bitmap
        System.Drawing.Image outputImage = new System.Drawing.Bitmap(destWidth, destHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
        System.Drawing.Graphics grPhoto = System.Drawing.Graphics.FromImage(outputImage);

        grPhoto.InterpolationMode = (System.Drawing.Drawing2D.InterpolationMode)(interpolationMode);
        grPhoto.SmoothingMode = (System.Drawing.Drawing2D.SmoothingMode)smoothingMode;
        grPhoto.PixelOffsetMode = (System.Drawing.Drawing2D.PixelOffsetMode)pixelOffsetMode;

        grPhoto.DrawImage((System.Drawing.Image)bmp, new System.Drawing.Rectangle(0, 0, destWidth, destHeight),
            new System.Drawing.Rectangle(0, 0, sourceWidth, sourceHeight), System.Drawing.GraphicsUnit.Pixel);

        grPhoto.Dispose();

        textureData = new byte[4 * sourceWidth * sourceHeight];

        MemoryStream ms = new MemoryStream();
        ((System.Drawing.Bitmap)outputImage).Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);

        ms.Seek(0, SeekOrigin.Begin);
        Texture2D result = Texture2D.FromFile(gd, ms);
        ms.Dispose();
        sw.IntervalStop();
        sw.AppendResults("MEGS.txt");    

        return result;
    }

Funny thing is that HighQualityBicubic is much faster than Bicubic. (40ms vs 100ms)

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

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

发布评论

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

评论(2

素年丶 2024-09-07 01:34:41

你是如何用 C# 实现你的矩阵的?

在您的情况下,由于 .Net 默认情况下必须在矩阵数组中进行边界检查,因此可能会损失很多速度。在这种情况下,您可以使用不安全的 C# 使代码更快(从而消除任何边界检查)。

但是,如果它已经与外部方法一起工作得足够快,为什么不使用它们呢?

How did you implement your matrix in C#?

In your case a lot of speed could be lost due to .Net having to do bounds checks in a matrix array by default. In that case you could make your code much faster using unsafe C# (and thus removing any bounds checks).

But if it already works fast enough with the external methods why not use them?

﹏雨一样淡蓝的深情 2024-09-07 01:34:41

您是否尝试过使用 GetThumbnailImage方法?

进一步扩展Adam Robinson 的评论 :我希望您使用秒表类来计时?

Have you tried this with the GetThumbnailImage method?

To further extend Adam Robinson's comment: I hope you timed this using the Stopwatch class?

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