5.6. Рисование фигур и текста¶
Алгоритм, который что-то определяет по изображению, часто нуждается в том, чтобы это решение было видимым. Детектор блобов находит область, которая важна приложению; приложение хочет, чтобы эта область была нарисована на кадре, чтобы оператор – или разработчик, запускающий скрипт – мог увидеть, что было найдено. Преобразование координат отображает входную позицию в выходную; отладка обычно означает отметку обеих позиций на одном изображении. Предпросмотр в IDE считывает всё, что находится в буфере кадра в момент опроса, поэтому простейший способ сделать вывод алгоритма видимым – записать аннотации прямо в буфер кадра. Семейство методов рисования класса Image – это набор инструментов именно для такой работы.
5.6.1. Примитивы¶
Каждый метод рисования помещает на изображение один определённый вид метки. Каталог невелик и держится близко к геометрическим примитивам, которые аннотация действительно требует:
draw_line()– прямой отрезок линии между двумя конечными точками.draw_rectangle()– выровненный по осям прямоугольник, полый или закрашенный.draw_circle()– окружность вокруг центра, полая или закрашенная.draw_ellipse()– эллипс с произвольным поворотом.draw_cross()– знак плюс в точке, обычная метка для центроида или цели клика.draw_arrow()– стрелка от начальной точки к конечной.draw_edges()– четыре стороны произвольного четырёхугольника по четырём угловым точкам; естественный способ обвести обнаруженный тег или область с перспективным искажением.draw_string()– текст из встроенного растрового шрифта.
Каждый из них изменяет исходное изображение на месте и возвращает то же изображение для построения цепочки, следуя соглашению о методах-операторах, установленному ранее.
Восемь примитивов рисования, по одному на панель. Каждый метод создаёт один вид метки.¶
5.6.2. Цвет¶
Каждый метод рисования принимает аргумент color, который решает, какое значение записать в каждый закрашиваемый пиксель. Форма этого аргумента зависит от формата изображения. Для изображения RGB565 естественной формой является кортеж (r, g, b), где каждый канал находится в диапазоне 0 – 255; модуль упаковывает это в 16-битное слово RGB565 перед записью. Для изображения в оттенках серого естественной формой является одно целое число яркости от 0 (чёрный) до 255 (белый). Методы также принимают сырое хранимое значение формата – 16-битное упакованное слово для RGB565, 8-битное целое для оттенков серого – что является эффективной формой, когда цвет был вычислен где-то ещё и уже находится в хранимой форме.
Опущение аргумента color закрашивает белым. Это значение по умолчанию удобно для работы с оттенками серого, где белый – максимальное значение и чётко читается на большинстве фонов. Для отладочных наложений RGB565 это почти всегда неправильно: зелёный или красный обычно лучше читается на той сцене, которую камера на самом деле видит, а явный цвет передаёт намерение.
5.6.3. Толщина и заливка¶
Большинство геометрических методов принимают два флага, которые решают, как рисуется метка:
thickness=Nзадаёт ширину линии в пикселях. По умолчанию равно1, что подходит для большинства наложений; большее значение полезно, когда аннотация должна оставаться видимой на насыщенной сцене или после того, как последующий этап конвейера ещё больше изменит изображение.fill=Trueпереключает метку с контура на сплошную, закрашивая каждый внутренний пиксель выбранным цветом. По умолчанию равноFalse.
Эти флаги не применяются к примитивам, у которых нет внутренней области для заливки – к линии, кресту, стрелке, четырёхугольнику – где имеет значение только thickness.
5.6.4. Рисование текста¶
draw_string() выводит символы из встроенного растрового шрифта размером 8 на 10 пикселей. x и y – это верхний левый угол ячейки первого символа, text – строка для рисования, а color следует тому же соглашению, что и геометрические методы. Шрифт несёт полный диапазон печатаемого ASCII и не имеет кернинга – каждый символ занимает одну и ту же ячейку шириной 8 пикселей – что делает вывод легко позиционируемым.
img.draw_string(10, 10, "blobs: 3", color=(0, 255, 0))
Строка может включать символы новой строки (\n); каждый символ новой строки перемещает следующий символ к началу новой строки на десять пикселей ниже предыдущей. Аргумент scale рисует каждый символ большего размера с коэффициентом с плавающей точкой, а x_spacing и y_spacing добавляют отступ вокруг каждого символа. Небольшой набор флагов поворота / зеркалирования / отражения применяется либо ко всей строке, либо к каждому символу по отдельности – достаточно контроля, чтобы расположить текст вдоль угла или у негоризонтальной границы, когда того требует разметка.
5.6.5. Очистка холста¶
Один метод в этом семействе не рисует никакой конкретной метки. Он просто сбрасывает каждый пиксель изображения в ноль:
clear()– обнуляет каждый пиксель, опционально с ограничением до ROI или с областью действия через маску.
clear() – правильный ответ, когда приложение составляет аннотацию с нуля каждый кадр – начать с чёрного холста, нарисовать новые аннотации, передать результат на дисплей – вместо наложения поверх захваченного кадра. Это также самый дешёвый способ подготовить временное изображение для использования в качестве буфера маски.
Только что выделенное изображение уже обнулено конструктором, поэтому clear() имеет значение именно для буферов, повторно используемых между кадрами.