Эффективность изменения размера изображения в C # и .NET 3.5 - PullRequest
15 голосов
/ 31 августа 2009

Я написал веб-сервис для изменения размера загружаемых пользователем изображений, и все работает правильно с функциональной точки зрения, но это приводит к резкому увеличению загрузки ЦП при каждом его использовании. Он работает на 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 + хорошо сравнивается с другими библиотеками, но я не нашел их достаточно, чтобы быть уверенным.

Есть ли выгоды от использования блоков "небезопасного кода"?

Пожалуйста, дайте мне знать, если я не включил достаточное количество кода ... Я счастлив выложить столько, сколько просили, но не хочу быть неприятным в посте.

Ответы [ 6 ]

6 голосов
/ 31 августа 2009

Обработка изображений обычно является дорогостоящей операцией. Вы должны помнить, что 32-битное цветное изображение расширяется в памяти до 4 * ширины пикселя * высоты пикселя, прежде чем ваше приложение даже начнет какую-либо обработку. Определенно следует ожидать всплеска, особенно при выполнении любых видов обработки пикселей.

При этом единственное место, где я могу видеть вас в том, что вы можете ускорить процесс или снизить нагрузку на ваш процессор - это попробовать режим интерполяции низкого качества.

3 голосов
/ 31 августа 2009

Я знаю, что DirectX, выпущенный с Windows 7, как говорят, обеспечивает аппаратное ускорение 2D. Означает ли это, что это побьет GDI + на такого рода операции, я не знаю. У MS довольно нелестное описание GDI здесь , что подразумевает, что он медленнее, чем должен быть, среди прочего.

Если вы действительно хотите попробовать себя в этом, есть отличный учебник по GDI , который это показывает. Автор использует как SetPixel, так и «небезопасные блоки» в различных частях своих руководств.

Кроме того, многопоточность, вероятно, поможет вам в этом, если ваш сервер имеет более одного процессора. То есть вы можете обрабатывать более одного изображения одновременно и, возможно, получать более быстрые результаты.

2 голосов
/ 31 августа 2009

Вы можете попробовать ImageMagick. Это бесплатно, и есть также. NET обертка: нажмите здесь . Или здесь . Или вы можете отправить команду в оболочку DOS.

Время от времени мы использовали ImageMagick на серверах Windows для пакетной обработки, а иногда и для более гибкого преобразования изображений.

Конечно, есть и коммерческие компоненты, такие как Leadtools и Atalasoft. Мы никогда не пробовали их.

2 голосов
/ 31 августа 2009

Когда вы пишете

Я написал веб-сервис для изменения размера загруженные пользователем изображения

Мне кажется, что пользователь загружает изображение на (веб?) Сервер, а затем сервер вызывает веб-сервис для масштабирования?

Если это так, я бы просто перенес масштабирование прямо на сервер. Имхо, масштабирование изображения не оправдывает его собственный веб-сервис. И вы получаете совсем немного ненужного трафика, идущего с сервера на веб-сервис и обратно. В частности, потому что изображение, вероятно, закодировано в base64, что делает трафик данных еще больше.

Но я просто догадываюсь здесь.

p.s. Небезопасные блоки сами по себе не дают никакой выгоды, они просто позволяют скомпилировать небезопасный код. Поэтому, если вы не напишите свою собственную маршрутизацию масштабирования, небезопасный блок не поможет.

2 голосов
/ 31 августа 2009

Вы можете попробовать

newGrapics.InterpolationMode = InterpolationMode.Low;

при HighQualityBicubic будет наиболее ресурсоемким из операций ресэмплирования, но, конечно, вы потеряете качество изображения.

Кроме того, я не вижу ничего, что можно сделать для ускорения вашего кода. GDI + почти наверняка будет самым быстрым на машине Windows (никакой код, написанный на C #, не превзойдет чистую библиотеку C), а использование других библиотек изображений несет потенциальный риск unsafe и / или ошибок в коде.

Суть в том, что изменение размера изображения - дорогостоящая операция, независимо от того, что вы делаете. Самое простое решение в вашем случае - просто заменить процессор вашего сервера более быстрой моделью.

0 голосов
/ 31 августа 2009

Я подозреваю, что всплеск вызван тем, что у вас режим интерполяции запущен. Все режимы интерполяции работают на пиксель, а BiCubic High Quality примерно такой же высокий, как вы можете использовать GDI +, поэтому я подозреваю, что расчеты на пиксель затрачивают ресурсы вашего процессора.
В качестве теста попробуйте опустить режим интерполяции до InterpolationModeNearestNeighbor и посмотреть, снизится ли всплеск процессора - если это так, то это ваш виновник.
Если это так, то сделайте несколько проб и ошибок в соотношении цены и качества, скорее всего, вам не понадобится высококачественный BiCubic для получения достойных результатов

...