Fast Image resize: OpenCV + IPP vs. Convert ImageMagick

Скорость изменения размера изображения важна во многих ситуациях. Верить наслово, что Intel IPP будет в ресайзе всех рвать нельзя и надо провести тестирование.

Методика тестирования 

Моя задача в тесте: изменить размер JPEG рисунка в три раза с 1748x2480 до 583x827 с q=95 и применением фильтра Lanczos при интерполяции.

Сервер: 16 vCPU Xeon X5670 2.93 GHz, 12GB RAM, vmWare vSphere ESXi-5.1.0, guest CentOS6 x64

Рекламируемый во многих местах Intel IPP платный, но для OpenSource проектов он бесплатен и я использовал его вместе с OpenCV 3.1, собранным из исходников с https://github.com/Itseez/opencv/

В качестве альтернативы выступил ImageMagic 6.7.2.7 / GraphicsMagic 1.3.20 с libjpeg-turbo 1.2.1

OpenCV тестировался с разными опциями: OpenMP, TBB, IPP и без оных.

Тесты прогонялись на одном рисунке по 100 раз для получения усредненного значения.

Задача ресайза для OpenCV запускалась из python, т.е. содержит дополнительные расходы на враппер, при этом python 2.6 запускался один раз и затем 100 раз читал, ресайзил и записывал рисунок, в то время как ImageMagic/GraphicsMagick запускались все сто раз из шела.

Меня интересовала скорость ресайза только JPEG. Остальные возможноси OpenCV не интересовали и все рекомендации по компилированию OpenCV даны именно для задачи ресайза.

Во время проведения теста обращение к диску было минимальным, а дисковая подсистема являет собой систему хранения среднего уровня IBM DS5300 с RAID5 и производительностью около 2000 IOPS. Т.е. в диски задача не упиралась.

Т.к. все работает под вирутальной машиной, другие оптимизации OpenCV: CUDA, Intel VA и т.п. не использовались.

Конвертация ImageMagick

/usr/bin/convert page-1.jpg -quality 95 -filter Lanczos -scale 583x827 /tmp/outc.jpg

Конвертация GraphicsMagick

/usr/bin/gm -convert page-1.jpg -quality 95 -filter Lanczos -scale 583x827 /tmp/outc.jpg

Компиляция OpenCV

Пример компиляции, использованный в конечных результатах для CentOS6:

cmake -D BUILD_opencv_python2=ON \
BUILD_opencv_python3=OFF \
-DPYTHON_EXECUTABLE=/usr/bin/python2.6 -DPYTHON2_INCLUDE_DIR=/usr/include/python2.6 -DPYTHON_LIBRARY=/usr/lib64/libpython2.6.so.1.0 \
-DPYTHON2_NUMPY_INCLUDE_DIRS=/usr/lib64/python2.6/site-packages/numpy/core/include/numpy \
-DPYTHON2_PACKAGES_PATH=/usr/lib64/python2.6/site-packages \
-DBUILD_opencv_world=OFF \
-DBUILD_PYTHON_SUPPORT=ON \
-DBUILD_DOCS=OFF \
-DBUILD_EXAMPLES=ON  \
-DBUILD_JPEG=ON \
-DBUILD_OPENEXR=OFF \
-DBUILD_PACKAGE=ON \
-DBUILD_PERF_TESTS=OFF  \
-DBUILD_PNG=ON  \
-DBUILD_SHARED_LIBS=OFF \
-DBUILD_TBB=OFF \
-DBUILD_TESTS=OFF \
-DBUILD_TIFF=OFF \
-DBUILD_WITH_DEBUG_INFO=OFF \
-DBUILD_ZLIB=OFF \
-DWITH_1394=OFF \
-DWITH_EIGEN=ON \
-DWITH_FFMPEG=OFF \
-DWITH_GIGEAPI=OFF \
-DWITH_GSTREAMER=OFF \
-DWITH_GTK=OFF \
-DWITH_IPP=ON \
-DWITH_JASPER=OFF \
-DWITH_JPEG=ON \
-DWITH_LIBV4L=OFF \
-DWITH_OPENCL=OFF \
-DWITH_OPENCLAMDBLAS=OFF \
-DWITH_OPENCLAMDFFT=OFF \
-DWITH_OPENEXR=OFF \
-DWITH_OPENGL=OFF \
-DWITH_OPENMP=OFF \
-DWITH_OPENNI=OFF \
-DWITH_PNG=ON \
-DWITH_PVAPI=OFF \
-DWITH_QT=OFF \
-DWITH_TBB=OFF \
-DWITH_TIFF=OFF \
-DWITH_UNICAP=OFF \
-DWITH_V4L=OFF \
-DWITH_XIMEA=OFF \
-DWITH_XINE=OFF \
-Wno-dev ../

Результаты

Включение OpenMP в OpenCV приводило к значительному росту нагрузки на ядра сервера и к увеличению времени исполнения задачи примерно в два раза. Вывод однозначен: OpenMP крайне вреден и его использовать не следует.

Также были протестированы различные алгоритмы интерполяции для OpenCV и к существенному изменению времени генерации они не привели.

Отключение ускорения ресайза (или компиляция без IPP) не приводят к росту производительности. Глядя на исходники, стало понятно почему:
OpenCV для ресайза не задействует IPP если ресайзится рисунок с 8 битами на цвет и используются фильтры отличные от линейного или кубического. Что стало ясно из 3283 строки функции cv::resize в файле  https://github.com/Itseez/opencv/blob/f95203e93fdaf5997c22d8d9230d14f21b17d74e/modules/imgproc/src/imgwarp.cpp

Я добавил в описанный файл отладочный код, показывавший используется ли IPP и подсунул рисунок PNG с 16 битами на цвет. Отладочный код показал форсирование IPP, но итоговый результат на конвертацию так и остался близким к ресайзу без использования IPP.

Включение TBB также на уровне погрешности измерений к улучшению не привело, поэтому не вижу смысла в компиляции с ним.

Кроме встроенной функции ресайза в OpenCV есть функция аффинных преобразований. При помощи нее также можно ресайзить рисунки, но скорость падает в разы.

ImageMagick ресайзит за 170 мс с примерным разбросом 3 мс.

GraphicsMagic ресайзит за 120 мс с примерным разбросом 1 мс.

OpenCV + IPP ресайзит за 107 мс с самым большим разбросом в 5 мс.

Победителем стал OpenCV. На минимальные 10% от него отстал GraphicsMagick и на 65% ImageMagick.

Но, на практике, если при каждом ресайзе рисунка полностью загружать OpenCV через python, произойдет увеличение времени ресайза почти в три раза, в связи с чем либо следует переписать программу на C, либо OpenCV + ipp + python оказывается медленнее GraphicsMagick.

Сколько стоит конвертация

В код OpenCV вставлены счетчики измерения времени на чтение файла, ресайз и сохранение. В миллисекундах получается, что время чтения 88 мс, время конвертации 2.8 мс, время записи 17 мс. Отсюда ясно, что можно пользоваться для ресайза тяжелыми алгоритмами, а большая часть времени уходит на чтение.

Однако, если этот же тест запускать последовательно, каждый раз для ресайза запуская заново интерпретатор, то время чтения почти не меняется, время ресайза увеличивается в 4 раза до 12 мс, а время записи возрастает в семь раз до 114 мс.

Качество

Алгоритмы ресайза одинаковые, качество jpeg-сжатия 95%. Но...

У ImageMagick и GraphicsMagic визуально результат одинаковый, а вот если их сравнить с OpenCV + IPP, то в случае с текстом читать явно удобней GraphicsMagick:

Исходники для сравнения

Original

OpenCV + IPP



GraphicsMagick

Выводы

OpenCV с IPP должен быть быстрее всех, но если не использовать враппер на python и подсовывать рисунки более 8 бит на цвет. При использовании с python и вызовом из командной строки на каждый ресайз эта связка проигрывает GraphicsMagick из-за накладных расходов на запуск интерпретатора python. Также внутри кода OpenCV для функции ресайза есть оптимизации для Tegra и OpenCL. Они идут раньше IPP и, при ресайзе в большом качестве их тоже можно опробовать.

Минимальное отставание GraphicsMagick в задаче при заметно меньших хлопотах в CentOS с установкой делает для меня эту программу победителем.

ImageMagick проигрывает всем, его следует избегать. Народ где-то в интернетах писал, что из-за неоптимизированной записи.

Самое печальное, что ожидания кардинального улучшении скорости ресайза не сбылись и IPP никаких чудес не показал (впрочем, и не мог, как выяснилось из ознокомления исходников). Причина близости результата IPP к jpeg-turbo кроется в уже хорошей оптимизации jpeg-turbo в плане работы на процессорах с SSE2 и в том, что ресайз сам по-себе занимает на порядок меньше времени, чем чтение+декодирование и кодирование+запись.

В связи с чем, резона покупать IPP для ресайза картинок я не вижу и надо искать способы ускорения кодирования и декодирования. Конечно, я не затрагивал OpenCV CUDA и есть другие механизмы ускорения изменения размера, но в моем случае они не особо подходят т.к. я не хочу требовать от своего проекта наличие CUDA-видеокарты в сервере. Хотя...

Популярные сообщения из этого блога

Как оживить корпоративный сайт?

Мастерим компьютер для прямых интернет трансляций и записи с видеокамеры или системы ВКС

Тестирование производительности Drupal: MySQL vs PostgreSQL часть 2