4

有没有办法使用可通过 .NET 应用程序消耗的 GPU(显卡)来调整图像大小?

我正在寻找一种非常高效的方法来调整图像大小,并且听说 GPU 可以比 CPU(使用 C# 的 GDI+)快得多。是否有已知的实现或示例代码使用 GPU 来调整我可以在 .NET 中使用的图像大小?

4

3 回答 3

6

您是否考虑过使用 XNA 调整图像大小?在这里,您可以了解如何使用 XNA 将图像作为 png/jpeg 保存到 MemoryStream 中,然后再将其重用为 Bitmap 对象:

编辑:我将在此处发布一个示例(取自上面的链接),说明如何使用 XNA。

public static Image Texture2Image(Texture2D texture)
{
    Image img;
    using (MemoryStream MS = new MemoryStream())
    {
        texture.SaveAsPng(MS, texture.Width, texture.Height);
        //Go To the  beginning of the stream.
        MS.Seek(0, SeekOrigin.Begin);
        //Create the image based on the stream.
        img = Bitmap.FromStream(MS);
    }
    return img;
 }

我今天还发现你可以使用 OpenCV 来使用 GPU/多核 CPU。例如,您可以选择使用 .NET 包装器(例如Emgu)并使用其 Image 类来操作您的图片并返回 .NET Bitmap 类:

public static Bitmap ResizeBitmap(Bitmap sourceBM, int width, int height)
{
    // Initialize Emgu Image object
    Image<Bgr, Byte> img = new Image<Bgr, Byte>(sourceBM); 

    // Resize using liniear interpolation
    img.Resize(width, height, INTER.CV_INTER_LINEAR);

    // Return .NET Bitmap object
    return img.ToBitmap();
}
于 2012-10-29T23:32:39.433 回答
1

我写了一个快速峰值来检查使用 WPF 的性能,尽管我不能肯定地说它使用了 GPU。

不过,请参见下文。这会将图像缩放到其原始大小的 33.5(或其他)倍。

public void Resize()
{
    double scaleFactor = 33.5;

    var originalFileStream = System.IO.File.OpenRead(@"D:\SkyDrive\Pictures\Random\Misc\DoIt.jpg");

    var originalBitmapDecoder = JpegBitmapDecoder.Create(originalFileStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);

    BitmapFrame originalBitmapFrame = originalBitmapDecoder.Frames.First();

    var originalPixelFormat = originalBitmapFrame.Format;

    TransformedBitmap transformedBitmap =
        new TransformedBitmap(originalBitmapFrame, new System.Windows.Media.ScaleTransform()
        {
            ScaleX = scaleFactor,
            ScaleY = scaleFactor
        });

    int stride = ((transformedBitmap.PixelWidth * transformedBitmap.Format.BitsPerPixel) + 7) / 8;
    int pixelCount = (stride * (transformedBitmap.PixelHeight - 1)) + stride;

    byte[] buffer = new byte[pixelCount];

    transformedBitmap.CopyPixels(buffer, stride, 0);

    WriteableBitmap transformedWriteableBitmap = new WriteableBitmap(transformedBitmap.PixelWidth, transformedBitmap.PixelHeight, transformedBitmap.DpiX, transformedBitmap.DpiY, transformedBitmap.Format, transformedBitmap.Palette);

    transformedWriteableBitmap.WritePixels(new Int32Rect(0, 0, transformedBitmap.PixelWidth, transformedBitmap.PixelHeight), buffer, stride, 0);

    BitmapFrame transformedFrame = BitmapFrame.Create(transformedWriteableBitmap);

    var jpegEncoder = new JpegBitmapEncoder();
    jpegEncoder.Frames.Add(transformedFrame);

    using (var outputFileStream = System.IO.File.OpenWrite(@"C:\DATA\Scrap\WPF.jpg"))
    {
        jpegEncoder.Save(outputFileStream);
    }
}

我正在测试的图像是 495 x 360。它在几秒钟内将其大小调整到超过 16k x 12k,包括保存。

在单核运行中,它以每秒 165 次左右的速度将大小调整为 1.5 倍。在 i7 和 GPU 上似乎什么都不做,20% 的 CPU 我希望在多线程时获得 5 倍以上。

性能分析显示了一个热门路径,wpfgfx_v0400.dll该路径是本机 WPF 图形库,并且接近 DirectX(在 Google 中查找“milcore”)。

所以它可能会加速,我不知道。

卢克

于 2014-03-20T16:43:52.227 回答
0

是的,可以使用 GPU 来调整图像大小。这可以使用 DirectX Surfaces 来完成(例如在 C# 中使用 SlimDx)。您应该创建一个表面并将图像移动到该表面,然后您可以仅使用 GPU 将此表面拉伸到所需大小的另一个目标表面,最后从目标表面取回调整大小的图像。在这些情况下,表面的像素格式可能不同,GPU 会自动处理它。但是这里有些事情会影响此操作的性能。在 GPU 和 CPU 之间移动数据是一个耗时的过程。您可以根据自己的情况应用一些技术来提高性能,并避免 CPU 和 GPU 内存之间的额外数据传输。

于 2015-04-05T10:33:11.143 回答