RaspberryPi 4B でZoneMinderを使用する Part5…パフォーマンスの調整

#全体の目次
[目標の設定と環境の準備](https://qiita.com/BUBUBB/items/b7f3eb0e16a1c1a938b2)
[ZoneMinderのインストール](https://qiita.com/BUBUBB/items/bdf6df6b1d0ee1e14bc0)
[ZoneMinderの全般設定](https://qiita.com/BUBUBB/items/9de905615f389fd9ed50)
[カメラの登録](https://qiita.com/BUBUBB/items/f9415bc8bc526d0d84a5)
[パフォーマンスの調整](https://qiita.com/BUBUBB/items/9f98c91479a2ab6d8c0c)
[アクセスのブロック](https://qiita.com/BUBUBB/items/dbc7d59065484cd32476)
[外部からのアクセス](https://qiita.com/BUBUBB/items/99174603530094e5f746)
[ZmNinjyaの使用（未)]()



#このページでやること
Raspberry Pi では、複数のカメラで運用するのにはパフォーマンス的に無理がある。そこで、身の丈に合った設定を行い、現実的な運用方法を考える。

#目次
[温度とCPU使用率を観測する](#温度とcpu使用率を観測する)
[低バンド幅プロファイルの設定](#低バンド幅プロファイルの設定)
[カメラ設定の調整](#カメラ設定の調整)
　[Generalタブ](#generalタブ)
　[Sourceタブ](#Sourceタブ)
　[Generalタブ](#storageタブ)
　[Generalタブ](#timestampタブ)
　[Generalタブ](#buffersタブ)
[ゾーンの設定](#ゾーンの設定)
　[ゾーンの編集と追加](#ゾーンの編集と追加)
　[ゾーンプロパティの編集](#ゾーンプロパティの編集)
　[ゾーンの形の調整](#ゾーンの形の調整)
　[ゾーンプロパティ](#ゾーンプロパティ)
[最終的な状況](#最終的な状況)

#温度とCPU使用率を観測する

必要に応じてCPU使用率と温度を監視して調整に使用するため、次のようなスクリプトを作成する。

```
#!/bin/bash
echo ■温度：
vcgencmd measure_temp

echo ■CPU周波数：

cpufreq=`vcgencmd measure_clock arm | cut -d '=' -f 2`
echo $((cpufreq/1000000))MHz

echo ■CPU利用率：

function cpuuse() {
    cpu_user=$2
    cpu_nice=$3
    cpu_sys=$4
    cpu_idle=$5
    cpub_busy=$((cpu_user+cpu_nice+cpu_sys))
    cpub_all=$((cpub_busy+cpu_idle))

    cpu_user=${13}
    cpu_nice=${14}
    cpu_sys=${15}
    cpu_idle=${16}
    cpua_busy=$((cpu_user+cpu_nice+cpu_sys))
    cpua_all=$((cpua_busy+cpu_idle))

    cpu_use=$(((cpua_busy-cpub_busy)*100/(cpua_all-cpub_all)))

    return $cpu_use
}

procstatcpu=`cat /proc/stat | grep 'cpu'`
cpuab=`echo "$procstatcpu" | grep 'cpu '`
cpu0b=`echo "$procstatcpu" | grep 'cpu0'`
cpu1b=`echo "$procstatcpu" | grep 'cpu1'`
cpu2b=`echo "$procstatcpu" | grep 'cpu2'`
cpu3b=`echo "$procstatcpu" | grep 'cpu3'`
sleep 1
procstatcpu=`cat /proc/stat | grep 'cpu'`
cpuaa=`echo "$procstatcpu" | grep 'cpu '`
cpu0a=`echo "$procstatcpu" | grep 'cpu0'`
cpu1a=`echo "$procstatcpu" | grep 'cpu1'`
cpu2a=`echo "$procstatcpu" | grep 'cpu2'`
cpu3a=`echo "$procstatcpu" | grep 'cpu3'`

cpuuse $cpuab $cpuaa
cpu_usea=$?
cpuuse $cpu0b $cpu0a
cpu_use0=$?
cpuuse $cpu1b $cpu1a
cpu_use1=$?
cpuuse $cpu2b $cpu2a
cpu_use2=$?
cpuuse $cpu3b $cpu3a
cpu_use3=$?

echo $cpu_usea% [ $cpu_use0% $cpu_use1% $cpu_use2% $cpu_use3% ]
```

ファイルを作成したら、実行権限を与えて別ターミナルなどで実行する。定期的にCPU使用率や温度が表示されるので、調整時の参考とする。

```
$ chmod 777 cpu.sh
$ watch ./cpu.sh
■温度：
temp=50.5'C
■CPU周波数：
700MHz
■CPU利用率：
15% [ 5% 14% 29% 9% ]
```

#低バンド幅プロファイルの設定

メインウインドウの左上にある、[High][Midium][Low]の部分をクリック、バンド幅の設定ダイアログを [Low]にしておく。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2096509/1a5ee1c3-bc33-507d-d87e-d622f49f5dea.png" width=60%>

#カメラ設定の調整

Consoleにおいて、それぞれのカメラのIPアドレスをクリックすると、カメラ設定の調整が表示できる。それぞれについて満足いく性能になるように調整する。
この値は私の環境の設定値であり、認識の誤りや無意味な値がある。

##Generalタブ

|設定名|デフォルト|設定値|説明|
|:---|:---|:---|:---|
|Function|None|Modect|常時録画ではなく、イベント録画に設定する。SSDの使用量や負荷の減少を期待。ただ、容量などが許せば、常時録画（Record）も有効かもしれない。イベントの検出処理が不要になるので。|
|Maximum FPS|30.0|30.0|この値を減らすとぱFPSは低下するが負荷は減るようだ。しかし、有効なのはローカルカメラとjpeg/snapshotモードのipカメラに限定されるので設定は不要|
|Alarm Maximum FPS|30.0|30.0|アラーム発生時のMaximum FPS。設定不要|
|Refernce Image Blend %ge|6.25|カメラ毎|大きくすると進行が緩やかなイベントを検出しにくくなる。屋外などは天候が緩やかに変換するので、大きな値にするらしい。屋外が12.5、屋内が6.5がデフォルトになっているので、カメラの設置位置に従いこれを指定。|
|Alarm Reference Image Blend %ge|6.25|カメラ毎|詳細不明。|

##Sourceタブ

|設定名|デフォルト|設定値|説明|
|:---|:---|:---|:---|
|Source Path|---|RTSP|URLは、低解像度を使用する。低解像度(VGA程度）から高解像度（1080P)などになるとCPU負荷は4～5倍になる。運用時は、ZoneMinderで「だいたいの」様子を見たり録画を確認し、詳細な録画は各カメラのmicroSDに任せることにする。また、zoneMinderで使用したRTSPはほかのツールでも使用できる。RTSPでの情報参照は中国のサイトを経由しないので、リアルタイムストリーミングで高画質が必要な場合、別のツールと併用する。問題なのはCPU速度なので時間が解決してくれるかもしれない。|
|Method|TCP|UDP|UDPの方が高速。ただ、リアルタイム視聴時や、イベント録画で画面が乱れる場合にはTCPに変更する。また、カメラによっては、UDPを指定すると画像が出ないものもある。(ctronics）この場合はTCPにする|
|Target colorspace|32bit|32bit|パフォーマンスに無関係?|
|Capture Width/height|カメラ毎|カメラ毎|適切な値を設定する。値が間違えていると画像が出ずにエラーメッセージがわかりにくいこともある。VLCなどを使って画像の大きさを核にすること。（RaspberryPi 4B でZoneMinderを使用する Part4…カメラの登録>カメラの登録-マニュアルで登録するを参照）|
|Orientation|Normal|Normal|カメラ画像を反転したり鏡像にしたりする。ほとんどのIPカメラでカメラ側に同等の機能があるのでそちらを使用する|
|Deinterlacing|Disabled|none|none|カメラに合わせるが、IPカメラでは常にDisabledで良い|

##Storageタブ

|設定名|デフォルト|設定値|説明|
|:---|:---|:---|:---|
|Save JPEGS|Frames Only|Disabled|Jpegフレーム単位で画像を記録するかどうか。Disabledにした上で、Video Writerの設定をH264 Passthroughにするのが最も軽量な設定のようだ。|
|Video Writer||H264 Camera Passthrough|カメラの出力するH264をそのまま保存する。今のIPカメラはほとんどH264出力を持っているので、これで十分|
|Whether…|オン|オン|記録時に音声も保存するか|

#Timestampタブ

画像に含めるタイムスタンプ。変更不要。

#Buffersタブ

イベント録画時の設定。イベント発生前後のフレーム数を指定できる。このフレームを小さくして（デフォルトは０）しまうと、イベントが始まる瞬間が録画できないことがあった。（画面内で人が動いても、動き始めの瞬間が録画できない）そういう場合に、ここで調整する。

|設定名|デフォルト|設定値|説明|
|:---|:---|:---|:---|
|Image Buffer Size|20|200|録画用に200枚のリングバッファを用意する。この値は、後に出てくるPreEvent Image Countよりも大きくする必要がある。イベント発生時に、PreEvent Image Sizeに指定されたフレームだけ遡って映像として保存するため。メモリ量と相談だが、8GもあるRaspberry PIなので200枚ｘ6台くらいは楽勝|
|Warmup Frames|0|0|画像解析処理の起動時に、事前に用意するフレーム数。少なすぎると起動時に誤アラームが発生する。しかし、この値を多くしてもあまり誤警告は減らなかった。デフォルトのままにしておく|
|Pre Event Image Count|0|100|イベントが発生すると、100フレーム遡って録画を開始する。遡るときには、Image Buffer Sizeのリングバッファが使用される。Raspberry PIでは、パフォーマンスを維持するためフレーム数を減らして録画する必要があり、そのせいかイベントの発生が非常に遅いと感じた。そのため、この値を大きく取っている。|
|Post Event Image Count|5|100|イベントが終了（画面で動きがなくなった）あとに、どれくらい録画するかを指定する。この値にはImage Bufferは使用されない。速度を向上するため、ゾーン（動きを検知する領域）を小さくして、ここを通ったら録画開始、という形に指定するため、この値も大きくしてある。例えば、玄関前全体にゾーンを設定するのではなく、玄関に来る前に必ず通る場所に小さいゾーンを設定し、この値を大きくする、という運用がパフォーマンスでは有効|
|Stream Replay Image Buffer|0|0|リアルタイムビューで巻き戻し機能を使う時にこの値を指定する。自宅警備員のようにずっとモニターを見ているわけではないので、この機能は使用しない。値は０を指定する|
|Alarm Frame Count|1|1|アラームが発生するまでに必要な連続したフレーム数。誤検出の有無に影響するがパフォーマンスには関係がなさそうなのでデフォルトのままとする|


#Miscタブ

変更不要


#ゾーンの設定

##ゾーンの編集と追加
ZoneMinderでは、画像内の変化を見つけてイベントを発生させることが出来る。（各カメラのFunctionがModectになっているとイベントが発生すると自動的に録画が行われる)
モーションの検出はコストが高い処理なので検出範囲を調整してなるべく少ない範囲を検出対象にする。

Console画面でZoneの欄の数字をクリックする。

![30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2096509/5c4c79e7-0f6c-4feb-e77d-5e781c2671ba.png)

画面には現在のライブストリームを背景に、赤い枠（ゾーン）が１つ表示されている。
![31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2096509/51a43eb1-aef2-da3f-cd61-0321b365e298.png)

この赤い枠内をクリックすると、ゾーンの編集が出来る。また、[Add New Zone]をクリックすると、新しいゾーンを追加できる。

ゾーンそれぞれは、形（任意の多角形－四角形に限らない）や属性が指定できる。ゾーンを一つの複雑な形にするよりも、複数のゾーンを組み合わせ、その属性（モーションキャプチャの敏感さなど）を調整した方が良い。


##ゾーンプロパティの編集

ゾーンの編集画面は次のようになる。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2096509/6e860152-1ea5-bbbf-c97e-9ffe3795bc2f.png" width=50%>

###ゾーンの形の調整

赤い枠の四隅には、緑のマークがあり、自由に動かすことが出来る。また、画面下部のAction + - の部分を押すと、緑のマークを追加したり削除することが出来る。これでゾーンを任意の形、大きさに設定できる。

例えば、この画像では、画面の上部を少しあけて、カメラが出力する日時を検出対象から外している。ZoneMinderの検出ロジックでは、上下左右に動くものについて検出精度が高く、その場で形が変わるもの（時刻表示など）は検出されにくくなっている。そのため、日時部分を避けるのは必須ではないが、せめて検出範囲を少し減らしている。

ゾーンは、なるべく小さくすることで負荷が減り、誤検出も少なくできる。（ゼロにはできない）

###ゾーンプロパティ

|設定名|デフォルト|設定値|説明|
|:---|:---|:---|:---|
|Name|All|||
|Type|Active|Active|このゾーン内に画像の変化が見られるとトリガーが発生する。ほかの設定はマニアックなものが多いのであまり使用しない。Includsiveは、例えば生垣にInclusive、生垣の前の地面にActiveなどと指定する。すると、生垣が風邪で揺れてもイベントは発生しないが、生垣の動きとその手間の地面で小さな画像変化（足がちょっと見えるだけ）などが起こったときに、大きな画像変化としてトリガーが発生する。便利なケースもあるが指定すると重くなる。|
|Preset|---|---|ありがちな設定が、これ以降のパラメータに自動的に設定される。もし、不満が無ければfast-medium辺りに指定してほかの設定はお任せにしてしまうこともできる。|
|Units|Percent|Percent|これ以下の数字は％で指定する。この％は、画面全体ではなく、ゾーンのなかの比率|
|Alarm Color|255/0/0|255/0/0|ゾーンの色分け。大量のゾーンを作成するときには便利かもしれない。検出精度や速度には影響しない|
|Alarm Check Method|Blobs|AlarmedPixels|3段階のチェックステップ（AlermedPixels→FilteredPixel→Blobs）のうち、最初の１ステップだけを行う。当然AlermedPixelsだけをおこなう設定の方が高速。|
|Min/Max Pixel Threshold|25|||
|Filter Width/Height|3,3|||
|Zone Area|100|||
|Min/Max Alarmed Area|40,75|25,-|AlarmedPixelで使われるパラメータ。minの値が大きすぎると輝度の変化に鈍感になる。そのため白い壁の前を白いものが通ると検出されなくなる。今回は誤警告は多くても良いという設定なので、値を小さくしてある。maxの値は0が適切。|
|Min/Max Filtered Area|3,75||Alarm Check MethodがAlarmedPlixelの場合は設定不要。|
|Min/Max Blob Area|2,-||Alarm Check MethodがAlarmedPlixelの場合は設定不要。|
|Min/Max Blobs|1,-||Alarm Check MethodがAlarmedPlixelの場合は設定不要。|
|Overload Frame Ignore Count|0|0|この値は大きすぎる変化を無視する、と言う設定。証明が点灯したなどで画面全体に変化があったおときにその動作を無視する。今回は無視せず記録する。|
|Extend Alarm Frame Count|0||使用しない。 Preclusive Zonesを指定した時にのみ有効。|



#最終的な状況

最終的に、カメラ6台、Raspberry Pi 4B (8GBytes) を使用し、通常稼働時でCPUは10～20%、温度は室温(20度)＋25度程度で運用が可能だった。

MontageなどのUIを使用すると、CPUは20％程度まで高くなる。