Нормалі поверхні
Оцінювання нормалей поверхні передбачає напрямок, у який повернута кожна видима поверхня. LibreYOLO надає його як задачу normal, що повертає щільне поле одиничних векторів на полотні початкового зображення.
Визначення
Задача normal передбачає за одним RGB-зображенням трикомпонентний одиничний вектор
для кожного пікселя, тобто напрямок, у який повернута поверхня в цьому пікселі.
На відміну від глибини, результат не має вільного масштабу, тому два передбачення
можна безпосередньо порівнювати без вирівнювання.
Передбачення заповнює result.normal_map, корисне навантаження NormalMap із масивом
float32 форми (H, W, 3) на полотні початкового зображення, яке також доступне як
result.normals. Вектори використовують систему координат камери OpenCV у LibreYOLO:
+x спрямовано праворуч, +y вниз, а +z углиб сцени. Вони повернуті до камери,
тому фронтально-паралельна поверхня має значення (0, 0, -1). Метод
.assert_normalized() перевіряє, що кожен піксель має скінченне значення й одиничну
довжину в межах допуску. result.boxes залишається порожнім, тому conf, iou
і max_det не впливають на результат, а Results.plot() підтримує цю задачу.
Моделі
Задачу normal підтримують два сімейства.
MoGe-2 є спеціалізованим варіантом: монокулярною моделлю геометрії з одним прямим проходом і трьома розмірами енкодера. LibreYOLO не копіює ці контрольні точки до своєї організації; під час завантаження відповідний розмір отримується з офіційних репозиторіїв у зафіксованій ревізії та перевіряється за записаною контрольною сумою SHA-256.
LibreMODUS створює нормалі як один із цільових результатів
моделі any-to-any та може приймати на вході карту глибини замість RGB-зображення.
Для неї потрібне доповнення modus і власний автентифікований обліковий запис
Hugging Face. Вона не підтримує ані val(), ані export(), тому не бере участі
в описаних нижче валідації та експорті.
Передбачення
Під час першого використання ваги MoGe-2 завантажуються й кешуються локально.
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreMoGe2s-normal.pt")result = model(SAMPLE_IMAGE, save=True) normals = result.normal_mapprint(normals.data.shape) # одиничні вектори float32 форми (H, W, 3)normals.assert_normalized() # породжує помилку, якщо якийсь піксель не має одиничної довжиниfrom libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreMoGe2s-normal.pt")result = model(SAMPLE_IMAGE) # Система координат камери OpenCV: +x праворуч, +y вниз, +z углиб сцени. Поверхня,# повернута до камери, має значення, близьке до (0, 0, -1).field = result.normals.datah, w = field.shape[:2]print(field[h // 2, w // 2])from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreMoGe2s-normal.pt")result = model(SAMPLE_IMAGE) # plot() візуалізує поле; метод визначено для результатів нормалей і країв.result.plot().save("normals.png")Значення imgsz має бути кратним розміру патча енкодера ViT, що LibreYOLO перевіряє
до початку запуску. Для списку зображень виконується по одному прямому проходу на
зображення; ця задача не має швидкого шляху зі складеним батчем. Докладніше про
джерела, потокову обробку та роботу з результатами див. у розділі
передбачення.
Формат датасету
Для валідації нормалей кожному зображенню відповідає триканальний 16-бітний файл PNG такої самої роздільної здатності й з такою самою основою назви, а також необов'язкова маска дійсності.
dataset/
data.yaml
images/
val/room.jpg
normals/
val/room.png
masks/
val/room.pngpath: dataset
train: images/train
val: images/val
normals_dir: normals
masks_dir: masks
nc: 1
names: {0: normal}Цільовий PNG має точно три канали uint16, збережені як RGB. Декодування виконується
за формулою n = png / 65535 * 2 - 1 із подальшим повторним нормалізуванням кожного
вектора, а декодовані вектори використовують ту саму систему координат камери OpenCV,
що й передбачення. Піксель маски вважається дійсним, якщо він ненульовий; якщо файлу
маски немає, дійсним є кожен скінченний ненульовий декодований вектор. Недійсні
й доповнені цільові пікселі зберігаються всередині як (0, 0, 0) і ніколи не
враховуються в метриках. Повний контракт наведено в розділі
форматів датасетів.
Навчання
Жодне сімейство нормалей не має реалізації навчання: train() породжує
NotImplementedError для обох. На сторінці MoGe-2 наведено її зафіксовані офіційні
контрольні точки для передбачення, валідації та експорту.
Валідація
Метод val() вимірює кут між кожним передбаченим вектором і відповідним еталонним
вектором для пікселів, позначених датасетом як дійсні.
from libreyolo import LibreYOLO model = LibreYOLO("LibreMoGe2s-normal.pt")metrics = model.val(data="my-dataset.yaml", imgsz=518) print(metrics["metrics/mean_angular_error"]) # градусиprint(metrics["metrics/median_angular_error"]) # градусиprint(metrics["metrics/within_11_25"]) # відсоток пікселівprint(metrics["metrics/within_22_5"], metrics["metrics/within_30"])metrics/mean_angular_error і metrics/median_angular_error містять цей кут у градусах,
і менше значення є кращим. metrics/within_11_25, metrics/within_22_5 і
metrics/within_30 є відсотками дійсних пікселів, кутова похибка яких не перевищує
11.25, 22.5 і 30 градусів, тому більше значення є кращим. Зверніть увагу на одиницю:
ці три значення є відсотками, а не частками. fitness дорівнює
metrics/within_11_25, поділеному на 100, що приводить вибір найкращої контрольної
точки до тієї самої шкали [0, 1], що й для всіх інших задач.
Експорт
Експортована модель нормалей знову завантажується через LibreYOLO() за суфіксом
файлу, тому файл .onnx поводиться як контрольна точка й повертає той самий Results.
from libreyolo import LibreYOLO model = LibreYOLO("LibreMoGe2s-normal.pt")model.export(format="onnx", imgsz=518)from libreyolo import LibreYOLO, SAMPLE_IMAGE # Фабрика визначає маршрут за суфіксом файлу, тому експортований артефакт# завантажується як будь-яка контрольна точка й повертає той самий об'єкт Results.model = LibreYOLO("LibreMoGe2s-normal.onnx")result = model(SAMPLE_IMAGE) print(result.normal_map.data.shape)Експорт нормалей використовує контракт середовища виконання з фіксованою роздільною
здатністю й батчем 1: параметр dynamic і значення batch, відмінне від 1,
відхиляються, а imgsz має бути кратним розміру патча енкодера. Підтримку окремих
форматів наведено на сторінці MoGe-2 і в
повній матриці експорту.
Експорт містить аргументи, які приймає кожен формат.