Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Работа с изображениями на Python в 2017 году

Работа с изображениями на Python в 2017 году

Александр Карпинский (lead backend developer @ uploadcare.com) @ Moscow Python Conf 2017
"Я работаю в компании Uploadcare и занимаюсь сервисом высокопроизводительной модификации изображений на лету. Некоторое время назад сделал ряд полезных изменений в популярной библиотеке для работы с изображениями Pillow. Параллельно развиваю свой форк Pillow-SIMD, нацеленный на максимальную производительность.
В докладе я расскажу, как наиболее эффективно можно решать задачи обработки изображений в современном Питоне. Какие есть инструменты, какие могут быть подводные камни. Поделюсь собственным опытом и наработками".
Видео: https://conf.python.ru/rabota-s-izobrazheniyami-na-python-v-2017-godu/

Avatar for Moscow Python Meetup

Moscow Python Meetup

October 20, 2017
Tweet

More Decks by Moscow Python Meetup

Other Decks in Programming

Transcript

  1. Чем занимаюсь Сервис обработки картинок на лету в Uploadcare. •

    Высокая производительность • Надежность • Масштабируемость • Построен на Pillow 2
  2. Pillow • Форк PIL (Python Imaging Library). 1995 год •

    Нативное расширение для Python • Версии Python: 2.7, 3.3+, pypy, pypy3 Сайт: python-pillow.org 4
  3. Pillow-SIMD • C мая 2016 года • Drop-in replacement for

    Pillow • Инструкции SSE4 (по умолчанию) и AVX2 Сайт: github.com/uploadcare/pillow-simd 5
  4. OpenCV • Расшифровывается Open Computer Vision. 2000 год • Биндинг

    на Python входит в комплект и очень популярен • Версии Python: 2.7, 3.4+, пока без pypy Сайт: opencv.org 6
  5. VIPS • 1993 год, обогнала своё время • Биндинг pyvips

    поддерживается автором • Версии Python: 2.7, 3.3+, pypy, pypy3 Сайт: jcupitt.github.io/libvips/ 7
  6. ImageMagick & GraphicsMagick • Очень популярная библиотека. 1990 год •

    Биндинг Wand использует ctypes, проект заброшен • Биндинг pgmagick использует Boost.Python, не работает в pypy Сайт: imagemagick.org, graphicsmagick.org 8
  7. 3 3, 3 Почему важно проверять результат from PIL import

    Image, ImageFilter.BoxBlur im.filter(ImageFilter.BoxBlur( )) ... import cv2 cv2.blur(im, ksize=( )) ... 01. 02. 03. 01. 02. 03. 10
  8. Ускорение в Pillow-SIMD • Ресайз: от 4 до 7 раз

    • Размытие: 2,8 раз • Применение ядра 3x3 или 5x5: 11 раз • Умножение и деление на альфа-канал: в 4 и 10 раза • Альфа-композиция: 5 раз • Еще что-то по мелочи 17
  9. Метрики производительности • Реальное время выполнения одной операций Важно на

    десктопе. • Пропускная способность потока операций Становится более важным на сервере. 22
  10. Способы параллельной работы 1. На уровне приложения Реальное время выполнения

    не меняется. Пропускная способность растет пропорционально количеству ядер. 23
  11. Способы параллельной работы 2. На уровне графических операций Реальное время

    выполнения уменьшается. Пропускная способность растет далеко не линейно от количества ядер. 24
  12. Способы параллельной работы 3. На уровне команд процессора и данных

    (SIMD) Реальное время выполнения уменьшается. Пропускная способность растет. Win-win. 25
  13. Правило N + 1 Создавать для обработки не более N

    + 1 воркеров, где N — количество ядер или потоков процессора. Воркер — процесс или поток, занятый обработкой. 28
  14. process_image Асинхронная работа Долгая работа процессора блокирует event loop, даже

    если библиотека отпускает GIL. @gen.coroutine def get(self, *args, **kwargs): im = (...) ... 01. 02. 03. 04. 29
  15. 1 yield Асинхронная работа @run_on_executor(executor=ThreadPoolExecutor( )) def process_image(self, ...): ...

    @gen.coroutine def get(self, *args, **kwargs): im = process_image(...) ... 01. 02. 03. 04. 05. 06. 07. 30
  16. %time 1.2 ms Ленивая загрузка >>> from PIL import Image

    >>> im = Image.open('cover.jpg') Wall time: >>> im.mode, im.size ('RGB', (2152, 1345)) 01. 02. 03. 04. 05. 32
  17. %time 1.2 ms %time 73.6 ms Ленивая загрузка >>> from

    PIL import Image >>> im = Image.open('cover.jpg') Wall time: >>> im.mode, im.size ('RGB', (2152, 1345)) >>> im.load() Wall time: 01. 02. 03. 04. 05. 06. 07. 33
  18. LOAD_TRUNCATED_IMAGES Режим битых картинок from PIL import Image, ImageFile ImageFile.

    = True Image.open('trucated.jpg').save('trucated.out.jpg') 01. 02. 03. 35
  19. Pillow VIPS OpenCV IM Количество кодеков 17 12+ 8 66

    Битые картинки ✅ ✅ ✅ ✅ Ленивая загрузка ✅ ✅ ❌ ❌ Чтение EXIF и ICC ✅ ✅ ❌ ✅ Автоповорот EXIF ❌ ✅ ✅ ✅ 36
  20. cv2.IMREAD_UNCHANGED Особенности OpenCV cv2.imread(filename, flags= ) • Оставляет альфа-канал у

    PNG-файлов • Перестает поворачивать JPEG-файлы 38
  21. Почему так? • Мало кодеков • Нет ленивой загрузки •

    Нет доступа к EXIF и ICC • Странное флаги OpenCV не рассчитан на работу с непроверенными источниками. 39
  22. numpy.array Решение Изображение в OpenCV — это массив numpy. import

    numpy from PIL import Image ... pillow_image = Image.open(filename) cv_image = (pillow_image) 01. 02. 03. 04. 05. 41
  23. Image.fromarray Решение import numpy from PIL import Image ... pillow_image

    = (cv_image, "RGB") pillow_image.save(filename) 01. 02. 03. 04. 05. 42