5.30. Сопоставление с шаблоном

Детекторы, рассмотренные до сих пор, отвечают на вопросы о содержимом одного кадра: где находятся блобы, куда идут линии, что говорит напечатанный код. Другой класс вопросов сравнивает одно изображение с другим. Выглядит ли эта область захваченного кадра как эталонный фрагмент, который я сохранил во время калибровки? На этот вопрос отвечают методы сопоставления.

Тональный и статистический анализ представил get_similarity() для смежного вопроса – насколько в целом похожи эти два изображения одинакового размера? – с SSIM в качестве лежащей в основе метрики. Оставшийся вопрос сопоставления – это вопрос локализации: не «насколько похожи эти два изображения», а «где внутри этого большего изображения появляется этот меньший фрагмент?» Правильным инструментом для вопроса локализации является сопоставление с шаблоном.

5.30.1. Базовый вызов

find_template() ищет первое место, где небольшое шаблонное изображение появляется внутри захваченного кадра. Реализация использует нормализованную взаимную корреляцию (NCC): шаблон скользит по кадру, оценка совпадения для каждой позиции вычисляется по корреляции между пикселями шаблона и лежащими под ними пикселями кадра (нормализованной относительно локальных средних значений и дисперсий, чтобы изменения усиления не обманывали совпадение), и первая позиция, чья оценка превышает threshold, возвращается в виде ограничивающей рамки:

template = image.Image("/sdcard/template.bmp", copy_to_fb=False)
template.to_grayscale()

match = img.find_template(template, threshold=0.7,
                           search=image.SEARCH_DS)

if match is not None:
    img.draw_rectangle(match, color=(255, 0, 0))

Метод работает только с изображениями в оттенках серого. Захватывайте в оттенках серого (естественный выбор для любой камеры без цветного датчика) или преобразуйте на месте через to_grayscale() перед вызовом. То же относится к шаблону, загруженному с диска: цветной шаблон преобразуется тем же методом, и результат – это то, что ожидает механизм сопоставления.

threshold – это число с плавающей точкой от 0.0 до 1.0. Значение 1.0 требует идеального попиксельного совпадения (которое никогда не случается с реальными захваченными изображениями), 0.0 принимает что угодно, а значения между 0.6 и 0.8 покрывают распространенный случай, когда шаблон был захвачен при схожем освещении, а сцена не изменилась кардинально. Повышайте порог, чтобы подавить ложные срабатывания; понижайте его, чтобы принимать более зашумленные совпадения ценой большего числа ложных попаданий.

5.30.2. Стратегия поиска

search выбирает между двумя стратегиями. image.SEARCH_EX – это исчерпывающий поиск: шаблон скользит по каждой позиции с шагом step пикселей в кадре и возвращает первое попадание выше порога. image.SEARCH_DS – это алмазный поиск: механизм сопоставления сначала делает грубую выборку, затем уточняет вокруг лучшей оценки, что значительно быстрее, но может пропустить истинное совпадение, если грубый проход случайно попал рядом с локальным максимумом, который превосходит глобальный. Для конвейера реального времени, где шаблон четко определен и вряд ли будет спутан, SEARCH_DS – правильное значение по умолчанию; для однократной калибровки, где цена промаха выше цены более медленного сканирования, SEARCH_EX безопаснее.

step управляет пропуском пикселей во время исчерпывающего прохода (алмазный поиск управляет своим шагом сам). Большие значения step ускоряют сканирование ценой субпиксельной точности. roi ограничивает поиск областью кадра, как сужая то, что рассматривает механизм сопоставления, так и сокращая объем работы.

Возвращаемое значение – это кортеж ограничивающей рамки (x, y, w, h), определяющий лучшее совпадение, или None, если ни одна позиция не превысила порог. Ограничивающая рамка напрямую передается в draw_rectangle() или crop() для следующего этапа обработки.

5.30.3. Ловушка масштаба и поворота

Классическая ловушка сопоставления с шаблоном – это чувствительность к масштабу и повороту. Механизм сопоставления сравнивает шаблон с кадром попиксельно; шаблон, захваченный на одном расстоянии, не совпадает с тем же объектом, захваченным на другом расстоянии, а шаблон, захваченный прямо в лоб, не совпадает с тем же объектом, рассматриваемым под углом. Порог незаметно опускается ниже уровня совпадения, даже когда объект явно виден человеческому глазу, и метод возвращает None.

Существует несколько обходных путей для простых случаев. Приложение может захватить несколько шаблонов в разных масштабах и запускать find_template() для каждого по очереди, принимая первый, который превышает порог; стоимость растет с числом шаблонов. Приложение может предварительно обработать кадр с помощью rotation_corr() или полярного преобразования (Геометрические преобразования), чтобы устранить мешающий поворот до запуска сопоставления; сопоставляемый шаблон по-прежнему должен соответствовать скорректированной геометрии.

Полезный прием для конвейеров контроля качества сочетает механизм сопоставления с шаблоном с оценщиком сходства, представленным в разделе тонального и статистического анализа: find_template() находит деталь в захваченном кадре, а возвращенная ограничивающая рамка вырезается и передается в get_similarity() для сравнения с эталонным фрагментом. Шаг сопоставления с шаблоном решает, где находится деталь; шаг оценки сходства решает, приемлема ли деталь. Оба шага выполняются для каждого кадра, порог по mean является воротами годен/брак, а сопоставленная ограничивающая рамка, нарисованная обратно в кадре, – это предпросмотр в IDE, за которым наблюдает оператор.