C# 和 .NET 3.5 中的图像调整大小效率

发布于 2024-08-03 15:01:56 字数 953 浏览 2 评论 0原文

我编写了一个 Web 服务来调整用户上传的图像大小,从功能的角度来看,一切都正常工作,但它会导致每次使用时 CPU 使用率飙升。它在 Windows Server 2008 64 位上运行。我尝试编译为 32 位和 64 位,得到的结果大致相同。

该服务的核心是这个函数:

private Image CreateReducedImage(Image imgOrig, Size NewSize)
{
    var newBM = new Bitmap(NewSize.Width, NewSize.Height);
    using (var newGrapics = Graphics.FromImage(newBM))
    {
        newGrapics.CompositingQuality = CompositingQuality.HighSpeed;
        newGrapics.SmoothingMode = SmoothingMode.HighSpeed;
        newGrapics.InterpolationMode = InterpolationMode.HighQualityBicubic;
        newGrapics.DrawImage(imgOrig, new Rectangle(0, 0, NewSize.Width, NewSize.Height));
    }

    return newBM;
}  

我在该服务上放置了一个探查器,它似乎表明绝大多数时间都花在 GDI+ 库本身上,而我的代码中没有太多收获。

问题: 我在这里的代码中是否做了一些明显低效的事情?看起来和我看到的例子很符合。

使用 GDI+ 以外的库有什么好处吗?我看到的基准测试似乎表明 GDI+ 与其他库相比表现良好,但我没有找到足够的信心。

使用“不安全代码”块有好处吗?

如果我没有包含足够的代码,请告诉我...我很乐意按照要求提供尽可能多的代码,但不想在帖子中变得令人讨厌。

I have written a web service to resize user uploaded images and all works correctly from a functional point of view, but it causes CPU usage to spike every time it is used. It is running on Windows Server 2008 64 bit. I have tried compiling to 32 and 64 bit and get about the same results.

The heart of the service is this function:

private Image CreateReducedImage(Image imgOrig, Size NewSize)
{
    var newBM = new Bitmap(NewSize.Width, NewSize.Height);
    using (var newGrapics = Graphics.FromImage(newBM))
    {
        newGrapics.CompositingQuality = CompositingQuality.HighSpeed;
        newGrapics.SmoothingMode = SmoothingMode.HighSpeed;
        newGrapics.InterpolationMode = InterpolationMode.HighQualityBicubic;
        newGrapics.DrawImage(imgOrig, new Rectangle(0, 0, NewSize.Width, NewSize.Height));
    }

    return newBM;
}  

I put a profiler on the service and it seemed to indicate the vast majority of the time is spent in the GDI+ library itself and there is not much to be gained in my code.

Questions:
Am I doing something glaringly inefficient in my code here? It seems to conform to the example I have seen.

Are there gains to be had in using libraries other than GDI+? The benchmarks I have seen seem to indicate that GDI+ does well compare to other libraries but I didn't find enough of these to be confident.

Are there gains to be had by using "unsafe code" blocks?

Please let me know if I have not included enough of the code...I am happy to put as much up as requested but don't want to be obnoxious in the post.

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

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

发布评论

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

评论(6

唠甜嗑 2024-08-10 15:01:56

图像处理通常是一项昂贵的操作。您必须记住,在应用程序开始任何类型的处理之前,32 位彩色图像会在内存中扩展为 4 * 像素宽度 * 像素高度。肯定会出现峰值,尤其是在进行任何类型的像素处理时。

话虽这么说,我认为您能够加快进程或降低对处理器的影响的唯一地方就是尝试较低质量的插值模式。

Image processing is usually an expensive operation. You have to remember that a 32 bit color image is expanded in memory into 4 * pixel width * pixel height before your app even starts any kind of processing. A spike is definitely to be expected especially when doing any kind of pixel processing.

That being said, the only place i could see you in being able to speed up the process or lowering the impact on your processor is to try a lower quality interpolation mode.

∞梦里开花 2024-08-10 15:01:56

您可以尝试

newGrapics.InterpolationMode = InterpolationMode.Low;

,因为 HighQualityBicubic 将是处理器最密集的重采样操作,但当然您会损失图像质量。

除此之外,我真的看不出可以采取任何措施来加速您的代码。 GDI+ 几乎肯定是 Windows 机器上最快的(用 C# 编写的代码不会超越纯 C 库),并且使用其他图像库存在不安全和/或有错误代码的潜在风险。

最重要的是,无论您做什么,调整图像大小都是一项昂贵的操作。最简单的解决方案是您的情况可能只是将服务器的 CPU 替换为更快的型号。

You could try

newGrapics.InterpolationMode = InterpolationMode.Low;

as HighQualityBicubic will be the most processor-intensive of the resampling operations, but of course you will then lose image quality.

Apart from that, I can't really see anything that can be done to speed up your code. GDI+ will almost certainly be the fastest on a Windows machine (no code written in C# is going to surpass a pure C library), and using other image libraries carries the potential risk of unsafe and/or buggy code.

The bottom line is, resizing an image is an expensive operation no matter what you do. The simplest solution is your case might simply be to replace your server's CPU with a faster model.

凉世弥音 2024-08-10 15:01:56

我知道随 Windows 7 一起发布的 DirectX 据说可以提供 2D 硬件加速。我不知道这是否意味着它会在这种操作上击败 GDI+。 MS 对 GDI 有相当不讨好的描述

如果你真的想尝试自己做这种事情,有一个很棒的 GDI 教程 显示了它。作者在教程的不同部分使用了 SetPixel 和“不安全块”。

顺便说一句,假设您的服务器有多个 CPU,多线程可能会对您有所帮助。也就是说,您可以一次处理多张图像,并且可能会更快地获得结果。

I know that the DirectX being released with Windows 7 is said to provide 2D hardware acceleration. Whether this implies it will beat out GDI+ on this kind of operation, I don't know. MS has a pretty unflattering description of GDI here which implies it is slower than it should be, among other things.

If you really want to try to do this kind of stuff yourself, there is a great GDI Tutorial that shows it. The author makes use of both SetPixel and "unsafe blocks," in different parts of his tutorials.

As an aside, multi-threading will probably help you here, assuming your server has more than one CPU. That is, you can process more than one image at once and probably get faster results.

戏剧牡丹亭 2024-08-10 15:01:56

当你写的时候

我编写了一个网络服务来调整大小
用户上传的图片

听起来用户将图像上传到(网络?)服务器,然后服务器调用网络服务来进行缩放?

如果是这种情况,我只需将缩放直接移至服务器即可。恕我直言,缩放图像并不能证明它自己的网络服务是合理的。从服务器到 Web 服务并返回时,您会收到相当多不必要的流量。特别是因为图像可能是 base64 编码的,这使得数据流量更大。

但我只是在这里猜测。

ps Unsafe 块本身不会带来任何好处,它们只是允许编译不安全的代码。因此,除非您编写自己的扩展路由,否则不安全的块不会有帮助。

When you write

I have written a web service to resize
user uploaded images

It sounds to mee that the user uploads an image to a (web?) server, and the server then calls a web service to do the scaling?

If that is the case, I would simply move the scaling directly to the server. Imho, scaling an image doesn't justify it's own web service. And you get quite a bit unnecessary traffic going from the server to the web service, and back. In particular because the image is probably base64 encoded, which makes the data traffic even bigger.

But I'm just guessing here.

p.s. Unsafe blocks in itself doesn't give any gain, they just allow unsafe code to be compiled. So unless you write your own scaling routing, an unsafe block isn't going to help.

鹿! 2024-08-10 15:01:56

您可能想尝试 ImageMagick。它是免费的,并且还有一个 .NET 包装器:单击此处。或者此处
或者您可以向 DOS Shell 发送命令。

我们时常在 Windows 服务器上使用 ImageMagick,用于批处理,有时用于更灵活的图像转换。

当然,也有商业组件,例如 Leadtools 和 Atalasoft 的组件。我们从未尝试过这些。

You may want to try ImageMagick. It's free, and there is also a .NET wrapper: click here. Or here.
Or you can send a command to a DOS Shell.

We have used ImageMagick on Windows Servers now and then, for batch processing and sometimes for a more flexible image conversion.

Of course, there are commercial components as well, like those by Leadtools and Atalasoft. We have never tried those.

半窗疏影 2024-08-10 15:01:56

我怀疑峰值是因为你直接启动了插值模式。所有插值模式均按像素工作,而 BiCubic 高质量大约是 GDI+ 所能达到的最高质量,因此我怀疑每像素计算正在消耗您的 CPU。
作为测试,尝试将插值模式降至 InterpolationModeNearestNeighbor 并查看 CPU 峰值是否下降 - 如果是这样,那就是罪魁祸首。
如果是这样,那么对成本与质量进行一些试验和错误,您可能不需要高质量 BiCubic 来获得不错的结果

I suspect the spike is because you have the interpolation mode cranked right up. All interpolation modes work per pixel and BiCubic High Quality is about as high as you can go with GDI+ so I suspect the per pixel calculations are chewing up your CPU.
As a test try dropping the interpolation mode down to InterpolationModeNearestNeighbor and see if the CPU spike drops - if so then that's your culprit.
If so then do some trial and error for cost vs quality, chances are you might not need High Quality BiCubic to get decent results

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