插值算法、C# 和 C++ 的速度一起工作
我需要快速实现流行的插值算法。我发现 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 技术交流群。
发布评论
评论(2)
您是否尝试过使用 GetThumbnailImage
方法?
进一步扩展Adam Robinson 的评论 :我希望您使用秒表类来计时?
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
你是如何用 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?