yokotoka
@yokotoka
Python guru

Как заставить логику Pillow.Image.alpha_composite выполняться на GPU?

Привет!

В библиотеке Pillow у класса Image есть замечательная функция - alpha_composite. Если ей подсунуть два Image в RGBA профиле, то она очень правильно склеит два изображения, а именно:
1. Если у обоих картинок были прозрачные области - то в результирующем изображении тоже будет прозрачно.
2. Если у той, что кладётся сверху полупрозрачная область - то та что снизу будет правильно "просвечивать" через верхнюю
3. Если сверху непрозрачное - то оно игнорирует нижележащие пиксели.

Проблема в том, что она делает это достаточно медленно. Я запускал в multiprocessing на всех ядрах, но похоже что для CPU это предел, даже Pillow-SIMD не даёт заметного выигрыша.

Поэтому я обратил внимание на GPU. Но тут возникла другая проблема - ни одна другая библиотека, которую я попробовал не имеет режима, в котором работает Pillow.Image.alpha_composite - либо я не разобрался. OpenCV во всех режимах, в которых я пробовал и по всем советам с SO делает не то что нужно - прозрачные пиксели верхнего изображения либо не учитываются, либо на прозрачный цвет заменяется чёрный в самом изображении. pyVips в режиме Image.composite делает то же что и OpenCV.

Подскажите, пожалуйста, как клеить изображения по типу Pillow.Image.alpha_composite на GPU? Возможно даже не в Python.
  • Вопрос задан
  • 152 просмотра
Пригласить эксперта
Ответы на вопрос 1
ScriptKiddo
@ScriptKiddo
даже Pillow-SIMD не даёт заметного выигрыша

Если Pillow-SIMD не дает выигрыша - то значит проблема в чем-то другом.

Судя по бенчмаркам - выигрыш в производительности до 4 раз при наличии AVX2
https://python-pillow.org/pillow-perf/

617f1e0022dc4129640400.png

Обратите внимание, что компилировать Pillow-SIMD с поддержкой AVX2 нужно самостоятельно

$ pip uninstall pillow
$ CC="cc -mavx2" pip install -U --force-reinstall pillow-simd


Также, сжатие изображения при сохранении потребляет значительную часть ресурсов.
Изображения PNG можно сжимать менее агрессивно примерно так:

im.save('png.png', compress_level=1)
Для сохранения в JPEG, если не нужна прозрачность после объединения, требуется установить SIMD версию libjpeg - libjpeg-turbo

https://fastai1.fast.ai/performance.html#is-jpeg-c...

Содержание ссылки

Is JPEG compression SIMD-optimized?
libjpeg-turbo replacement for libjpeg is SIMD-optimized. In order to get Pillow or its faster fork Pillow-SIMD to use libjpeg-turbo, the latter needs to be already installed during the former’s compilation time. Once Pillow is compiled/installed, it no longer matters which libjpeg version is installed in your virtual environment or system-wide, as long as the same libjpeg library remains at the same location as it was during the compilation time (it’s dynamically linked).

However, if at a later time something triggers a conda or pip update on Pillow it will fetch a pre-compiled version which most likely is not built against libjpeg-turbo and replace your custom built Pillow or Pillow-SIMD.

Here is how you can see that the PIL library is dynamically linked to libjpeg.so:

cd ~/anaconda3/envs/fastai/lib/python3.6/site-packages/PIL/
ldd _imaging.cpython-36m-x86_64-linux-gnu.so | grep libjpeg
libjpeg.so.8 => ~/anaconda3/envs/fastai/lib/libjpeg.so.8
and ~/anaconda3/envs/fastai/lib/libjpeg.so.8 was installed by conda install -c conda-forge libjpeg-turbo. We know that from:

cd ~/anaconda3/envs/fastai/conda-meta/
grep libjpeg.so libjpeg-turbo-2.0.1-h470a237_0.json
If I now install the normal libjpeg and do the same check on the jpeg’s package info:

conda install jpeg
cd ~/anaconda3/envs/fastai/conda-meta/
grep libjpeg.so jpeg-9b-h024ee3a_2.json

I find that it’s lib/libjpeg.so.9.2.0 (~/anaconda3/envs/fastai/lib/libjpeg.so.9.2.0).

Also, if libjpeg-turbo and libjpeg happen to have the same version number, even if you built Pillow or Pillow-SIMD against libjpeg-turbo, but then later replaced it with the default jpeg with exactly the same version you will end up with the slower version, since the linking happens at build time. But so far that risk appears to be small, as of this writing, libjpeg-turbo releases are in the 8.x versions, whereas jpeg’s are in 9.x’s.

How to tell whether Pillow or Pillow-SIMD is using libjpeg-turbo?
You need Pillow>=5.4.0 to accomplish the following (install from github until then: pip install git+https://github.com/python-pillow/Pillow).

python -c "from PIL import features; print(features.check_feature('libjpeg_turbo'))"
True
And a version-proof check:

from PIL import features, Image
from packaging import version

try: ver = Image.__version__ # PIL >= 7
except: ver = Image.PILLOW_VERSION # PIL < 7

if version.parse(ver) >= version.parse("5.4.0"):
if features.check_feature('libjpeg_turbo'):
print("libjpeg-turbo is on")
else:
print("libjpeg-turbo is not on")
else:
print(f"libjpeg-turbo' status can't be derived - need Pillow(-SIMD)? >= 5.4.0 to tell, current version {ver}")

Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы