Перейти до основного вмісту

Використання USB-камери

nodes::UsbCameraInput зчитує USB-вебкамери (UVC), що надсилають MJPEG, і виводить кадри JPEG камери. Передайте стабільний ідентифікатор камери. UsbCameraInputOptions використовує назви полів і типові значення CameraInputOptions (камери MIPI), але camera_name обов’язкове, а format немає.

USB camera -> UsbCameraInput (JPEG) -+-> VideoSender passthrough (MJPEG)
`-> SimaDecode (NV12 or NV16) -> model

Більшість вебкамер надсилає JPEG 4:2:2, які декодуються в NV16. usb_camera_info() повідомляє, у яке розміщення декодуються JPEG камери: використайте його як out_format для SimaDecode, а коли воно повертає NV16, задайте preprocess.color_convert.input_format моделі значення PreprocessColorFormat::NV16, і кадри надходитимуть до моделі без етапу перетворення.

Що підтримує Neat​

  • Камери UVC, під’єднані до USB-порту Modalix DevKit, на Platform 3.0.
  • Захоплення MJPEG із субдискретизацією кольоровості 4:2:0 або 4:2:2.
  • Точні ширина, висота й частота кадрів, які камера пропонує для MJPEG. Neat не масштабує зображення й не підбирає найближчий режим.

Камери лише з H.264, захоплення нестисненого YUYV/NV12, потоки глибини чи ІЧ і керування камерою, як-от експозиція, до цього шляху не входять.

Пошук ідентифікатора камери​

Кожна USB-камера має стабільний ідентифікатор, складений з її USB-порту та ідентифікаторів виробника й продукту, у тому самому форматі, що й у libcamera:

/base/pci@7000000000-3.1:1.0-046d:08e5

Ідентифікатор не змінюється після перезавантаження чи зміни порядку під’єднання. Він змінюється, коли камеру переносять на інший USB-порт, тому дві однакові камери на різних портах мають різні ідентифікатори. Перелічіть під’єднані камери:

for (const std::string& id : simaai::neat::usb_camera_ids()) {
std::cout << id << "\n";
}

Щоб побачити, які режими MJPEG пропонує камера, перегляньте її формати на DevKit. Номер пристрою потрібен лише для цієї перевірки; Neat знаходить пристрій за ідентифікатором.

devkit$v4l2-ctl --list-devicesv4l2-ctl -d /dev/video1 --list-formats-ext

Створення графа​

#include <neat.h>

namespace neat = simaai::neat;

neat::UsbCameraInputOptions camera;
camera.camera_name = "/base/pci@7000000000-3.1:1.0-046d:08e5";
camera.width = 1920;
camera.height = 1080;
camera.framerate_num = 30;
camera.framerate_den = 1;
camera.buffer_name = "camera0";

neat::Graph graph("usb_camera");
graph.add(neat::nodes::UsbCameraInput(camera));
graph.add(neat::nodes::Output());

neat::Run run = graph.build();
std::optional<neat::Sample> frame = run.pull(/*timeout_ms=*/5000);

Вузол виводить кадри JPEG камери. Щоб запустити на них модель, декодуйте їх за допомогою SimaDecode, як показано в наступному розділі.

UsbCameraInput один раз відкриває камеру під час створення вузла, щоб перевірити режим і прочитати субдискретизацію кольоровості першого кадру. Спершу закрийте інші програми, що використовують камеру. usb_camera_info(camera) виконує ту саму перевірку без створення вузла й повертає пристрій захоплення та decoded_format: NV12 або NV16.

Якщо вам також потрібен decoded_format, викличте usb_camera_info один раз і передайте його результат у UsbCameraInput(camera, info), як показано в наступному розділі. Тоді вузол повторно використовує цю перевірку замість того, щоб знову відкривати камеру, і лише перевіряє через sysfs, що пристрій досі належить цій камері. Передавайте однакові параметри в обидва виклики.

Після від’єднання камери або перенесення на інший порт знову викличте UsbCameraInput. Збирання раніше створеного графа завершиться помилкою, тож він ніколи не відкриє іншу камеру, що отримала старий номер пристрою.

Передавання JPEG камери​

Щоб надсилати відео камери до переглядача й водночас запускати на ньому модель, під’єднайте вузол до наскрізного VideoSender, який надсилає JPEG як RTP/JPEG без повторного кодування, і до SimaDecode, у якого out_format дорівнює decoded_format камери:

const neat::UsbCameraInfo info = neat::usb_camera_info(camera); // opens the camera once

neat::SimaDecodeOptions decode;
decode.type = neat::SimaDecodeType::MJPEG;
decode.out_format = info.decoded_format; // NV12 or NV16
decode.dec_width = 1920;
decode.dec_height = 1080;
decode.dec_fps = 30;

auto sender = neat::nodes::groups::VideoSenderOptions::Passthrough(
neat::nodes::groups::RtspCodec::MJPEG);
sender.host = "127.0.0.1";

neat::GraphLinkOptions video_link;
video_link.policy = neat::GraphLinkPolicy::RealtimeLatestByStream;

neat::Graph source;
source.add(neat::nodes::UsbCameraInput(camera, info)); // reuses info, no second open
neat::Graph decoder;
decoder.add(neat::nodes::SimaDecode(decode));

neat::Graph graph("usb_camera_forward");
graph.connect(source, decoder);
graph.connect(decoder, detector); // your model Graph
graph.connect(source, neat::nodes::groups::VideoSender(sender), video_link);

Камера захоплює кадри в буфери CMA, які апаратний декодер читає на місці, тож між захопленням і декодуванням жоден кадр не копіюється. Драйвер UVC ядра, як і раніше, копіює USB-пакети в кожен буфер кадру. До відправника застосовуються обмеження RTP/JPEG з розділу Передавання відео.

Пам’ять і відкинуті кадри​

ПараметрДія
queue_depth, leaky_queueНевелика черга з відкиданням після камери відкидає застарілі кадри, коли граф не встигає. Пул захоплення камери містить queue_depth + 6 буферів, не більше 64, тож queue_depth може бути не більше 58.

Вебкамери часто додають байти після маркера кінця JPEG, а деякі кадри надходять неповними або позначеними драйвером USB як пошкоджені. UsbCameraInput відкидає кадри, які драйвер позначив як пошкоджені, ще до свого виходу, тож їх не отримують ні VideoSender passthrough, ні декодер. Декодер декодує кожен кадр до маркера кінця й відкидає неповні чи пошкоджені кадри, не зупиняючись. Елемент декодера рахує їх у властивості dropped-count.

Усунення несправностей​

ПовідомленняЩо робити
no USB camera with ID ...; connected USB camera IDs: ...Використайте один із наведених ідентифікаторів. Ідентифікатор змінюється, коли камеру переносять на інший порт.
no USB cameras are connectedПеревірте кабель і lsusb.
has no MJPEG mode 1920x1080 at 30/1 fps; its MJPEG modes are: ...Виберіть один із наведених режимів. Деякі камери пропонують високу роздільність лише з нижчою частотою кадрів.
is in use by another processЗакрийте іншу програму, яка відкрила камеру.
sent no usable MJPEG frameКамера надсилає JPEG, які Neat не може декодувати, наприклад із субдискретизацією 4:4:4, або не надсилає кадрів зовсім.
is no longer /dev/videoNПісля створення графа камеру від’єднали, перенесли або її номер змінився. Знову викличте UsbCameraInput.
is not at '/dev/videoN' as its UsbCameraInfo saysПісля виклику usb_camera_info камеру від’єднали, перенесли або її номер змінився, або ця інформація стосується іншої камери. Знову викличте usb_camera_info і передайте нову інформацію.