メインコンテンツまでスキップ

USBカメラを使う

nodes::UsbCameraInput は、MJPEGを送るUSB(UVC)Webカメラを読み取り、カメラのJPEGフレームを出力します。カメラの固定IDを渡します。UsbCameraInputOptions は(MIPIカメラの)CameraInputOptions のフィールド名と既定値を使いますが、camera_name は必須で、format はありません。

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

多くのWebカメラは4:2:2のJPEGを送り、これはNV16にデコードされます。usb_camera_info() はカメラのJPEGがデコードされるレイアウトを返します。これを SimaDecode の out_format に使い、NV16 が返された場合はモデルの preprocess.color_convert.input_format を PreprocessColorFormat::NV16 に設定すると、フレームは変換段なしでモデルに届きます。

Neatがサポートする範囲​

  • Platform 3.0で、Modalix DevKitのUSBポートに接続したUVCカメラ。
  • 4:2:0または4:2:2のクロマサンプリングによるMJPEGキャプチャー。
  • カメラがMJPEG用に提示する正確な幅、高さ、フレームレート。Neatはスケーリングや近いモードの選択を行いません。

H.264専用カメラ、非圧縮のYUYV/NV12キャプチャー、深度やIRのストリーム、露出などのカメラ制御は、この経路の対象外です。

カメラIDを調べる​

各USBカメラには、USBポートとベンダーID、製品IDから作られる固定IDがあり、形式はlibcameraと同じです。

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

IDは再起動や接続順序の変化では変わりません。カメラを別のUSBポートに移すと変わるため、異なるポートに接続した同じカメラ2台は別々のIDになります。接続されているカメラを一覧表示します。

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

カメラが提供するMJPEGモードを確認するには、DevKit上でフォーマットの一覧を表示します。デバイス番号はこの確認にだけ使い、NeatはIDからデバイスを見つけます。

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を転送する​

カメラの映像をビューアーに送りつつ、同じ映像でモデルも実行するには、このノードを、JPEGを再エンコードせずにRTP/JPEGとして送る VideoSender パススルーと、out_format にカメラの decoded_format を指定した SimaDecode に接続します。

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カメラの後にある小さなleakyキューが、グラフの処理が遅れたときに古いフレームを破棄します。カメラのキャプチャープールは queue_depth + 6 個のバッファーを持ち、上限は64個のため、queue_depth は最大58です。

Webカメラは、JPEGの終了マーカーの後にバイトを付け足すことがよくあり、一部のフレームは不完全な状態で届いたり、USBドライバーによって破損とマークされたりします。UsbCameraInput はドライバーが破損とマークしたフレームを出力前に破棄するため、VideoSender のパススルーにもデコーダーにも届きません。デコーダーは各フレームを終了マーカーまでデコードし、不完全なフレームや破損したフレームは停止せずに破棄します。デコーダー要素は、それらを dropped-count プロパティで数えます。

トラブルシューティング​

メッセージ対処
no USB camera with ID ...; connected USB camera IDs: ...一覧にあるIDのいずれかを使ってください。カメラを別のポートに移すとIDが変わります。
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 frameNeatがデコードできないJPEG(4:4:4サンプリングなど)をカメラが送っているか、フレームがまったく届いていません。
is no longer /dev/videoNグラフの作成後に、カメラが抜かれたか、移動されたか、番号が変わりました。UsbCameraInput をもう一度呼び出してください。
is not at '/dev/videoN' as its UsbCameraInfo saysusb_camera_info の呼び出し後に、カメラが抜かれたか、移動されたか、番号が変わったか、またはその情報が別のカメラのものです。usb_camera_info をもう一度呼び出し、新しい情報を渡してください。