AI映像解析で車両の速度を自動算出すると異常値ばっかりで苦労した

2023/1/23追記：ストリーミング対応の新規記事を追加しました。24時間など長時間ストリーミングを安定受信して映像解析する苦労話を記載しています。最後の「関連記事」からご参照ください。

# サマリー
**・速度の算出結果がおかしい
・原因調査と対策
・距離マスクを詳細化したときの効果
・多方向からによる距離マスクの検証結果**

前回の記事「[YOLOXの映像解析で車両の速度をAIで算出して渋滞を判定するのに苦労した～その２：速度算出手法編](https://qiita.com/drafts/a86f20673df6b6536345)」で距離マスクの説明をして、斜めに移動する車両もY軸方向の移動距離のみで速度が算出できることを説明しました。
また「画面の端問題」「カルマンフィルタ問題」など、速度算出の際に異常値となる原因を見つけ出し、それらを排除して正確な速度算出ができるようにしました。

しかし実際にやってみるとそう甘くはなく、意外な原因で速度算出値がブレることが分かりました。
ここでは失敗した映像と成功した映像の比較を行い、最終的には度数分布で異常値を2%以下に抑え込みました。

また距離マスクが詳細になったときの効果や、一方向ではなく多方向に移動する車両に距離マスクが有効かどうかも検証した結果を記載します。

# 速度の算出結果がおかしい

で、実際に撮影した映像でテストしました。このような映像です。速度検出の対象は右側車線で、左側は除外しています（映像サイズは720p)。
![vlcsnap-2022-11-07-17h06m15s037.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/5902759d-5d15-4a32-c36c-651e3a139480.png)

距離マスクはシンプルにして、こんな感じで設定しています（白線の長さと間隔で指定）。
![距離マスクイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/f41c8857-9771-5db2-2787-4965b942032c.jpeg)

画面上部の黒い部分は、実際には除外対象です。
実際の距離マスクと車両の移動方向（青矢印）は以下となります。
![DSCN3489_720p_DisMask1031-3説明.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/cfe3298a-b263-49cb-29bd-06070118d0e8.jpeg)

これでテストしたところ、このような[結果映像（約30秒）](https://youtu.be/kIPL7LNceyY)となりました。30fpsで処理しており、有効な速度検出数は2547件です。

ところが車がスムースに移動するだけ（渋滞は発生していない）の映像なのに、時速20Km以下や時速70Km以上の異常値が散見されました。また急加速しているわけでもないのに、前フレームから倍のスピードになる場合もあります。
全車両(有効2547件)で確認したところ、度数分布は次のようになりました。

**実験１結果**
| 階級 | 件数 | 割合 |
|:-:|:-:|:-:|
|0Km  | 44 | **1.73%**  |
| 0-10Km/h  | 6  |**0.24%**|
| 11-20km/h  | 82  |3.22% |
| 21-30km/h  | 948  |37.22% |
| 31-40km/h  | 528 |20.73% |
| 41-50lm/h | 533 |20.93% |
| 51-60km/h  | 301 | 11.82% |
| 61-70km/h  | 36 | **1.41%** |
| 71-80km/h  | 61 | **2.39%** |
| 81-90km/h  | 6 | **0.24%** |
| 91-100km/h以上  | 1 | **0.04%** |
| 101-150km/h以上 | 1 | **0.04%** |

このうち、映像の感覚的には時速11km以上、60km以下というのが妥当なところです（一般道ですし）。よって10Km以下、61km以上を異常値として考えると、合計が201件あり異常率は6.09%でした。異常率が高すぎて泣けてきます・・・。

## なぜこんなに異常な速度が検出されたか？
結論から言うと、カメラが振動して映像が上下にブレていたのが問題でした。
[この映像（約30秒）](https://youtu.be/kIPL7LNceyY)のスライダを左右に移動していただくと、グラグラ画角が動くのが分かると思います。
撮影は歩道橋上にカメラを三脚で固定して行いましたが、中央付近は意外と振動に弱く歩行者が複数同時に歩いただけでかなり振動が発生したようです。

なぜ振動程度で速度異常が検出されるのか？
まずは車両ID=1のY軸方向の移動距離を見てみましょう。この算出では距離の移動をBOTTOM_LEFT（のY軸移動距離）で取ってます。

| フレーム数 | Y軸移動距離 | 時速 |
|:-:|:-:|:-:|
| 20 | 3 | 80.91 |
| 21 | 1 | 26.97 |
| 22 | 1 | 26.97 |
| 23 | 2 | 53.94 |
| 24 | 1 | 26.97 |
| 50 | 4 | 63.31 |
| 51 | 3 | 39.63 |
| 52 | 2 | 26.42 |
| 53 | 5 | 66.05 |
| 54 | 3 | 39.63 |

これからもお分かりの通り、24fまではカメラから遠い（つまり小さく映っている）ため、移動が1～2ピクセルの世界で、50fを超えても3～4ピクセルです。つまりカメラが数ピクセル分動いただけで、すぐに異常値で算出してしまいます。22⇒23fでいきなり速度が倍になっていますが、これも1ピクセルが瞬間的に2ピクセルになったために起こっています。カメラからの距離だけでなく、YOLOXによる検出のバウンディングボックスの「ゆらぎ」にも影響します。
なお20fが移動量3ピクセルで80.91km/hなのに対し、54fでは同じ移動量3ピクセルなのに、39.63km/hで算出されています。これは適用している距離マスクの場所が異なるためです。

## カメラがぶれていない映像でやり直し
再度、[カメラがぶれていない映像で検出をやり直しました（約1分45秒）](https://youtu.be/OQjf4Ju2X-M)結果は以下の通りです（総数は3864件）。また1フレーム・1ピクセル単位での目立つ誤差をなだめる（平滑化）するにはFPSを落とすのが最も良いため、今度は30fpsではなく15fpsで処理してみました（30fpsではリアルタイム処理できないため、実運用でも15fps以下となる）。
結果は以下の通りです。なお距離マスクは実験1と同じくシンプルな距離マスクを使っています。

**実験２結果**
| 階級 | 件数 | 割合 |
|:-:|:-:|:-:|
|0Km  | 12 | **0.31%**  |
| 0-10Km/h  | 6  |**0.16%**|
| 11-20km/h  | 550  |14.23% |
| 21-30km/h  | 1410  |36.49% |
| 31-40km/h  | 1083 |28.03% |
| 41-50lm/h | 589 |15.24% |
| 51-60km/h  | 188 | 4.87% |
| 61-70km/h  | 15 | **0.39%** |
| 71-80km/h  | 7 | **0.18%** |
| 81-90km/h  | 3 | **0.08%** |
| 91-100km/h以上  | 1 | **0.03%** |
| 101-150km/h以上 | 0 | **0.00%** |

10Km以下、61km以上を異常値として考えると、合計が42件あり異常率は1.14%とかなり小さくなりました。

# 距離マスクを詳細化したときの効果
今度は同じ1分41秒の映像で、距離マスクを詳細化したときの結果を比較してみましょう。
作成した距離マスクはこんな感じです。これは1メートル単位で色のを塗り分けています。
![距離マスクイメージ詳細.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/40b73ca0-0379-cfee-4eef-aef8df00482a.jpeg)
実際の距離マスクと車両の移動方向（青矢印）は以下となります。
![DSCN3489_720p_DisMask1031-2説明.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/5d3bf7bc-3867-741b-8bbe-9bdcf737db89.jpeg)

実験２と同じ映像で同じ15fpsで処理し、距離マスクだけが異なります。
結果は以下の通りです。結果映像は[こちら](https://youtu.be/Avh2OV2E5ME)です。

**実験３結果**
| 階級 | 件数 | 割合 |
|:-:|:-:|:-:|
|0Km  | 12 | **0.31%**  |
| 0-10Km/h  | 11 |**0.28%**|
| 11-20km/h  | 453  |11.72% |
| 21-30km/h  | 1465  |37.91% |
| 31-40km/h  | 1288 |33.33% |
| 41-50lm/h | 432 |11.18% |
| 51-60km/h  | 176 | 4.55% |
| 61-70km/h  | 13 | **0.34%** |
| 71-80km/h  | 12 | **0.31%** |
| 81-90km/h  | 2 | **0.05%** |
| 91-100km/h以上  | 0 | **0.00%** |
| 101-150km/h以上 | 0 | **0.00%** |

有効な速度検出は3864件で、10Km以下、61km以上を異常値として考えると、合計が50件あり異常率は1.29%と実験３と比較して0.15%アップしてしまいました。

ただ実験３と度数分布を比較してみると興味深いことが分かります。
![シンプル距離マスクと詳細比較グラフ（赤が詳細）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/6bab6463-f40c-6d23-ab00-e6e30099e1f5.png)

グラフは青が実験２，赤が実験３です。実験２と比較すると実験３は21km/h以上40km/h以下に集まっていることが分かります。映像的にも加速して順調に走り抜ける車両が多いため、グラフの山が狭く・高くなるのは良い結果であると言えます。

なお異常値が実験３と比べて0.15%高くなってしまった原因としては、カメラから遠い距離マスクが1本3ピクセルや4ピクセルで、さらに15fps処理のため時速10km以下が（実験３と比較すると）誤検出しやすかったため・・・と思われます（時速10km以下は実験３と比較して5件多い）。

# 多方向からによる距離マスクの検証結果

距離マスクは映像に対して一意で設定されますが、車両の移動方向が様々な場合にも対応できるか検証してみましょう。例えばこんな映像です。
![vlcsnap-2022-11-07-20h06m04s745.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/fec70da0-f971-d5ac-3dfc-6bd42e3665aa.png)

これは兼松サステック(株)のCCTVシステム事業部より提供していただいた映像で、ネットワークカメラ「QNO-6072R」で撮影したものです。映像は昼間ですが、雨天です。映像時間は2分30秒です。
設定した距離マスクは以下となります。
![QNO-6072_DayRain_720p_DistMask2説明.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/f420bd21-bd41-db25-5e03-562a6d8869e4.jpeg)
実際の距離マスクと車両の移動方向（青矢印）は以下となります。
![QNO-6072_DayRain_720p_DistMask2説明2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/b9efca07-c793-19af-d9f8-42181100cb31.jpeg)

交差点を撮影しているため、今回は信号待ちなどで停止することがあります（ずっと停車しているパトカーもある）。よって今回は時速0kmは異常値にはなりません。そこで61km/h以上を異常値として考えると、度数分布は次のようになります。[結果映像（2分33秒）](https://youtu.be/FSVRNgejx-k)はこちらです。

**実験４結果**
| 階級 | 件数 | 割合 |
|:-:|:-:|:-:|
|0Km  | 3201 | 41.77%  |
| 0-10Km/h  | 509 |6.64%|
| 11-20km/h  | 236  |3.08% |
| 21-30km/h  | 492 |6.42% |
| 31-40km/h  | 1129 |14.73% |
| 41-50lm/h | 1441 |18.80% |
| 51-60km/h  | 521 | 6.80% |
| 61-70km/h  | 95 | **1.24%** |
| 71-80km/h  | 17 | **0.22%** |
| 81-90km/h  | 10 | **0.13%** |
| 91-100km/h以上  | 5 | **0.07%** |
| 101-150km/h以上 | 8 | **0.10%** |

有効な速度検出は7664件で、61km以上を異常値として考えると、合計が135件あり異常率は1.76%となります。これまでの実験２～３と同じく異常率が2%以下なので問題ないと言えるでしょう。

# 関連記事
・[2023年：裏技公開！ AI映像解析で物体検出精度をあげる簡単テクニック](https://qiita.com/ComputerVision/items/1bb9861d0b55b0161818)
・[2023年：24時間以上ストリーミングさせるとトラブルばかりで苦労した](https://qiita.com/ComputerVision/items/26a72a3f83fcf6c5d0d1)
・[2022年：YOLOXの映像解析で車両の速度をAIで算出して渋滞を判定するのに苦労した～その１：リアルタイム処理編](https://qiita.com/ComputerVision/items/5283a0ebbb59d5a4cb8f)
・[2022年：YOLOXの映像解析で車両の速度をAIで算出して渋滞を判定するのに苦労した～その２：速度算出手法編](https://qiita.com/ComputerVision/items/a86f20673df6b6536345)