Эффективность изменения размера изображения в C # и .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 + хорошо сравнивается с другими библиотеками, но я не нашел их достаточно, чтобы быть уверенным.

Можно ли получить выгоду от использования блоков «небезопасного кода»?

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


person Matthew Nichols    schedule 31.08.2009    source источник
comment
Если вы запустите это в жестком цикле, сколько изображений в секунду вы сможете обработать при каких размерах входных / выходных изображений?   -  person Jonathan Rupp    schedule 31.08.2009
comment
Если я запускаю только часть кода, изменяющую размер изображения, локально, я могу изменить размер 1000 изображений за 45 секунд или около того. Введите 873x655, измените размер и обрежьте до 300x250.   -  person Matthew Nichols    schedule 03.09.2009
comment
Что-то определенно не так. Библиотека ImageResizer для ASP.NET внутренне использует GDI + и имеет намного более высокую пропускную способность. Я подозреваю, что это связано со способом обработки ввода-вывода - буферизация файлового потока в память перед созданием экземпляра Image / Bitmap устраняет определенные недостатки параллелизма.   -  person Lilith River    schedule 30.05.2013
comment
@ComputerLinguist Это было пару вакансий назад, поэтому у меня больше нет доступа к коду (и он больше не используется), поэтому сейчас я не могу это изучить. Буду иметь в виду, когда в следующий раз буду работать с GDI +.   -  person Matthew Nichols    schedule 30.05.2013


Ответы (6)


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

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

person Paul Sasik    schedule 31.08.2009

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

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

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

person Brian    schedule 31.08.2009

Вы могли бы попробовать

newGrapics.InterpolationMode = InterpolationMode.Low;

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

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

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

person Ian Kemp    schedule 31.08.2009

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

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

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

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

Но я здесь только предполагаю.

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

person Pete    schedule 31.08.2009

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

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

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

person Olaf    schedule 31.08.2009

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

person zebrabox    schedule 31.08.2009