5.27. Пошук кіл і прямокутників¶
Лінії та відрізки охоплюють прямі краї у захопленому кадрі, але багато реальних об’єктів, які шукає камера, не є прямолінійними. Монета, що лежить на столі, — це коло. Надрукована етикетка, стікер, верхня частина коробки, побачена під кутом — це чотирикутник. Модуль зображень надає спеціальний детектор для кожного: пошук кіл у стилі Хафа та пошук чотирикутників, заснований на AprilTag.
Обидва методи слідують тому самому шаблону, що й детектори ліній: threshold контролює кількість голосів, необхідних для виявлення, roi звужує область пошуку, а повернуті об’єкти містять як позицію, так і значення впевненості. Однак простори параметрів і правильні значення за замовчуванням відрізняються настільки, що заслуговують окремого розгляду.
5.27.1. Кола Хафа¶
find_circles() виконує кільцевий варіант перетворення Хафа. Кожен піксель межі, виявлений під час попереднього проходу Собеля, голосує за кожне коло, що може через нього проходити; кола, які набирають достатню кількість голосів, повертаються як результат.
circles = img.find_circles(threshold=3500,
x_margin=10, y_margin=10, r_margin=10,
r_min=10, r_max=80, r_step=2)
for c in circles:
img.draw_circle((c.x, c.y, c.r), color=(255, 0, 0))
threshold — це мінімальна сума магнітуд меж Собеля вздовж кандидата-кола. Більші кола проходять через більше пікселів і тому потребують вищих порогів; значення, що знаходить монету радіусом 20 пікселів, також спрацює на шум навколо межі в 100 пікселів, тоді як значення, налаштоване на велику монету, пропустить маленьку. Коли діапазон очікуваних радіусів відомий, правильне значення порогу масштабується з довжиною кола — приблизно threshold = 50 * 2 * pi * r дає розумну відправну точку, а точне значення визначається в ході короткого налаштування.
r_min, r_max і r_step задають пошук за радіусом. Без обмежень детектор шукатиме кожен радіус від кількох пікселів до половини ширини зображення, що є і повільним, і джерелом хибних спрацювань. Встановлення r_min і r_max для охоплення очікуваного розміру цілі з достатнім запасом (наприклад, r_min=15, r_max=25 для монети, радіус якої становить близько 20 пікселів) значно скорочує обсяг роботи та покращує співвідношення сигнал-шум голосів. r_step контролює гранулярність пошуку; більші кроки прискорюють роботу, але можуть пропустити коло, справжній радіус якого потрапляє між двома перевіреними значеннями. Значення за замовчуванням r_step=2 є розумним компромісом.
x_margin, y_margin і r_margin контролюють об’єднання близьких виявлень — так само, як theta_margin і rho_margin роблять це для виявлення ліній. Одне фізичне коло на зображенні голосує за кластер кіл-кандидатів, центри та радіуси яких збігаються з точністю до кількох пікселів; поля стягують кожен кластер до його піку перед побудовою списку результатів. Більші поля повертають менше, але впевненіших виявлень; менші поля повертають більше виявлень з можливими майже-дублікатами.
x_stride і y_stride задають крок сканування при голосуванні — так само, як в інших детекторах. Значення за замовчуванням 2 і 1 підходять для більшості зображень; збільшення обох до 4 — стандартний компроміс між швидкістю та якістю для зображень з відомо великими колами.
Кожен повернутий Circle містить x, y, r (центр і радіус) та magnitude (загальна кількість голосів, корисна як оцінка впевненості для сортування або фільтрації). Відображення виявлення у кадрі — це один виклик: draw_circle() приймає кортеж (x, y, r) з 3 елементів, доступний безпосередньо як (c.x, c.y, c.r) з результату.
5.27.2. Прямокутники¶
find_rects() запозичує детектор чотирикутників з конвеєра AprilTag — та сама процедура, що знаходить чорний квадрат навколо тегу, тут використовується самостійно як універсальний детектор прямокутників.
rects = img.find_rects(threshold=12000)
for r in rects:
img.draw_rectangle(r.rect, color=(0, 255, 0))
for corner in r.corners:
img.draw_circle((corner[0], corner[1], 4),
color=(0, 255, 0))
threshold — це мінімальна сума магнітуд меж навколо периметра прямокутника. Друкований чорно-білий прямокутник у добре освітленому кадрі легко перевищує 10000; слабко видимий прямокутник на текстурованому фоні може вимагати зниження до 2000 — це компроміс між хибними спрацюваннями та чутливістю. Як і у детектора кіл, правильне значення визначається в ході швидкого налаштування з потрібними цілями в кадрі.
Детектор є проективним — він знаходить чотирикутники, сторони яких прямі, але не обов’язково паралельні або вирівняні за осями. Наклейка, знята під кутом, виглядає на зображенні як трапеція, і детектор прямокутників правильно її знаходить; вирівняний за осями прямокутник — це просто вироджений випадок, де чотири кути утворюють прямокутну коробку. roi обмежує пошук; решта іменованих аргументів успадковують значення за замовчуванням з конвеєра AprilTag і рідко потребують налаштування.
Кожен повернутий Rect містить обмежувальний прямокутник, вирівняний за осями: x, y, w, h, а також кортеж rect з 4 елементів, який приймає draw_rectangle(), і чотири виявлені кути як corners. Обмежувальний прямокутник використовується застосунком для приблизного визначення позиції та розміру; кути описують сам проективний чотирикутник. Коли камера знімає плоску ціль під кутом і застосунку потрібно усунути трапецієподібне спотворення — зчитати текст із наклейки, взяти зразок кольору з плоскої ділянки — кути подаються безпосередньо до rotation_corr() з ключовим словом corners= (див. виправлення лінзи та перспективи), і результатом є виправлений прямокутник, готовий до подальшого аналізу.
Попередження
Оскільки детектор налаштований під потреби конвеєра AprilTag — чотирикутники з чіткими, контрастними межами, як-от контур чорного тегу на білому папері — він не є засобом пошуку будь-яких прямокутників. Прямокутники з низьким контрастом, текстурованими межами або на насиченому тлі можуть залишитися невиявленими. Ефективність роботи залежить від ситуації: перевіряйте результати на реальних цілях завчасно, перш ніж будувати навколо цього конвеєр.
5.27.3. Коли детектор спрацьовує помилково¶
Кола особливо виграють від попередньої фільтрації вхідного зображення. Зашумлений кадр містить багато випадкових пікселів меж, які голосують, і простір Хафа має широкі розмиті піки, які важко розділити при об’єднанні. Прохід gaussian() або mean() перед find_circles() згладжує шум і зберігає справжні межі; детектор повертає чіткіші піки за менший час.
Для прямокутників поширений збій є протилежним: низький контраст між прямокутником і його фоном означає, що сума магнітуд меж ніколи не досягає threshold. Прохід histeq() для перерозподілу яскравості по всьому діапазону від 0 до 255 відновлює контраст, необхідний детектору. (Контраст має існувати десь у зображенні; вирівнювання гістограми може лише посилити те, що вже є.)