Fedora32（VMware）でwebカメラ（UVC）を動かす

#目的
``OpenCV4.2``でwebカメラを動かしたい！！

##環境
``OS : Fedora32 64bit (VMware Workstation 15 Player)``
[``webカメラ : ELECOM UCAM-C0220FBNWH``](https://www.elecom.co.jp/products/UCAM-C0220FBNWH.html)

#この記事のまとめ
###躓いた点
webカメラは認識されているが画面に映らない

###解決法
VMwareの ``仮想マシン設定 >> USBコントローラー >> USBの互換性`` を``USB2.0``から``USB3.1``へ変更する

***
#方法
##OpenCVのインストール
まずはOpenCV4.2のインストールをします。

```
sudo dnf update
sudo dnf install opencv
```

これでサポートされている中の最新のOpenCVがインストールされると思います。

##プログラミング
次にプログラムを書きます。今回は公開されているプログラムを``OpenCV4.2``用に変更して利用させていただきます。
``sample``というディレクトリを作成してその中に``sample.cpp``を書きます。好きでVimを使っているのでエディタは何でも良いです。

```
mkdir sample
cd sample
vim sample.cpp
```

```sample.cpp

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

int main(int argc, char *argv[])
{
  cv::VideoCapture cap(0);
  // 様々な設定...
  cap.set(cv::CAP_PROP_FRAME_WIDTH, 640);
  cap.set(cv::CAP_PROP_FRAME_HEIGHT, 480);
  // カメラがオープンできたかの確認
  if(!cap.isOpened()) return -1;

  cv::namedWindow("Capture", cv::WINDOW_AUTOSIZE|cv::WINDOW_FREERATIO);
  while(1) {
    cv::Mat frame;
    cap >> frame;  // キャプチャ
    // 様々な処理
    // ...
    cv::imshow("Capture", frame); // 表示
    if(cv::waitKey(30) >= 0) 
       {
	  cv::imwrite("cap.png", frame);
       break;
       }
  }
}

```
[参考にさせていただいたプログラム](http://opencv.jp/cookbook/opencv_io.html#id6)

##ビルド
ビルド方法は様々ありますが今回は汎用性も加味して``cmake``を用います。
``sample``ディレクトリ内に``CMakeLists.txt``を作ります。

```
vim CMakeLists.txt
```
中身は公式に公開されているものを参考にさせていただきます。

```CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project( Sample )
find_package( OpenCV REQUIRED )
file(GLOB SRC
    "*.h"
    "*.cpp"
)
add_executable( exe ${SRC} )
target_link_libraries( exe ${OpenCV_LIBS} )
```
[参考にさせていただいたプログラム](https://docs.opencv.org/2.4/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.html)

##カメラを接続
PCにカメラを接続しポップアップで出てくる``新しいUSBデバイスが検出されました``と言う画面から``仮想マシンに接続``を選択します。

以下のコマンドでカメラが認識されているか確認できます。

```
$ lsusb
Bus 001 Device 002: ID 056e:7016 Elecom Co., Ltd UCAM-C0220F
```
このようにカメラっぽいものがあれば認識されています。

※今回用いているカメラはUVCと言われるカメラの種類で自分でドライバを入れる必要がないため、ドライバのインストールについては触れません。UVCでないカメラで認識されない場合は各自ドライバをインストールしてください。

##実行（まだここでは動かないため注意）

sampleディレクトリ内で以下のコマンドを実行します。

```
mkdir build
cd build
cmake ..
make
./exe
```

すると

```
$ ./exe
[ INFO:0] global /builddir/build/BUILD/opencv-4.2.0/modules/videoio/src/videoio_registry.cpp (187) VideoBackendRegistry VIDEOIO: Enabled backends(7, sorted by priority): FFMPEG(1000); GSTREAMER(990); INTEL_MFX(980); V4L2(970); CV_IMAGES(960); CV_MJPEG(950); FIREWIRE(940)
[ INFO:0] global /builddir/build/BUILD/opencv-4.2.0/modules/videoio/src/cap_gstreamer.cpp (690) open OpenCV | GStreamer: v4l2src device=/dev/video0 ! videoconvert ! appsink drop=true
[ INFO:0] global /builddir/build/BUILD/opencv-4.2.0/modules/videoio/src/cap_gstreamer.cpp (723) open OpenCV | GStreamer: mode - MANUAL

```
と出てきて写真も撮れず、プログラムも終了しません。

とりあえず``Ctrl+C``で終了します。

##原因
+ プログラムが悪い
+ カメラが悪い
+ ドライバが機能していない
+ OSが悪い
+ VMwareが悪い

と様々な原因が考えられたため、それぞれ検証しました。

すると、カメラは正常で、ドライバも機能しているし、Ubuntuでも同じ症状が出ていました。試しに``cheese``という写真を撮るだけのソフトを使ってみると、PCのカメラでは映るがwebカメラでは黒い画面になりソフトが動きません。つまりプログラムが悪いわけでも無さそうでした。
この症状からすると**接続はされているが間にVMwareがあるためデータが遮断されている**、という可能性がありました。その前提で調べてみると[このサイト](https://askubuntu.com/questions/864399/webcam-not-working-on-ubuntu-16-04-with-vmware)が見つかりました。
このサイトには

>Change USB Compatibility to 1.1 in Virtual Machine Settings.

と書かれておりVMwareの設定からUSB接続の設定を``USB1.1``に変えると良くなるということでした。恐らく古いサイトのため``USB1.1``への変更をしていますが、それぞれのパソコンかwebカメラにあった設定にするべきなのだと思います。

##解決法
VMwareの左上から、``Player(P) >> 管理(M) >> 仮想マシン設定(S)``を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270096/84980fae-e855-3454-a2d7-7e3c02bc44d4.png)
開いた画面のデバイスからUSBコントローラを選び、USBの互換性をUSB 3.1に変更しOKを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270096/00cce5b5-090e-4a84-4ca6-1a2a561a7244.png)


すると、サスペンドモードになりVMwareが閉じます。そのためもう一度VMwareからFedoraを起動させてください。

元の画面に戻ったはずなのでもう一度プログラムを実行します。

```
$ ./exe
[ INFO:0] global /builddir/build/BUILD/opencv-4.2.0/modules/videoio/src/videoio_registry.cpp (187) VideoBackendRegistry VIDEOIO: Enabled backends(7, sorted by priority): FFMPEG(1000); GSTREAMER(990); INTEL_MFX(980); V4L2(970); CV_IMAGES(960); CV_MJPEG(950); FIREWIRE(940)
[ INFO:0] global /builddir/build/BUILD/opencv-4.2.0/modules/videoio/src/cap_gstreamer.cpp (690) open OpenCV | GStreamer: v4l2src device=/dev/video0 ! videoconvert ! appsink drop=true
[ INFO:0] global /builddir/build/BUILD/opencv-4.2.0/modules/videoio/src/cap_gstreamer.cpp (723) open OpenCV | GStreamer: mode - MANUAL
[ WARN:0] global /builddir/build/BUILD/opencv-4.2.0/modules/videoio/src/cap_gstreamer.cpp (935) open OpenCV | GStreamer warning: Cannot query video position: status=0, value=-1, duration=-1

```
と出て
![刑務所に入れられる消しゴム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270096/ef6121f9-6b37-c9ec-b015-4e8fbd4c09e1.png)
見事カメラが動きます！！
また、``build``ディレクトリ内に``cap.png``が出来ているはずです。

終了時は``Ctrl+C``で強制終了することができます。

#まとめ
VMwareで外部との接続が必要なものを動かすときはVMwareの設定に気をつけましょう。

#参考
+ カメラ詳細 https://www.elecom.co.jp/products/UCAM-C0220FBNWH.html
+ OpenCVプログラム http://opencv.jp/cookbook/opencv_io.html#id6

+ OpenCVのCMakeの基本
https://docs.opencv.org/2.4/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.html

+ ライブラリ自動検索
https://qiita.com/shohirose/items/d9bda00a39a113965c5c

+ ファイル自動追加
https://www.it-swarm.dev/ja/c++/cmake%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E3%80%81%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E3%83%BC%E5%86%85%E3%81%AE%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E3%82%BF%E3%83%BC%E3%82%B2%E3%83%83%E3%83%88%E3%81%AB%E8%87%AA%E5%8B%95%E7%9A%84%E3%81%AB%E8%BF%BD%E5%8A%A0%E3%81%97%E3%81%BE%E3%81%99%E3%81%8B%EF%BC%9F/969423914/


+ webcam-vmware https://askubuntu.com/questions/864399/webcam-not-working-on-ubuntu-16-04-with-vmware