5.7. Композиция изображений¶
Примитивы рисования с предыдущей страницы наносят на изображение геометрические метки – линию, прямоугольник, фрагмент текста. Это покрывает большинство аннотаций, которые алгоритму нужно сделать видимыми, но не все из них. Иногда аннотация сама является изображением: захваченный опорный кадр для отображения рядом с текущим, миниатюра предыдущего захвата, показанная в углу предпросмотра, ранее сохранённый шаблон, визуализированный поверх живого кадра для калибровки. Механизм рисования одного изображения поверх другого – это единственный метод – draw_image() – с достаточным числом параметров, чтобы управлять положением, масштабированием, цветовой палитрой и прозрачностью, необходимыми для настоящей композиции.
5.7.1. Базовый вызов¶
В простейшей форме draw_image принимает другое Image и позицию, в которой его нужно нарисовать:
reference = image.Image("/sdcard/reference.bmp")
img.draw_image(reference, x=10, y=10)
Назначение – это img; источник – это reference; верхний левый пиксель источника попадает в (10, 10) изображения img, а остальные пиксели источника следуют от него вправо и вниз. Пиксели назначения, которые покрывает источник, перезаписываются соответствующими пикселями источника; пиксели за пределами области источника остаются нетронутыми.
Если источник выходит за край назначения, выпадающие части молча обрезаются – то же снисходительное поведение, что и у set_pixel для позиций вне диапазона. Прикладному коду не нужно заранее ограничивать позицию размерами изображения; он может передать желаемую позицию и позволить методу самому обработать обрезку.
5.7.2. Загрузка файла на лету¶
draw_image принимает путь к файлу вместо аргумента Image и загружает файл перед его компоновкой:
img.draw_image("/sdcard/reference.bmp", x=10, y=10)
Это выглядит как удобство – одна строка вместо двух – и так оно и есть, но разница больше, чем синтаксис. Создание Image из файла выделяет буфер для хранения декодированных пикселей, и этот буфер существует до тех пор, пока сборка мусора не освободит его. Передача пути напрямую в draw_image позволяет модулю декодировать файл во временный буфер, выполнить композицию из него и освободить буфер по завершении вызова, не требуя, чтобы прикладной код удерживал ссылку на отдельный Image между кадрами.
5.7.3. Масштабирование¶
Когда источник и назначение имеют разные размеры – захват низкого разрешения, компонуемый на холст более высокого разрешения, или миниатюра, которой нужно придать размер определённой доли кадра – два параметра масштаба заботятся об изменении размера источника при его рисовании:
img.draw_image(reference, x=10, y=10, x_scale=2.0, y_scale=2.0)
x_scale и y_scale – это независимые числа с плавающей точкой; передача обоих с одинаковым значением масштабирует равномерно, а передача разных значений растягивает или сжимает источник вдоль одной оси. Масштабирование происходит во время рисования; источник reference не изменяется.
Битовая маска флагов-подсказок (hint) решает, как масштабирование фактически интерполирует между пикселями. image.BILINEAR даёт более гладкие результаты ценой больших вычислений; image.BICUBIC даёт ещё более гладкие результаты и стоит ещё дороже; по умолчанию используется метод ближайшего соседа, который является самым дешёвым и правильным выбором, когда источник уже находится в пиксельном разрешении назначения. Флаги обработки соотношения сторон – SCALE_ASPECT_KEEP, SCALE_ASPECT_EXPAND, SCALE_ASPECT_IGNORE – решают, что делать, когда соотношение сторон источника не соответствует прямоугольнику, в который он рисуется.
5.7.4. Альфа-смешивание¶
По умолчанию draw_image заменяет пиксели назначения пикселями источника. Когда цель – полупрозрачное наложение, чтобы назначение просвечивало сквозь источник, параметр alpha управляет тем, как эти двое смешиваются. alpha=0 показывает только назначение (без источника); alpha=255 – значение по умолчанию и показывает только источник (полная замена); промежуточные значения смешивают эти двое пропорционально:
img.draw_image(overlay, x=0, y=0, alpha=128)
Отдельный аргумент alpha_palette – это единственный механизм попиксельной альфы в модуле. Он принимает изображение GRAYSCALE, значения которого используются как альфа в соответствующей позиции источника – например, тепловая карта, альфа которой меняется вместе с её интенсивностью. Альфа должна предоставляться в виде этого отдельного аргумента в оттенках серого; исходное изображение, которое несёт собственный альфа-канал (скажем, PNG с прозрачностью), не передаёт его автоматически.
5.7.5. ROI источника и палитра¶
Ещё два параметра завершают механизм композиции:
roi=(x, y, w, h)ограничивает источник его собственным подпрямоугольником, так что только этот прямоугольник компонуется на назначение. Полезно для обрезки в рамках того же вызова, без подготовки промежуточного обрезанного изображения.color_paletteзаменяет значение каждого пикселя источника через таблицу подстановки перед рисованием – тот же механизм, что используютto_rainbow()иto_ironbow(), представленный здесь, чтобы наложение можно было палитризировать по пути на назначение без отдельного прохода преобразования.
Оба сочетаются со всем остальным в вызове: с масштабированием, альфой, аргументом mask со стороны назначения и параметром roi со стороны назначения, который ограничивает запись прямоугольником назначения.