Is there a way to resize an image using GPU?

☆樱花仙子☆ 提交于 2019-12-22 08:19:58

问题


Is there a way to resize an image using GPU (graphic card) that is consumable through a .NET application?

I am looking for an extremely performant way to resize images and have heard that the GPU could do it much quicker than CPU (GDI+ using C#). Are there known implementations or sample code using the GPU to resize images that I could consume in .NET?


回答1:


Have you thought about using XNA to resize your images? Here you can find out how to use XNA to save image as a png/jpeg to a MemoryStream and later reuse it a Bitmap object:

EDIT: I will post an example here (taken from the link above) on how you can possibly use 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;
 }

I also found out today that you can OpenCV to use GPU/multicore CPUs. You can for example choose to use a .NET wrapper such as Emgu and and use its Image class to manipulate with your picture and return a .NET Bitmap class:

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



回答2:


I wrote a quick spike to check performance using WPF, though I cannot for sure say that its using the GPU.

Still, see below. This scales an image to 33.5 (or whatever) times its original size.

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

The image I was testing was 495 x 360. It resized it to over 16k x 12k in a couple of seconds, including save out.

It resizes to 1.5x around 165 times a second in a single-core run. On an i7 and the GPU seemingly doing nothing, CPU at 20% I'd expect to get 5x more when multithreaded.

Performance profiling shows a hot path to wpfgfx_v0400.dll which is the native WPF graphics library and is close to DirectX (look-up 'milcore' in Google).

So it might be accelerated, I don't know.

Luke




回答3:


Yes, it is possible to use GPU to resize your images. This can be done using DirectX Surfaces (for example using SlimDx in C#). You should create a surface and move your image to it, and then you can stretch this surface to another target surface of your desired size using only GPU, and finally get back the resized image from the target surface. In these scenario, pixel format of the surfaces can be different and the GPU automatically handles it. But here there are things that can affect the performance of this operation. Moving data between GPU and CPU is a time consuming process. You can apply some techniques to boost performance based on your situation, and avoiding extra data transfer between CPU and GPU memory.



来源:https://stackoverflow.com/questions/13130758/is-there-a-way-to-resize-an-image-using-gpu

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!