Эффективность изменения размера изображения в С# и .NET 3.5
Я написал веб-службу для изменения размера загруженных пользователем изображений, и все работает правильно с функциональной точки зрения, но это заставляет процессор использовать шипы каждый раз, когда он используется. Он работает на 64-битной Windows Server 2008. Я попытался скомпилировать 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 + хорошо сравнивается с другими библиотеками, но я не нашел достаточного количества этих данных, чтобы быть уверенным.
Можно ли получить выгоды от использования блоков "небезопасного кода"?
Пожалуйста, дайте мне знать, если я не включил достаточное количество кода... Я рад поставить столько, сколько было запрошено, но не хочу быть неприятным в сообщении.
Ответы
Ответ 1
Обработка изображений обычно является дорогостоящей операцией. Вы должны помнить, что 32-битное цветное изображение расширяется в памяти в высоту пикселя шириной 4 * пикселя, прежде чем ваше приложение даже начнет любую обработку. Спайка, безусловно, следует ожидать, особенно при обработке любого пикселя.
Говоря это, единственное место, где я мог видеть, что вы можете ускорить процесс или снизить влияние на ваш процессор, - это попробовать режим интерполяции более низкого качества.
Ответ 2
Я знаю, что DirectX, выпущенный с Windows 7, как утверждается, обеспечивает аппаратное ускорение 2D. Не означает ли это, что он выдержит GDI + в этом виде операции, я не знаю. MS имеет довольно нелестное описание GDI здесь, что означает, что оно медленнее, чем должно быть, между прочим.
Если вы действительно хотите попробовать сделать этот материал самостоятельно, есть отличный GDI Tutorial, который показывает его. Автор использует как SetPixel, так и "небезопасные блоки" в разных частях своих учебных пособий.
В стороне, многопоточность, вероятно, поможет вам здесь, если на вашем сервере больше одного процессора. То есть вы можете обрабатывать более одного изображения одновременно и, вероятно, получать более быстрые результаты.
Ответ 3
Вы можете попробовать
newGrapics.InterpolationMode = InterpolationMode.Low;
как HighQualityBicubic
будет наиболее интенсивным в процессоре операций повторной дискретизации, но, конечно же, вы потеряете качество изображения.
Кроме того, я не вижу ничего, что можно было бы сделать для ускорения вашего кода. GDI + почти наверняка будет самым быстрым на Windows-машине (ни один код, написанный на С#, не превзойдет чистую библиотеку C), а использование других библиотек изображений несет потенциальный риск unsafe
и/или багги-кода.
Суть в том, что изменение размера изображения - дорогостоящая операция, независимо от того, что вы делаете. Самое простое решение - ваше дело может просто заменить ваш серверный процессор более быстрой моделью.
Ответ 4
Когда вы пишете
Я написал веб-сервис для изменения размера загруженные пользователем изображения
Звучит так, что пользователь загружает изображение на сервер (??), а затем сервер вызывает веб-службу для масштабирования?
Если это так, я просто переместил бы масштабирование непосредственно на сервер. Imho, масштабирование изображения не оправдывает его собственный веб-сервис. И вы получаете довольно ненужный трафик, идущий от сервера к веб-службе, и обратно. В частности, поскольку изображение, вероятно, кодируется base64, что делает трафик данных еще большим.
Но я просто догадываюсь здесь.
p.s. Небезопасные блоки сами по себе не дают никакой выгоды, они просто позволяют скомпилировать небезопасный код. Поэтому, если вы не написали свою собственную масштабирующую маршрутизацию, небезопасный блок не поможет.
Ответ 5
Возможно, вы захотите попробовать ImageMagick. Это бесплатно, и есть также оболочка .NET: нажмите здесь. Или здесь.
Или вы можете отправить команду в оболочку DOS.
Мы использовали ImageMagick на серверах Windows сейчас и затем, для пакетной обработки, а иногда и для более гибкого преобразования изображений.
Конечно, есть и коммерческие компоненты, такие как Leadtools и Atalasoft. Мы никогда этого не пробовали.
Ответ 6
Я подозреваю, что всплеск обусловлен тем, что режим интерполяции сработал правильно. Все режимы интерполяции работают на пиксель, а высокое качество BiCubic примерно такое же, как и у GDI +, поэтому я подозреваю, что вычисления на пиксель пережевывают ваш процессор.
В качестве теста попробуйте отключить режим интерполяции до InterpolationModeNearestNeighbor
и посмотреть, падает ли пик CPU - если это так, то ваш виновник.
Если это так, выполните некоторые пробные и ошибки для стоимости и качества, скорее всего, вам может не понадобиться BiCubic высокого качества, чтобы получить достойные результаты.