WEBカメラと産業用UVCカメラのv4l2-ctrlのプロパティの差


#背景
今まで監視カメラを通して目視検査で検査を行っていたが、
人の目に代わるカメラ、人の頭脳に代わる画像処理ソフトウェアに置き換わるようになってきた。画像処理に関する資料は多くあるが意外とカメラに関するドキュメントが少ない。カメラといっても安いAmazonで売っているようなWebカメラからBtoB向けの産業用カメラまで幅広く、どう違うのか正直分からないので、ハイスペックなカメラ（産業用カメラ）とWebカメラに差異がどの程度あるのかLinuxで検証する。

#Linuxでカメラを使うには
LinuxカーネルのカメラドライバVideo for Linux Two(V4L2)というビデオキャプチャAPIとして実装するのが一般的。
最近のlinux(Linux 2.6.26以降)だと、 V4L2、UVCカメラドライバは既にカーネルに含まれている模様。

#検証するカメラに関して
Webカメラで使われている規格UVC(USB Video Class)に準拠したカメラを使用。
v4l2の汎用的なLinuxドライバーを用いてデバイス制御が可能。

参考：https://www.argocorp.com/UVC_camera/Linux.html

#v4l2のコマンドでプロパティを確認するためには
v4l-ctlコマンドでオプションに「-list_formats」を指定すれば Video4Linux2でサポートされているプロパティを確認できる。

参考：https://leico.github.io/TechnicalNote/Linux/webcam-usage

#WEBカメラのプロパティを確認
使用したカメラ：Logitech（ロジテック） ウェブカメラ V-U0015 
<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136687/78bf6395-93a7-fdbf-9d61-0c49fb6e1b05.jpeg">


###カメラのプロパティ情報を確認
```console:terminal-webcamera
pi@raspberrypi:~ $ v4l2-ctl --list-ctrls
                     brightness 0x00980900 (int)    : min=0 max=255 step=1 default=128 value=128
                       contrast 0x00980901 (int)    : min=0 max=255 step=1 default=32 value=32
                     saturation 0x00980902 (int)    : min=0 max=255 step=1 default=32 value=32
 white_balance_temperature_auto 0x0098090c (bool)   : default=1 value=1
                           gain 0x00980913 (int)    : min=0 max=255 step=1 default=64 value=64
           power_line_frequency 0x00980918 (menu)   : min=0 max=2 default=2 value=2
      white_balance_temperature 0x0098091a (int)    : min=0 max=10000 step=10 default=4000 value=4000 flags=inactive
                      sharpness 0x0098091b (int)    : min=0 max=255 step=1 default=24 value=24
         backlight_compensation 0x0098091c (int)    : min=0 max=1 step=1 default=0 value=0
                  exposure_auto 0x009a0901 (menu)   : min=0 max=3 default=3 value=3
              exposure_absolute 0x009a0902 (int)    : min=1 max=10000 step=1 default=166 value=166 flags=inactive
         exposure_auto_priority 0x009a0903 (bool)   : default=0 value=1
                      led1_mode 0x0a046d05 (menu)   : min=0 max=3 default=3 value=3
                 led1_frequency 0x0a046d06 (int)    : min=0 max=131 step=1 default=0 value=0
```

色調、ホワイトバランス（オンオフのみ）、ゲイン、自動露光、固定露光時間、コントラスト等は制御できる。
led1_modeやled1_frequencyといったLEDインジゲーター点灯を変えられるのは特徴的。


###とりあえず画面に出す
gstreamerのパイプラインを使って画面を表示してみる。
参照：https://gstreamer.freedesktop.org/documentation/video4linux2/v4l2src.html?gi-language=c

```console:terminal
gst-launch-1.0 v4l2src　! videoconvert ! ximagesink
```

実際に露光時間を設定してみる。自動露光を切り、露光時間をセットする。

```console:terminal
v4l2-ctl --set-ctrl=exposure_auto=1,exposure_absolute=30
```
https://seesaawiki.jp/w/renkin3q/d/Linux/v4l2-ctl

####実行結果
<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136687/c3828593-17a9-211a-5afb-940a18a5c903.png">


自動露光をオフにしても、自動ゲインが有効になっているのが原因で暗いところから明るいところにカメラを映すと若干白飛びする。
ただ、早く動き回るものや明るさの制御やトリガー処理などが不要であれば特に困ることはない。

#産業用カメラ
使用したカメラ：TheImagingSource社 産業用カメラ DFK33UP2000 

<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136687/6ab25f72-93cf-d35d-40b4-8d147e937265.jpeg">



###カメラのプロパティ情報を確認
```console:terminal-industrial-camera
pi@raspberrypi:~ $ v4l2-ctl --list-ctrls
                     saturation 0x00980902 (int)    : min=0 max=255 step=1 default=64 value=64
                            hue 0x00980903 (int)    : min=-180 max=180 step=1 default=0 value=0
   white_balance_component_auto 0x0098090c (bool)   : default=1 value=1
    white_balance_red_component 0x0098090e (int)    : min=0 max=255 step=1 default=64 value=69 flags=inactive
   white_balance_blue_component 0x0098090f (int)    : min=0 max=255 step=1 default=64 value=125 flags=inactive
                          gamma 0x00980910 (int)    : min=1 max=500 step=1 default=100 value=100
                           gain 0x00980913 (int)    : min=144 max=1200 step=1 default=144 value=144
                  exposure_auto 0x009a0901 (menu)   : min=0 max=3 default=3 value=3
              exposure_absolute 0x009a0902 (int)    : min=1 max=100000 step=1 default=3 value=3 flags=inactive
               exposure_time_us 0x0199e201 (int)    : min=50 max=10000000 step=1 default=333 value=333
                   auto_shutter 0x0199e202 (bool)   : default=1 value=1
        auto_exposure_reference 0x0199e203 (int)    : min=0 max=255 step=1 default=128 value=128
                      gain_auto 0x0199e205 (bool)   : default=1 value=1
                   trigger_mode 0x0199e208 (bool)   : default=0 value=0
               software_trigger 0x0199e209 (button) : flags=write-only
                  trigger_delay 0x0199e210 (int)    : min=0 max=1000000 step=1 default=0 value=159
                  strobe_enable 0x0199e211 (bool)   : default=0 value=0
                strobe_polarity 0x0199e212 (bool)   : default=0 value=0
                strobe_exposure 0x0199e213 (bool)   : default=0 value=0
                          gpout 0x0199e216 (bool)   : default=0 value=0
                           gpin 0x0199e217 (bool)   : default=0 value=0
                   roi_offset_x 0x0199e218 (int)    : min=0 max=1664 step=32 default=0 value=0
                   roi_offset_y 0x0199e219 (int)    : min=0 max=1184 step=4 default=0 value=0
                roi_auto_center 0x0199e220 (bool)   : default=1 value=1
               trigger_polarity 0x0199e234 (menu)   : min=0 max=1 default=0 value=1
            trigger_burst_count 0x0199e237 (int)    : min=1 max=1000 step=1 default=1 value=1
       trigger_debounce_time_us 0x0199e238 (int)    : min=0 max=1000000 step=1 default=0 value=0
           trigger_mask_time_us 0x0199e239 (int)    : min=0 max=1000000 step=1 default=0 value=0
 trigger_noise_suppression_time 0x0199e240 (int)    : min=0 max=1000000 step=1 default=0 value=0
     auto_functions_roi_control 0x0199e241 (bool)   : default=1 value=1
        auto_functions_roi_left 0x0199e242 (int)    : min=0 max=1904 step=1 default=0 value=480
         auto_functions_roi_top 0x0199e243 (int)    : min=0 max=1184 step=1 default=0 value=300
       auto_functions_roi_width 0x0199e244 (int)    : min=16 max=1920 step=1 default=0 value=960
      auto_functions_roi_height 0x0199e245 (int)    : min=16 max=1200 step=1 default=0 value=600
             white_balance_mode 0x0199e246 (menu)   : min=0 max=1 default=0 value=0
      white_balance_auto_preset 0x0199e247 (menu)   : min=0 max=4 default=0 value=0
  white_balance_green_component 0x0199e248 (int)    : min=0 max=255 step=1 default=64 value=64
      white_balance_temp_preset 0x0199e249 (menu)   : min=0 max=8 default=6500 value=4
      white_balance_temperature 0x0199e250 (int)    : min=2500 max=10000 step=100 default=6500 value=4000
 exposure_auto_upper_limit_auto 0x0199e254 (bool)   : default=1 value=1
   exposure_auto_upper_limit_us 0x0199e256 (int)    : min=50 max=1000000 step=1 default=333 value=33333
         override_scanning_mode 0x0199e257 (int)    : min=1 max=16 step=1 default=1 value=0
      auto_functions_roi_preset 0x0199e258 (menu)   : min=0 max=5 default=2 value=2
   trigger_global_reset_release 0x0199e261 (bool)   : default=0 value=0

```
設定できる項目数はWebカメラに比べて圧倒的に多い。
産業用カメラにあってWebカメラにしかない項目は
led1_modeやled1_frequencyといったLEDインジゲーター点灯項目のみ。
ゲインや露光時間はもちろんトリガー、ストロボアウト、ホワイトバランス、画素切り出し（ROI）も設定できる。

###とりあえず画面に出す
Webカメラと同様にgstreamerのパイプラインを使って画面を表示してみる。

```console:terminal
gst-launch-1.0 v4l2src ! videoconvert ! ximagesink
```

メーカー独自のモジュールを使えば拡張できる。
参照(手順):https://www.argocorp.com/software/DL/tis/Linux/RaspberryPI_USB.html
参照(Github):https://github.com/TheImagingSource/tiscamera
参照(Tutorial):https://www.theimagingsource.com/documentation/tiscamera/tutorial.html


```console:terminal
gst-launch-1.0 tcamsrc serial=<serial>! video/x-bayer,width=2592,height=1944,framerate=15/2 ! tcamwhitebalance auto=false red="75" green="65" blue="115" ! bayer2rgb !
jpegenc ! multifilesink location=/home/xxxx/output%d.jpeg
```

GStreamerのパイプラインに関して詳しくなくても
GStreamerをラップしたPythonのラッパーファイルもあるようなのでWebカメラと同等に制御できそう。

参照:https://www.argocorp.com/UVC_camera/Sample_Python_ExternalTrigger.html

####実行結果
<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136687/6a00c3dc-d3f0-2e71-410a-03658ed1de94.png">

メーカー製のモジュールを使わなくても露光時間やゲインの調整はもちろん、トリガーやストロボの制御まで可能。
メーカー製のモジュールを使用することで、gstereamerのパイプラインを意識することなく簡単にコーディングができ、初心者がPythonの実装するときなど向いている。
Webカメラよりも解像度が高いカメラを使ったので若干撮影した画像もきれいに取得することができた。

#結論
Webカメラでも単純な画像取得はある程度可能だが、色味の再現性や白とびがどうしても避けられない。そのため、細かいカメラの制御が可能な産業用カメラを使うことで基盤の検査システムや車載カメラシステムなどに使用できそう。