5.12. Бинарная пороговая обработка

Множество конвейеров обработки изображений сводится к вопросу о каждом пикселе: находится ли эта яркость внутри диапазона, который означает «передний план»? Достаточно ли этот цвет близок к красному, чтобы быть маркером, который отслеживает приложение? Является ли этот пиксель частью набора кандидатов, на который должен смотреть следующий этап конвейера? Пороговая обработка – это операция, которая превращает эти вопросы в бинарный ответ в каждой позиции – включено, если пиксель соответствует, выключено, если нет, – и сводит всё изображение к маске, с которой может работать остальная часть конвейера.

5.12.1. Метод binary

Метод binary() выполняет эту классификацию по каждому пикселю одним вызовом. Он принимает список диапазонов порогов – условий, которым может соответствовать пиксель, чтобы считаться «включённым», – и переписывает изображение так, что каждый пиксель, соответствующий хотя бы одному из диапазонов, устанавливается в максимальное значение формата, а каждый, который не соответствует, устанавливается в нуль. Результат – это бинарная маска, которую остальная часть конвейера может использовать напрямую.

В простейшей форме список порогов содержит один диапазон, и вызов возвращает маску пикселей в этом диапазоне:

img.binary([(120, 255)])

Именно форма списка делает binary мощным. Конвейер, который хочет отслеживать два цветных маркера или диапазон яркости плюс изолированный пик насыщенности, передаёт оба диапазона в одном списке и получает единую выходную маску, охватывающую все совпадения.

A horizontal grayscale gradient at the top labelled "input -- pixel values from 0 to 255". Below it, an inclusive threshold range from lo to hi is marked with brackets along the gradient, enclosing the range of brightness values that count as matches. A binary output bar at the bottom shows white inside the lo-to-hi range and black outside it.

Пороговая обработка превращает изображение с непрерывными значениями в бинарную маску: каждый пиксель внутри диапазона порога становится максимумом формата, каждый пиксель снаружи становится нулём.

5.12.2. Кортеж для оттенков серого

Для изображения в оттенках серого каждая запись в списке порогов – это кортеж из двух элементов (lo, hi), описывающий включающий диапазон яркости. Пиксели со значениями между lo и hi (включительно) совпадают; всё за пределами этого диапазона – нет. Естественные шаблоны просты:

  • (0, 60) совпадает с тёмными пикселями – от чёрного до тёмно-серого.

  • (180, 255) совпадает с яркими пикселями – от светло-серого до белого.

  • (100, 160) совпадает с пикселями среднего серого – полоса в середине диапазона яркости.

Порядок двух значений внутри кортежа не имеет значения; метод меняет их местами внутренне, если lo больше hi, поэтому (60, 0) работает так же, как (0, 60).

5.12.3. Кортеж LAB для цвета

Для изображения RGB565 каждая запись – это кортеж из шести элементов (l_lo, l_hi, a_lo, a_hi, b_lo, b_hi), описывающий включающий диапазон в цветовом пространстве LAB, а не напрямую в красном, зелёном и синем. Пороги – это L (светлота), A (хроматическая ось от зелёного к красному) и B (хроматическая ось от синего к жёлтому), каждый из которых сравнивается со значением пикселя в этом канале.

Причина использования LAB вместо прямой пороговой обработки RGB – это свойство, ради которого было разработано цветовое пространство LAB: LAB отделяет светлоту от цветности. Два пикселя, которые показывают один и тот же цвет, но при разной яркости, оказываются с разными значениями L, но примерно с одинаковыми значениями A и B. Это разделение позволяет диапазонам порогов описывать цвет по его положению на осях A и B и оставлять диапазон L широко открытым, чтобы принимать этот цвет при любой яркости от тени до света. Порог на основе RGB этого сделать не может – любое изменение освещения сдвигает все три значения R, G, B одновременно, и трекер, построенный на порогах RGB, ломается в первый же раз, когда облако проходит мимо солнца.

Практический шаблон: выбрать диапазоны A и B, описывающие цвет, который отслеживает приложение, и оставить диапазон L широким – часто (0, 100), чтобы принимать любую яркость, – если только приложению специально не нужно применять порог к яркости наряду с цветом.

Для кортежей с менее чем шестью значениями отсутствующие компоненты по умолчанию принимают максимальный диапазон (без ограничения по этой оси). Поэтому кортеж из двух элементов (l_lo, l_hi) в списке порогов RGB565 применяет порог только к светлоте и совпадает с любым цветом.

Примечание

По-настоящему широко открытый диапазон L имеет подвох на нижнем конце. По мере падения светлоты к нулю каждый цвет сходится к чёрному, при этом значения A и B стремятся к нулю и становятся подвержены доминированию шума – поэтому тёмные пиксели могут попасть в диапазоны A и B и отслеживаться как целевой цвет. Если чёрные области сцены загораются как совпадения, поднимайте l_lo, пока они не выпадут.

5.12.4. Флаги

Три именованных аргумента управляют выводом:

  • invert=True инвертирует результат. Каждый пиксель, который совпал бы, становится нулём, а каждый пиксель, который был бы нулём, становится максимальным значением. Полезно, когда естественный способ описать передний план – через то, чем он не является.

  • zero=True меняет режим работы: совпадающие пиксели обнуляются, а несовпадающие пиксели сохраняют свои исходные значения. Используйте это, когда цель – стереть совпадающие пиксели из изображения, а не свести изображение к их бинарной маске.

  • to_bitmap=True возвращает результат как изображение BINARY вместо перезаписи существующего формата источника. Результат с одним битом на пиксель – это то, что последующие аргументы маски принимают напрямую, и преобразование часто экономит память, избавляя от необходимости носить с собой маску полного формата.

Маска и ROI следуют той же конвенции, что и остальной интерфейс: прямоугольник roi ограничивает операцию подобластью, а изображение mask ограничивает её произвольным набором позиций.

5.12.5. По умолчанию на месте

Как и арифметические операции, binary по умолчанию выполняется на месте: пиксели исходного изображения перезаписываются бинарным выводом, и исходные значения теряются после вызова. Форма to_bitmap=True – это альтернатива, когда источник нужно сохранить, а вывод должен быть свежевыделенным изображением BINARY. Форма copy=True также принимается для результата в том же формате в новом буфере.