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, який відстежує оператор.