5.3. Формати пікселів¶
Алгоритм виявлення меж очікує, що кожен піксель зберігає значення яскравості. Алгоритм відстеження кольорового об’єкта очікує, що кожен піксель несе колір. Алгоритм морфологічного замикання очікує, що кожен піксель є або увімкненим, або вимкненим. Формат пікселів, який несе Image – один із форматів, перерахованих у каталозі Vision Sensors – дає змогу перевіряти ці очікування завчасно: формат заздалегідь вказує, в якому вигляді знаходяться пікселі і які алгоритми можуть працювати з ними без кроку перетворення.
Ця сторінка присвячена тому, як ці обмеження проявляються на практиці. Вибір правильного формату залежить від того, що робитиме конвеєр, а методи перетворення між форматами – це спосіб, яким конвеєр, якому потрібен більш ніж один формат, поєднує етапи разом.
П’ять нестиснутих форматів пікселів і те, як пакуються їхні байти. JPEG і PNG тут не показані, оскільки вони є стисненими потоками змінної довжини, а не фіксованими пікселями.¶
5.3.1. Основний формат у відтінках сірого¶
Більшість класичного технічного зору зводиться до роботи зі значеннями яскравості. Виявлення меж, зіставлення шаблонів, декодування AprilTag, оцінка оптичного потоку, морфологічні оператори, аналіз плям – всі вони на рівні роботи алгоритмів аналізують яскравість кожного пікселя та порівнюють її з яскравістю сусідніх пікселів. Колір сцени часто корисний для застосунку, який їх викликає, але самим алгоритмам він не потрібний.
Формат у відтінках сірого надає алгоритмам саме це, без накладних витрат. Один байт на піксель зберігає значення яскравості від 0 (чорний) до 255 (білий). Формат займає вдвічі менше місця, ніж RGB565 і YUV422, і втричі менше, ніж RGB888, тому кожна операція обробляє менше даних – це і швидше, і менше навантажує кадровий буфер. На менших камерах, де кадровий буфер конкурує з рештою скрипту за RAM, ця різниця у розмірі може вирішити, чи взагалі вміститься конвеєр. Якщо колір не є тією ознакою, яку потребує алгоритм, відтінки сірого – правильний вибір.
5.3.2. Колір через RGB565¶
Коли колір є визначальною ознакою – відстеження кольорового маркера, розрізнення червоних яблук від зелених, виявлення елемента інтерфейсу за відтінком – два байти на піксель забезпечують достатньо кольору для класифікації, яку виконують алгоритми. RGB565 – це стандартний кольоровий формат на камері, якого очікують методи, що враховують колір.
Відтворення анотованого кадру – малювання рамок виявлення, запис діагностичного тексту, виведення кадру на екран або передача його віддаленому переглядачу – також природно використовує RGB565. Попередній перегляд в IDE, вбудовані контролери дисплеїв і більшість мережевих одержувачів або споживають формат безпосередньо, або дешево перетворюють із нього.
5.3.3. Bayer як формат зберігання¶
Зображення Bayer – це необроблений вихід датчика до того, як ISP виконав дебаєризацію у готове кольорове представлення. Кожен піксель – це один байт, що зберігає один кольоровий канал – той, який пропустив кольоровий фільтр у цій позиції мозаїки. Це робить зображення Bayer таким самим розміром, як зображення у відтінках сірого, і втричі меншим, ніж RGB888, що відповідає практичному застосуванню Bayer: зберіганню багатьох кадрів одночасно, коли RAM є обмежувальним фактором.
Недолік у тому, що алгоритми у модулі image не працюють безпосередньо з зображеннями Bayer. Без дебаєризації жоден піксель не несе достатньо інформації для самостійного кольорового судження, а шаблони, які шукають алгоритми – межі, кути, плями – будуть спотворені мозаїкою. Єдині способи читання або зміни зображення Bayer – це get_pixel() і set_pixel(); все інше очікує готового представлення.
Типовий сценарій – зберігати кадри у форматі Bayer, поки вони перебувають у черзі, і перетворювати кожен у відтінки сірого або RGB565 у момент початку його обробки. Перетворення витрачає цикли CPU, але заощаджує RAM, яка інакше була б зайнята зберіганням готових кадрів протягом усього часу роботи застосунку.
Примітка
Єдині операції модуля image безпосередньо над пікселями Bayer – це get_pixel(), set_pixel() і шлях кодування JPEG для попереднього перегляду в IDE або віддаленому переглядачі. Малювання, аналіз і фільтрація потребують попереднього перетворення у відтінки сірого, RGB565 або бінарний формат.
5.3.4. YUV422 для конвеєрів, яким потрібно і те, і інше¶
YUV422 розділяє інформацію кожного пікселя на канал яскравості (Y) і два канали кольоровості (U та V), і субдискретизує кольоровість так, що суміжні пари пікселів спільно використовують одне значення U і одне V. У середньому виходить два байти на піксель – так само, як у RGB565 – але вони розташовані так, що канал Y вже є безперервним 8-бітним зображенням у відтінках сірого, що знаходиться за відомими зміщеннями у буфері.
Таке розташування – саме те, що потрібно конвеєру, в якому одні етапи працюють у відтінках сірого, а інші потребують кольору. Читання значень Y безпосередньо для етапів у відтінках сірого дозволяє уникнути явного перетворення; канали U і V доступні, коли пізніший етап дійсно потребує кольору. Поза цим конкретним сценарієм RGB565 зазвичай є простішим вибором для кольору, а відтінки сірого – для роботи лише з яскравістю; цінність YUV422 полягає у хорошій підтримці обох одночасно.
Примітка
Модуль image працює з YUV422 більш обмеженим чином, ніж із відтінками сірого, RGB565 або бінарним форматом – безпосереднє читання каналу Y для роботи у відтінках сірого та шлях кодування JPEG для попереднього перегляду в IDE або віддаленому переглядачі. Методи, що враховують колір, очікують RGB565; кадри YUV422 потребують явного перетворення перед аналізом кольору або малюванням.
5.3.5. Бінарний формат, маски та порогова обробка¶
Бінарне зображення – це один біт на піксель: кожен піксель є або 0, або 1. Цей формат рідко з’являється як знімок із датчика; натомість він є природним результатом порогової обробки (де перевірка кольору або яскравості класифікує кожен піксель як «так, відповідає» або «ні, не відповідає») і природним вхідним сигналом для морфологічних операцій та аргументу mask, який приймають багато методів.
Практична перевага формату – його розмір. Бінарне зображення займає одну восьму від розміру зображення у відтінках сірого, тому зберігання великої маски – попіксельний вибір позицій, яких має торкатися наступна операція – є дешевим. Те, що багато операцій приймають бінарне зображення як аргумент mask=, – це інший бік тієї самої монети: формат невеликий, і поєднання бінарного виходу одного етапу з вхідною маскою іншого – поширений шаблон конвеєра.
5.3.6. JPEG і PNG на межі обробки¶
Об’єкти Image у форматах JPEG і PNG відрізняються від інших у каталозі. Вони не є піксельними сітками; вони є стисненими байтовими потоками, які кодують дані пікселів у формі, яку піксельні операції не можуть читати. Виклик get_pixel() на JPEG не повертає піксель у позиції; піксель не знаходиться в розпакованому вигляді у жодному місці буфера для отримання методом.
JPEG і PNG з’являються на межі обробки зображень, де піксельні дані виходять із камери або надходять до неї у стисненому вигляді. Збереження кадру на диск у форматі JPEG зменшує розмір файлу; передача кадру по мережі у форматі JPEG здешевлює передачу; завантаження еталонного кадру з файлу JPEG дозволяє зберігати його на диску у значно меншій формі, ніж необроблені пікселі. Для будь-якого з цих випадків стиснене представлення є правильним вибором. Однак для реальної обробки JPEG застосунок спочатку перетворює його у придатний формат – і саме при цьому перетворенні стиснені байти розгортаються у пікселі і відбувається збільшення буфера (30 КБ JPEG може перетворитися на 600 КБ RGB565).
5.3.7. Перетворення між форматами¶
Шлях перетворення – це те, що поєднує різні формати в єдиний конвеєр. П’ять методів класу Image приймають існуюче зображення і повертають нове у іншому форматі:
to_grayscale()повертає зображення з одним байтом на піксель – формат, якого очікують класичні алгоритми.to_rgb565()повертає двобайтовий кольоровий формат, який розуміють як методи, що враховують колір, так і попередній перегляд в IDE.to_bitmap()повертає однобітове бінарне зображення – формат, який приймають морфологія та аргументиmask.to_jpeg()повертає JPEG-стиснене зображення, придатне для збереження або передачі.to_png()повертає PNG-стиснене зображення, коли перевага надається кодуванню без втрат над меншими файлами JPEG.
За замовчуванням кожне перетворення виконується на місці: буфер вихідного зображення перезаписується перетвореним результатом, і вихідні пікселі зникають після повернення виклику. Це найдешевший варіант як для CPU, так і для пам’яті, і він є правильним вибором, коли вихідний кадр більше не буде потрібен.
Коли вихідне зображення все ще потрібне – коли пізніший етап конвеєра має бачити оригінальний кадр – два аргументи з ключовим словом перевизначають поведінку за замовчуванням. copy=True виділяє окремий буфер для перетвореного зображення у купі Python і залишає джерело незмінним. copy_to_fb=True робить те саме виділення, але розміщує його у кадровому буфері замість купи – це те, до чого вдається застосунок, коли перетворене зображення має потрапити до попереднього перегляду в IDE, оскільки IDE читає з кадрового буфера.
Два додаткові методи повертають зображення RGB565, розфарбовані через палітру, а не прямим перетворенням. to_rainbow() відображає кожне однокальне вхідне значення на колір уздовж плавного градієнта, що проходить через видимий спектр. to_ironbow() відображає кожне вхідне значення на нелінійну палітру теплового зображення, що переходить від чорного через темно-червоний і помаранчевий до білого. Обидва є інструментами візуалізації, а не вимірювання; їхня мета – зробити однокальне зображення, сирі значення якого були б інакше невидимими для ока, доступним для сприйняття з першого погляду.
5.3.8. Розмір буфера¶
Одна остання деталь про формати, яку варто зазначити явно. size() завжди повідомляє розмір байтового буфера, а не кількість пікселів. Для нестиснених форматів це безпосередньо випливає з розмірів та кількості байтів на піксель: width * height * bytes_per_pixel. Для JPEG і PNG це розмір стисненого потоку, який змінюється від кадру до кадру залежно від вмісту сцени. Код, який виділяє буфери з байтових бюджетів, використовує size() для першого випадку; код, що передає стиснені кадри з камери, зчитує його після кожного стиснення, щоб дізнатися, скільки байтів фактично містить потік.