有没有办法使用可通过 .NET 应用程序消耗的 GPU(显卡)来调整图像大小?
我正在寻找一种非常高效的方法来调整图像大小,并且听说 GPU 可以比 CPU(使用 C# 的 GDI+)快得多。是否有已知的实现或示例代码使用 GPU 来调整我可以在 .NET 中使用的图像大小?
您是否考虑过使用 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();
}
我写了一个快速峰值来检查使用 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”)。
所以它可能会加速,我不知道。
卢克
是的,可以使用 GPU 来调整图像大小。这可以使用 DirectX Surfaces 来完成(例如在 C# 中使用 SlimDx)。您应该创建一个表面并将图像移动到该表面,然后您可以仅使用 GPU 将此表面拉伸到所需大小的另一个目标表面,最后从目标表面取回调整大小的图像。在这些情况下,表面的像素格式可能不同,GPU 会自动处理它。但是这里有些事情会影响此操作的性能。在 GPU 和 CPU 之间移动数据是一个耗时的过程。您可以根据自己的情况应用一些技术来提高性能,并避免 CPU 和 GPU 内存之间的额外数据传输。