Pythonでのカメラインタフェース

Pythonエンジニアのスキルの標準化のため、カメラインタフェースについて書く。

### 想定する読者
- Linux のPythonユーザー

## USBカメラ
```
ls /dev/video*
```
で表示されているはずです。

```.py:
import cv2

cap = cv2.VideoCapture(0)

if not cap.isOpened():
    print("カメラを開くことができませんでした")
    exit()

while True:
    ret, frame = cap.read()

    if not ret:
        print("フレームを取得できませんでした")
        break

    cv2.imshow('Camera', frame)

    # 'q' キーが押されたらループを終了
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()
```

#### Ubutuでのアプリケーション例
- cheese 
- VLC media player

## MIPI (CSI-2)
 CSI-2 のインタフェースでカメラを接続する例
#### Raspberry Pi4
- [Raspberry Pi4×カメラモジュールV3の環境構築](https://note.com/kiyo_ai_note/n/nddaa85727c1d) 
- [Raspberry Pi 5にカメラを接続する](https://zenn.dev/thorie/scraps/663b022248e67a)

RaspberryPi についていえば、「インタフェース」が頻繁に記事を書いているので、それらを参照するとよい。

### NVIDIA Jetson
[Jetson AGX Orin](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-orin/)の仕様を見てください。
CSI カメラのインタフェースが書かれています。

#### StereoLab ZED2i カメラ
3Dカメラのインタフェースの例として、ZED2iカメラを示します。
このカメラのSDKでは、以下のことができます。

・RGB画像を取得する。
・深度画像を取得する。
・撮影した領域の点群データを取得する。
・内蔵のIMUのデータを取得する。
・データの取得時刻を返す。
・物体検出結果を3Dでの座標として返す。
・そのため、通常のカメラとは異なるインタフェースになっています。

[qiitaでZED-SDKのタグがついた記事](https://qiita.com/tags/zed-sdk)
にZED SDKの解説記事があります。

#### そのほかの3Dカメラ
3Dカメラのプロバイダは、たいがいの場合、C++やPythonで使えるSDKを提供しています。
それらのSDKでは、StereoLab ZED2i カメラと同様に
・撮影した領域の点群データを取得する。
・物体検出結果を3Dでの座標として返す
などを同様に実装している場合があります。

## GMSL2カメラ

[GMSLカメラをなんとなく理解する](https://zenn.dev/turing_motors/articles/00fa3a484520c3)
[自動運転カメラの高負荷、その原因はLinuxカーネルのどこに？](https://zenn.dev/turing_motors/articles/47399ffaad6887)
[Jetson へのGMSLカメラを調査中](https://qiita.com/nonbiri15/items/cef6e73b8dd30d2c2c81)


## Gstreamer
pipelineで動画入力からの処理を扱おうとする枠組みです。
pipelineに分割しないシングルスレッドの処理では
1. フレームの読み込み
2. 画像のリサイズ
3. 検出処理
4. 検出結果の表示
が同一のスレッドで動作します。
そのため、検出処理をしているときに、他のスレッドでフレームの読み込みをすることがありません。
マルチコアを用いているのにその利点が活用できていないことになります。

GSTEAMERを使うと、pipeline 内の各エレメントが別のスレッドで動作するため、
マルチコアの恩恵を受けやすくなります。

pipelineで動画入力からの処理を扱おうとする枠組みです。
pipelineに分割しないシングルスレッドの処理では
1. フレームの読み込み
2. 画像のリサイズ
3. 検出処理
4. 検出結果の表示
が同一のスレッドで動作します。
そのため、検出処理をしているときに、他のスレッドでフレームの読み込みをすることがありません。
マルチコアを用いているのにその利点が活用できていないことになります。

GSTEAMERを使うと、pipeline 内の各エレメントが別のスレッドで動作するため、
マルチコアの恩恵を受けやすくなります。


NVIDIA はGStreamer を基盤として[DeepStream](https://developer.nvidia.com/ja-jp/deepstream-sdk)を提供しています。

GStreamer, DeepStream については、それぞれ検索してみてください。

#### OpenCVでGstreamerを使うためには
[PythonでOpenCVからGStreamerを使うためのOpenCV4.6.0のBuildについて](https://qiita.com/TakahiroOta/items/a34b3d1db6475ddc31d7)

[How to install with GStreamer support](https://github.com/opencv/opencv-python/issues/530)

## V4L2
[第3話　ビデオ入力（USB接続のV4L2準拠カメラ）](https://www.macnica.co.jp/business/semiconductor/articles/nvidia/136506/)

#### ROS2でのV4Lカメラ
[ROS2でusbカメラから画像情報を取得する](https://qiita.com/Hiroaki-K4/items/53c2565c77319ecc76e2)

## argus カメラ
[第2話　ビデオ入力（CSI接続のLibargus準拠カメラ）](https://www.macnica.co.jp/business/semiconductor/articles/nvidia/136489/)
[Libargus Camera API](https://docs.nvidia.com/jetson/l4t-multimedia/group__LibargusAPI.html)
[Jetsonのカメラドライバを書く[Argus撮影編]](https://qiita.com/uzuna/items/675d4f43e2bd97e6d0b9)


## RTSP(Real Time Streaming Protocol)
ストリーミングデータの配信のプロトコールです。
[RTSP Client for Python](https://github.com/dactylroot/rtsp)

[python-rtsp-server](https://github.com/vladpen/python-rtsp-server)

未調査です。


## ROS2でカメラ画像をpublishする
[ros2_camera_publish](https://github.com/ANI717/ros2_camera_publish/tree/main)

ROS2では、ノード間で、messageをpublish, subsribe(あるいはlisten）することで通信することができます。


## H.264
#### opencv でH.264で書き込む
[cv2.VideoWriterでH264 codecを使う。](https://qiita.com/john-rocky/items/c72f9d79efbd4e3b3251)

#### opencv でH.264で読み込む
[OpenCV VideoCapture with H264 CODEC](https://stackoverflow.com/questions/27392455/opencv-videocapture-with-h264-codec)

# 画像認識では画像が取得できることが出発点です。
ボードがそのカメラを認識させること
ネットワークの場合プロトコールに対応させること
デコード処理を高速化させること
(デコード処理のアクセラレータを使うこと)
GPUを使う処理の場合、処理を一貫してGPUで行わせることで、CPU-GPU間のトラフィックを発生させないことです。

## カメラの撮影条件を改善すること
カメラの撮影条件は、ゲイン設定、露光時間など多数あります。
それらを最適な条件に保つことが、画像認識の出発点になります。
黒つぶれ・白飛び画像では、なにもできなくなってしまいます。

## データの遅延を減らすこと
- データ処理をpipelineにすることで、マルチコアのCPUの利点を引き出すこと
- 処理の中でのバッファリングの影響を減らすこと
- jpeg エンコード　jpeg デコードをpipeline に含めないこと
- CPU, GPU間のデータの転送を減らすこと
- CSI2カメラインタフェースから直接GPUに転送すること
[Reading CSI camera input directly to GPU memory](https://forums.developer.nvidia.com/t/reading-csi-camera-input-directly-to-gpu-memory/235301) のような要望はでている。