HeadLess環境のRaspberryPi Zero WHで顔検出が出来るまで

#目標
RaspberryPi Zero WHをPCとUSBケーブルで接続し、セットアップします。
OpenCVとRasPiカメラを使って顔検出ができるまでの手順を説明します。

#環境（2020/09/06現在）
・RaspberryPi Zero WH（Wifiは使わないのでZeroでもOKです）
・PC（記事ではWin10マシンです）
・RaspberyPi Camera
・MicroUSBケーブル
・MicroSDカード（8GB以上　記事では32GBを使用）
・RasoberryPi OS （2020/08/20版）

#OSのインストールとセットアップ
##OSのインストール
Raspberry Pi OSは[Raspberry Pi Imager](https://www.raspberrypi.org/downloads/)を利用すると簡単にインストールできます。
![imager.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/eba361c9-f988-e433-74a2-985076cf0130.png)

標準ではデスクトップ版がインストールされます。

##セットアップ
書き込みが完了後SDカードを一旦取り外して再度マウントします。

SDカードを開いてファイルを編集します。

### config.txtファイル
config.txtファイルの最終行に以下の文を追加します。

```config.txt
dtoverlay=dwc2
```

###cmdline.txtファイル
cmdline.txtに次の文を追加します。
文中の「rootwait」と「quiet」の間に「modules-load=dwc2,g_ether」を追加します。

```cmdline.txt
console=serial0,115200 console=tty1 root=PARTUUID=58ce116e-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait modules-load=dwc2,g_ether quiet init=/usr/lib/raspi-config/init_resize.sh splash plymouth.ignore-serial-consoles
```

###sshファイルの追加
Bootパーティションに「ssh」というファイルを作成してください。
エクスプローラーでBootパーティションを開き、右クリック>新規作成>テキストドキュメントで「新しいテキストドキュメント.txt」を作成してから、ファイル名を「ssh」に変更します。この時拡張子「.txt」は付けないようにしてください。

ここまでがPC上で行うセットアップになります。
次はSDカードをRaspberry Pi Zeroに挿してからPCとUSBケーブルで接続しましょう。カメラも忘れずに接続してください。

###ドライバーのインストール
PCとRaspberry Pi Zeroを接続するとデバイスマネージャー上にUSBシリアルデバイスが現れます。
![driver.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/c6b4e06a-06f9-7601-d708-36a5331153fd.png)

このままではRaspberry Pi Zeroと通信できないので、PCからRaspberry Pi Zeroをネットワークデバイスとして認識するためのドライバーを次のリンクからダウンロードし、解凍しておきます。

[RPI Driver OTG](https://caron.ws/wp-content/uploads/telechargement/RPI%20Driver%20OTG.zip)

デバイスマネージャー上のUSBシリアルデバイスを右クリックしてドライバーの更新を選びます。

![driver2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/beef14f0-682b-bc5a-19df-2cf501db7389.png)

「コンピューターを参照してドライバーソフトウェアを検索」を選択して、先ほど解凍したフォルダを参照して次へをクリックします。
![driver3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/91aa6b94-b24f-a676-0bfb-8ebf9bfae44d.png)

インストールに成功すると次のようになります。
![driver4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/c3a97398-c36b-2410-6c51-db39f15d151d.png)

デバイスマネージャーのネットワークアダプタ上に「USB Ethernet/RNDIS Gadget」が現れます。
![driver5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/e1dfef2b-b23d-31ed-427f-bb95d08d6bbf.png)

これでターミナルプログラムからSSHでアクセスできるようになります。


###Raspberry Pi Zero上のセットアップ
お好きなターミナルソフト（筆者はWindowsTerminalを使っています）を起動し、Raspberry Pi ZeroにSSHで接続します。

```
> ssh pi@raspberrypi.local
```

![terminal1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/d775cd65-3993-4a14-e416-1a69ef00b20e.png)

一番最初の接続時には接続を続けるかどうか確認してくるので「yes」と入力します。

![terminal2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/c8bd53f2-b360-eead-981b-f24d8161b3ab.png)

続いてパスワードの入力が必要になるので初期パスワード「raspberry」と入力します。

![terminal3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/f4cc8510-f4ef-755a-acb3-9b1db46e14cd.png)

Raspberry Pi Zeroにログインできました。

###Raspberry Pi Zeroをインターネットに接続できるようにする
今の状態ではPCからRaspberry Pi Zeroにはアクセスできるのですが、Raspberry Pi Zeroからはインターネットにアクセスすることはできません。（Wifiをセットアップすれば可能ですが、今回は別の方法で接続します。）
Raspberry Pi Zeroをインターネットに接続するためにPCのネットワーク共有機能を使います。
PCの「ネットワークとインターネットの設定」を開きます。
![network01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/a3e24d98-fccd-bc24-5920-cdf5a5dccba1.png)
「アダプターのオプションを変更する」をクリックします。

![network02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/211a2a47-c364-6f13-7685-95f1fefea1da.png)
PC上のインターネットに接続しているアダプターのプロパティを開きます。

共有タブを選択し、「ネットワークの他のユーザーに、このコンピューターのインターネット接続をとおしての接続を許可する」にチェックを入れます。
![network03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/e089fb35-ace3-63d4-1d18-e2ddc4f9c17c.png)

「ホームネットワーク接続」が表示されている場合はRaspberry Pi Zeroを認識しているアダプター（上の図の場合は「イーサネット5」）を選択します。
「OK」をクリックして設定を終了します。
これでRaspberry Pi ZeroはPCを経由してインターネットに接続できるようになりました。

###raspi-configを使って設定
ターミナル上でRasberry Pi Zeroの設定を行います。

次のコマンドを入力します。

```
$ sudo raspi-config
```

![raspiconfig1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/9c1050ef-25c7-9170-a591-c82c469339b0.png)

5番目のメニューを選択します。

![raspiconfig2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/e321af28-d9df-f0eb-9844-18385d4da035.png)
「P1 Camera」を選択します。
![raspiconfig3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/0c051352-bcf3-c4a0-54fc-076ba6b52a2a.png)
「yes」を選んでカメラを有効にします。
![raspiconfig4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/5152dece-35fa-3bde-17df-aa601ee206b5.png)
「Ok」を選びます。
![raspiconfig5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/e74c01a4-6a14-979b-8951-33160589b596.png)
もう一度5番目のメニューを選び、続いて「P3 VNC」を選択します。
![raspiconfig6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/a98c63d0-a050-0a64-0a3a-aba1d027b58a.png)
「yes」を選択します。
![raspiconfig7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/e2593a4b-153d-30ba-6aa0-6a372844189d.png)
「Ok」を選びます。
![raspiconfig8.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/a3dceaa0-7383-49cc-c60d-73d75c4e3a8a.png)
次は7番目のメニューを選びます。
![raspiconfig9.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/7f03fe6d-bb26-6bf6-3d52-f9609c4cd9f8.png)
「A5 Resolution」を選びます。
![raspiconfig10.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/8e05a8c1-1504-dcc4-43a4-b5078c98535f.png)
VNC接続時の解像度を選択します。（筆者はDMT Mode 85を選びました。）
![raspiconfig11.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/dbeb868e-9d3c-5b4f-124e-83eaa72ed913.png)
「Ok」を選びます。
![raspiconfig12.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/62d07769-1d1f-e702-c593-14524dd7bffa.png)
最初のメニューに戻るので「finish」を選択します。
![raspiconfig13.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/7ff1e1a4-9290-1ad1-b022-4ef38dd9406c.png)
設定を反映するために再起動をします。「Yes」を選びます。

Raspberry Pii Zeroが再起動するので、SSH接続は切断されます。

###VNC Serverの設定
再びターミナルからRaspberry Pi Zeroに接続します。
VNC Serverの設定を変更します。次のファイルを編集します。
「/root/.vnc/config.d/vncserver-x11」

```
$ sudo nano /root/.vnc/config.d/vncserver-x11
```

ファイルの最後の行に「Authentication=VncAuth」と追加して保存します。

設定を反映するために一度リブートしておきます。
起動後ターミナルで接続しなおします。

次のコマンドでVNC接続のパスワードを設定します。

```
$ sudo vncpasswd -service
```

以上の設定でVNCを使ってデスクトップにアクセスできるようになりました。
お好きなVNCViewerで接続してください。
筆者は[RealVNC](https://www.realvnc.com/en/connect/download/viewer/)を使用しています。
![vncvewer.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/67f20b49-5631-2725-5b26-19a217e33d89.png)
![vncvewer2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/3f1501d5-9762-03e8-b510-1147fc4a0811.png)

###カメラの接続確認
次のコマンドでカメラが認識されているかどうか確認ができます。

```
$ vcgencmd get_camera
supported=1 detected=1
$
```
「supported=1 detected=1」と表示されたら正しく認識されています。「detected=0」の場合は接続がおかしい可能性があるのでケーブルがちゃんと接続されているか確認しましょう。

##プログラム
###ソフトウェアのアップデート
次のコマンドでソフトウェアのアップデートをしておきます。

```
$ sudo apt update
$ sudo apt upgrade
```
ソフトウェアのアップデートは時間がかかる場合があります。

###スワップファイルの拡張
初期のスワップファイルの設定は小さいのでサイズを変更します。
「/etc/dphys-swapfile」を編集します。

```
$ sudo nano /etc/dphys-swapfile
```
![swap01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/24c03f1e-f9f0-520c-f17a-16fde75cdbbe.png)
「CONF_SWAPSIZE=100」を「CONF_SWAPSIZE=2048」に変更して保存します。
設定を反映するために再起動しておきます。

###OpenCVのインストール
Python用のOpenCVパッケージのインストールを行います。
事前に必要なモジュールのインストールを行います。

```
$ sudo apt install libqt4-test libqtgui4 libjasper1 libatlas-base-dev libhdf5-dev
```

次にOpenCVのインストールですが、最新版はビルドパッケージでの配布のためインストールに時間がかかるため（時間がかかりすぎたので最後まで確認できていません。）ひとつ前のバージョンを指定してインストールします。

```
$ sudo pip3 install opencv-python==4.1.1.26
```

このバージョンはこのままだとエラーで利用できないので次の設定を行います。
/home/pi/.bashrcファイルの最後の行に次の文を追加します。

```
export LD_PRELOAD=/usr/lib/arm-linux-gnueabihf/libatomic.so.1
```

設定を反映させるために再起動します。

OpenCVがインストールできたか次のコマンドで確認します。
Python3をインタラクティブモードで起動します。

```python
>>> import cv2
>>> cv2.__version__
'4.1.1'
>>>
```
エラー表示がなければ正常にインストールされています。

###顔検出プログラム
OpenCVをインストールした際に顔検出を行うためのモジュールが用意されています。
それを使ってRasPiカメラに映った顔を検出するプログラムを試してみましょう。

ホームディレクトリ（/home/pi）に次のプログラムコードを入力して保存します。ファイル名は「face_detect.py」としています。

```python:face_detect.py
import numpy as np
import cv2

faceCascade=cv2.CascadeClassifier('/usr/local/lib/python3.7/dist-packages/cv2/data/haarcascade_frontalface_default.xml')

cap=cv2.VideoCapture(0)
cap.set(3,320)
cap.set(4,240)

while True:
    ret,img=cap.read()
    
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    
    faces=faceCascade.detectMultiScale(
        gray,scaleFactor=1.2,
        minNeighbors=5,
        minSize=(20,20)
    )
    
    for (x,y,w,h) in faces:
        cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
        roi_gray=gray[y:y+h,x:x+w]
        roi_color=img[y:y+h,x:x+w]
        
    cv2.imshow('video',img)
    
    k=cv2.waitKey(1) & 0xFF
    if k==ord('q'):
        break
    
cap.release()
cv2.destroyAllWindows()
```

保存したら、VNCでデスクトップに接続しましょう。
デスクトップ上でターミナルを開き、プログラムを実行します。

```
$ python3 face_detect.py
```

カメラ画像のウィンドウが開きますので、顔を映してみましょう。
顔を検出すると青色の矩形で囲まれます。
Raspberry Pi Zeroなので動作は速くはないですが、顔検出をすることができました。


以上　HeadLess接続のRaspberry Pi Zeroで顔検出を行うまでの手順でした。

VNCの設定ができてしまえば、いつでもHeadless環境で動作させることができますね。

##参考記事
[USB 1本とSDカードライタだけでできるUSB OTGを用いたRapsberry Pi Zero WH のセットアップ](https://qiita.com/Liesegang/items/dcdc669f80d1bf721c21)
[メモ:　RaspberryPi（Buster）にOpenCVをインストール](https://qiita.com/linyixian/items/02b21609067f694b4a73)