Raspberry pi zero w + Camera Module v2 + OpenCV + etc...で Lan内ストリーミング配信の下準備

# はじめに
　[前回は、Jetson Nano でのモバイル映像ストリーミングを試みたが成功できなかった]()。失敗の要因は、素人がアマゾンで買えるような市販のモバイルバッテリーでは駆動させられなかった、と結論した。今回は、モバイルバッテリーでも駆動できるであろうRaspberry pi zero w を使って、モバイル映像ストリーミングにチャレンジする。

# Raspberry pi zero w の セットアップ
　本体、公式ケース（蓋３種セット）、Raspberry Pi Camera Module V2 を購入した。セットアップにあたり、まずはRaspberry Pi OSを格納するMicroSDカードが必要だ。Webで情報を色々と調べると、８GB以上を使用している人がおおいようだが、今回はカメラのストリーミングしか行わないつもりなので、OSに Raspberry Pi LITEを選ぶこととし、むかーし使って今は引退しているMicroSDカード４GB（Class6）を使ってみることにした。OSをSDカードに書き込む手順については、[公式](https://www.raspberrypi.org/software/)の他、Qiita諸兄も色々と書いていらっしゃるので参考に困ることはないだろう。
　さて、SDカードが準備できたら、Raspberry Pi Zero Wにセットし、[カメラも接続して](https://images-na.ssl-images-amazon.com/images/I/61eDCbQ50lL._AC_SL1500_.jpg)いよいよ電源を・・・と、ここで気づく。あれ？これ、電源入れて初期設定ってどうやってやるのだ？ [HDMIは、miniなタイプだし、USB端子はマイクロなタイプが１つ（２つある端子のうち１つは電源専用）](https://images-na.ssl-images-amazon.com/images/I/41S9GcqfmcL._AC_SL1004_.jpg)、キーボードやマウスやディスプレイを割と普通にHDMI接続したり、USB（TypeA）でつないだり、なんてできない。いつものようにQiitaやGoogleで検索し、先人諸兄の知恵をお聞かせ願おう。そして見つかった方法が、USBケーブルでの接続を通じてSSHログインして各種設定を行う、という以下の方法。ガジェットモードとか呼ばれることもあるらしい。
　
　USB 1本とSDカードライタだけでできるUSB OTGを用いたRapsberry Pi Zero WH のセットアップ
　https://qiita.com/Liesegang/items/dcdc669f80d1bf721c21

　USBケーブル１本でRaspberry Pi Zeroの電源とネットワークを兼用させるUSB-OTGの設定方法。
　https://www.boardgamepark.com/entry/USB-OTG

　USBガジェットモードでRaspberry Pi 4Bもイケる
　https://raspida.com/usb-gadget-mode4rpi4b

　sshに成功したら、設定メニューで装置の初期化を行う。

    $ sudo raspi-config

１）　Filesystem　拡張
　Advanced Options > Expand File System でSDカードに書き込んだイメージの大きさの余剰部分をファイルシステムに追加してくれる。

２）　"pi"　Userのパスワード変更
　System Options > Password で設定。デフォルト以外のパスワードに変更できる。

3) カメラインターフェースの有効化
　Interface Options > Camera で設定。Enableにする。

4）　Localization
　Localization Options > Locale および Timezone を JA, Asia/Tokyo に変更した。

5）　Wireless Lan
　System Options > Wireless LAN を使って、wifiの設定を行って、再起動してしまえば、あとは電源供給を考えてしまえばリモート接続の心配はなくなる・・・と思ったのだが、raspi-config > wifi settings で設定した情報では、Wifi接続しない。この設定メニューでは、パスワードのタイプを聞いてこない。WEAなのかWPAなのかぐらい聞いてもよさそうなものを・・・。うまく動かない理由について個人的推察だが、パスワードの暗号化処理を行わないのではないか。そこで、上述の先輩の操作紹介のうち、コマンドラインでWifiを設定している手順を真似ることにした。自宅で利用する場合用のWifiの設定と、外出先でモバイルWifiもしくは会社のWifiを使う場合の設定など、Wifiの設定を複数利用することが見込まれるときは、手順を繰り返していくと、/etc/wpa_supplicant/wpa_supplicant.confに情報が追記され、利用可能なWifi接続情報をOSが起動時に自動選択してくれるようになる。

```
$ cd ~

# パスワードが履歴に残らないように，ファイルに書く
$ vi pass 

# 設定をファイルに書き出す
$ sudo sh -c 'wpa_passphrase "wifiのSSID" < pass >> /etc/wpa_supplicant/wpa_supplicant.conf'

# 生のパスフレーズがコメントアウトされて書き込まれているので消去する(#psk="**********"という行)
$ sudo vi /etc/wpa_supplicant/wpa_supplicant.conf

# 再起動
$ sudo reboot

# つながったらパスワードファイルを消去
$ rm ~/pass
```

これで再起動すれば、Wifi側からSSHできるようになる。一旦、電源を切って、USBの接続を電源専用に変えてみよう。

```
$ sudo poweroff
```

# カメラモジュールの設定確認

 カメラの設定状態確認のコマンドがあるらしい。こちらのサイトの情報を参考にした。

 公式カメラモジュールで省電力「あんまり監視しないカメラ」を作ってみた！
　https://raspida.com/surveillance-camera

```
'カメラモジュールのバージョン確認
$ vcgencmd version
Jun 7 2018 15:37:30
Copyright (c) 2012 Broadcom
version 4800f08a139d6ca1c5ecbee345ea6682e2160881 (clean) (release)

'カメラが検出されるかどうか確認
$ vcgencmd get_camera
supported=1 detected=1

```
 detectedは検出という意味なので、1ならOK。

 なお、この参考サイトで、静止画を一定間隔で更新表示するWebサーバーを設置する手法を記述しているが、この方法だと、毎回SDカード上にファイルを作成してそれを読み取る仕組みになるので、ちょっと思ったような画像更新速度が出せないかもしれない（私の使っているSDカードが古いClass6のせい）と思ったので、今回は別の方法にチャレンジしてみることにした。

　別の方法について、紹介しているサイトを３つ見つけた。

　１：mjpegstreamerを使う方法
　　ラズパイZeroとPi cameraでLEGOトレインの車載カメラをつくる
　　https://zoe6120.com/2019/04/30/786/
　
　２：UV4Lを使う方法
　　Raspberry Pi Zero W カメラ映像をリアルタイムでストリーミングする方法
　　https://robopara.co.jp/raspberry-pi-zero-w-%E3%82%AB%E3%83%A1%E3%83%A9%E6%98%A0%E5%83%8F%E3%82%92%E3%83%AA%E3%82%A2%E3%83%AB%E3%82%BF%E3%82%A4%E3%83%A0%E3%81%A7%E3%82%B9%E3%83%88%E3%83%AA%E3%83%BC%E3%83%9F%E3%83%B3%E3%82%B0/

　３：gstreamer+opencv
　　Raspberry PiにOpenCV+gstreamerをインストールしH264動画をキャプチャ
　　https://qiita.com/yamato225/items/0870beca1822c6dccad3

　筆者としては、Raspberry pi から[送信されるカメラ映像を、受信したPC等のソフトウェアで処理するにあたり、OpenCVでデータを扱えることが理想](https://qiita.com/tomofu74/items/0824c896819c087b7fbd)であるが、どの方法がベストなのかわからない。使っているSDカードの容量を考えると、すべての方法を同時に試すこともできないと思われる。JetsonNanoでのPythonスクリプトの動作経験も踏まえて、将来、送信側のSocketを作って・・・とか考えつく可能性もあるので、今回はOpenCVをインストールして、Pythonのスクリプトでデータを送る方法に備えることとして取り組んでみることにした。たぶん、表題の事案に対しては遠回りな答えだろう。

# OpenCV のインストール（ビルド）
　愚直に、ソースをとってきてビルドする。果たして、何時間かかるだろう・・・。

　ちなみに、OpenCVをaptでインストールした人の情報。

　【Raspberry Pi】Raspberry Pi Zero WにOpenCVの環境を構築する
　https://rikoubou.hatenablog.com/entry/2019/05/21/151337

```
sudo apt-get install libatlas-base-dev
sudo apt-get install libjasper-dev
sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev
sudo apt-get install ffmpeg x264 x265
sudo apt-get install cmake libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-tools libgtk2.0-dev gstreamer1.0-omx=1.0.0.1-0+rpi12+jessiepmg gstreamer1.0-plugins-bad gstreamer1.0-plugins-good
sudo apt-get install python2-dev python3-dev
sudo apt-get install python3-pip

python3 -m pip install numpy

'任意の作業用ディレクトリを作成して、OpenCVのソースをゲット。
mkdir OpenCV
cd OpenCV
wget https://github.com/opencv/opencv/archive/4.5.0.zip
unzip 4.5.0.zip
```

 この時点で、  df -m してみると、ディスクの残り空き容量は１GB弱。
・・・このディスクの空き容量を気にしながらシングルコアのコンピュータでmakeに取り掛かる緊張感・・・。20年ぶりぐらいか・・・

python2用のライブラリは作らないことにする。

```
cd opencv-4.5.0
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=RELEASE  -DINSTALL_C_EXAMPLES=OFF  -DWITH_1394=OFF -DWITH_GSTREAMER=ON -DWITH_FFMPEG=ON -DWITH_QT=OFF -DBUILD_opencv_python2=OFF -DBUILD_opencv_python3=ON -DPYTHON_DEFAULT_EXECUTABLE=$(which python3) ..
```

...10分ほどで、CMAKE終了。Configureできた内容確認。

```
-- General configuration for OpenCV 4.5.0 =====================================
--   Version control:               unknown
-- 
--   Platform:
--     Timestamp:                   2021-01-17T10:49:26Z
--     Host:                        Linux 5.4.83+ armv6l
--     CMake:                       3.13.4
--     CMake generator:             Unix Makefiles
--     CMake build tool:            /usr/bin/make
--     Configuration:               RELEASE
-- 
--   CPU/HW features:
--     Baseline:
--       requested:                 DETECT
--       disabled:                  VFPV3 NEON
-- 
--   C/C++:
--     Built as dynamic libs?:      YES
--     C++ standard:                11
--     C++ Compiler:                /usr/bin/c++  (ver 8.3.0)
--     C++ flags (Release):         -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wsuggest-override -Wno-delete-non-virtual-dtor -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections  -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG  -DNDEBUG
--     C++ flags (Debug):           -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wsuggest-override -Wno-delete-non-virtual-dtor -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections  -fvisibility=hidden -fvisibility-inlines-hidden -g  -O0 -DDEBUG -D_DEBUG
--     C Compiler:                  /usr/bin/cc
--     C flags (Release):           -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wuninitialized -Winit-self -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections  -fvisibility=hidden -O3 -DNDEBUG  -DNDEBUG
--     C flags (Debug):             -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wuninitialized -Winit-self -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections  -fvisibility=hidden -g  -O0 -DDEBUG -D_DEBUG
--     Linker flags (Release):      -Wl,--gc-sections -Wl,--as-needed  
--     Linker flags (Debug):        -Wl,--gc-sections -Wl,--as-needed  
--     ccache:                      NO
--     Precompiled headers:         NO
--     Extra dependencies:          dl m pthread rt
--     3rdparty dependencies:
-- 
--   OpenCV modules:
--     To be built:                 calib3d core dnn features2d flann gapi highgui imgcodecs imgproc ml objdetect photo python3 stitching ts video videoio
--     Disabled:                    world
--     Disabled by dependency:      -
--     Unavailable:                 java js python2
--     Applications:                tests perf_tests apps
--     Documentation:               NO
--     Non-free algorithms:         NO
-- 
--   GUI: 
--     GTK+:                        YES (ver 2.24.32)
--       GThread :                  YES (ver 2.58.3)
--       GtkGlExt:                  NO
--     VTK support:                 NO
-- 
--   Media I/O: 
--     ZLib:                        /usr/lib/arm-linux-gnueabihf/libz.so (ver 1.2.11)
--     JPEG:                        libjpeg-turbo (ver 2.0.5-62)
--     WEBP:                        build (ver encoder: 0x020f)
--     PNG:                         /usr/lib/arm-linux-gnueabihf/libpng.so (ver 1.6.36)
--     TIFF:                        build (ver 42 - 4.0.10)
--     JPEG 2000:                   build (ver 2.3.1)
--     OpenEXR:                     build (ver 2.3.0)
--     HDR:                         YES
--     SUNRASTER:                   YES
--     PXM:                         YES
--     PFM:                         YES
-- 
--   Video I/O:
--     FFMPEG:                      YES
--       avcodec:                   YES (58.35.100)
--       avformat:                  YES (58.20.100)
--       avutil:                    YES (56.22.100)
--       swscale:                   YES (5.3.100)
--       avresample:                NO
--     GStreamer:                   YES (1.14.4)
--     v4l/v4l2:                    YES (linux/videodev2.h)
-- 
--   Parallel framework:            pthreads
-- 
--   Trace:                         YES (with Intel ITT)
-- 
--   Other third-party libraries:
--     Lapack:                      NO
--     Eigen:                       NO
--     Custom HAL:                  NO
--     Protobuf:                    build (3.5.1)
-- 
--   OpenCL:                        YES (no extra features)
--     Include path:                /home/pi/OpenCV/opencv-4.5.0/3rdparty/include/opencl/1.2
--     Link libraries:              Dynamic load
-- 
--   Python 3:
--     Interpreter:                 /usr/bin/python3 (ver 3.7.3)
--     Libraries:                   /usr/lib/arm-linux-gnueabihf/libpython3.7m.so (ver 3.7.3)
--     numpy:                       /home/pi/.local/lib/python3.7/site-packages/numpy/core/include (ver 1.19.5)
--     install path:                lib/python3.7/dist-packages/cv2/python-3.7
-- 
--   Python (for build):            /usr/bin/python3
-- 
--   Java:                          
--     ant:                         NO
--     JNI:                         NO
--     Java wrappers:               NO
--     Java tests:                  NO
-- 
--   Install to:                    /usr/local
-- -----------------------------------------------------------------
-- 
-- Configuring done
-- Generating done
-- Build files have been written to: /home/pi/OpenCV/opencv-4.5.0/build

```
お、Raspberry pi zero w って、ArmV6なCPUなのか・・・。OpenCVサポートできるのかな。

とりあえず、makeを仕掛けてみますか・・・。１２時間で終わるかなぁ・・・。

24時間はかかる、という情報が・・・
https://raspberrypi.stackexchange.com/questions/112154/installing-opencv-on-a-raspberry-pi-zero

```
make -j2
```
12時間かかって65％・・・。ここから進まない。
24時間かかって９３％で、ネットワークエラー。これは家庭の事情だ。
・・・そして、３日目に入る。まだできない・・・。Swap領域を確保しないとメモリ不足か？ここらで諦めずに

```
make
```
やはりだめだ。スタックしてるっぽい。

# SWAP領域の拡張

　　参考：　Raspberry Pi のスワップ領域拡張
　  https://qiita.com/nyas/items/f4d0675061ee8cdcc3e7

/etc/dphys-swapfile の CONF_SWAPSIZE はデフォルトで１００となっている。先のmakeの時点で、残りの容量は６００MB強。ここで強気に値をあげてみる。

```
$ sudo vi /etc/dphys-swapfile

# set size to absolute value, leaving empty (default) then uses computed value
#   you most likely don't want this, unless you have an special disk situation
# CONF_SWAPSIZE=100
CONF_SWAPSIZE=512
```

再起動

```
$ sudo reboot
```

そして、makeの続きを・・・

```
$ cd OpenCV/opencv-4.5.0/build/
$ make
```
・・・　その後、3時間ほどして　１００％ 完了した。

```
$ sudo make install
```

さて、opencvをpython3で使えるようになったかな？

```
$ python3

Python 3.7.3 (default, Jul 25 2020, 13:03:44) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>>
```
とりあえず、文句言わずにimportしてくれはりましたわ！おおきに！

# おわりに

Raspberry pi zero w にカメラモジュールをセットアップして、opencvをインストールした。opencvのビルドにあたっては、swap領域の拡張が必要だということがわかった。