Комментарии 14
Говорят что скорость библиотеки Pillow оставляет желать лучшего, все стараются переходить на OpenCV, особенно что касается применения различных фильтров и рисования.
Вообще, библиотеки каждая хорошая по своему, и есть ситуации когда и Pillow очень удобен. Думаю, преимущество OpenCV все же в большей мене обусловлено более богатом наборе инструментов, в т.ч. для многих задач комп. зрения.
Кто говорит, покажите?
Ну, например:
https://github.com/experiencor/keras-yolo3/issues/105
Когда нужно быстро читать и подготавливать изображения для глубокого обучения, CPU становится боттлнеком
Код с Pillow не нашёл, из opencv там используются следующие возможности:
- Загрузка/сохранение изображений
- Ресайз
- Некоторые операции в random_distort_image;
- Кроме того есть нанесение текста и рисование прямоугольников, как я понял для дебага, то есть не самая критичная к производительности часть
Загрузка/сохранение изображений по большей части выполняется готовыми библиотеками вроде libjpeg-turbo или libwebp, тут вряд ли есть существенные различия. Отмечу лишь, что во время создания тикета пакет opencv-contrib-python
, который есть в requirements.txt
, собирался с обычной версией libjpeg, которая в несколько раз медленнее. Кроме того, после декодирования меняется порядок байт с BGR на RGB, что не добавляет скорости.
Про ресайз в OpenCV могу сказать, что он сломан для многих сочетаний размеров. Я к сожалению не понял из исходников, несколько сильный используется ресайз, в зависимости от этого результат OpenCV будет либо неверен и можно использовать супербыстрый фильтр nearest neighbor, либо результаты Pillow-SIMD с биллинейным фильтром будут не хуже.
В функции random_distort_image
происходят интересные вещи и казалось бы тут уж Pillow нечем ответить. Но нет, все это укладывается в рамки операций, которые можно сделать с помощью 3D color LUT, что будет работать с константной скоростью для любого сочетания параметров. А конкретнее 50 мегапикселей/cек для Pillow и почти 400 мегапикселей/cек для Pillow-SIMD. Сама же функция random_distort_image
работает со скоростью 41 мегапиксель/сек.
То есть по чистой производительности на ядро, Pillow, а тем более Pillow-SIMD для этих зада был бы быстрее. Единственное, с чем могли бы возникнуть проблемы — распараллеливание на несколько ядрер. Но тут я приверженец максимальной утилизации ресурсов, а для этого нужно запускать несколько задач параллельно, а не параллелить одну задачу внутри. А для этого в OpenCV тоже нет ничего встроенного.
Получается, зря говорят?
Если что-то сломано в OpenCV — просим открыть баг репорт. Вообще, билинейная интерполяция это одна из священных войн всего CV где решается вопрос непортируемости и нет победителей и не будет. В том же DL нельзя так просто исправить даже забагованную реализацию, потому что все натренированные к тому моменту сети разойдутся. Взять пример How Tensorflow’s tf.image.resize stole 60 days of my life. А для параллелизма есть встроенный в OpenCV parallel_for о применении которого можно почитать в нашей статье https://m.habr.com/ru/company/intel/blog/489884/.
Если что-то сломано в OpenCV — просим открыть баг репорт. Вообще, билинейная интерполяция это одна из священных войн всего CV где решается вопрос непортируемости и нет победителей и не будет.
Так зачем просите писать, если знаете, что толку не будет? Вот например давно открытый ишью про ресайз.
Можете как раз взять пример из статьи на которую вы дали ссылку, там очень показательный пример. Только отресайзить его не в 4x4, а даже 3x3. Как это может превратиться в это?
оригинал, cv2.INTER_LINEAR
, cv2.INTER_CUBIC
А должно получиться во всех случаях что-то вроде такого:
cv2.INTER_AREA
, PIL.Image.LINEAR
, PIL.Image.LANCZOS
И с NEAREST такие же проблемы, что в той статье:

для параллелизма есть встроенный в OpenCV parallel_for
Так я и говорю, что параллелизм на уровне одной операции всегда менее эффективен, чем распараллеливание нескольких операций, потому что есть а) накладные расходы на логику, запуск тредов, синхронизацию б) всегда найдется узкое место, которое не удастся распараллелить. Например код на питоне.
Например, в реальных проектах часто требуется поворачивать изображение согласно ориентации в EXIF (загрузил пользователь аватарку, которая снята на смартфон и бац, ориентация не верная).
Начиная с 6-й версии это делает вот так:
from PIL import ImageOps
image = ImageOps.exif_transpose(image)
и никакой больше возни. И таких «плюшек», про которых не говорят в подобных туториалах, очень много.
Введение в обработку изображений в Python при помощи Pillow