ディープラーニングで映像から動かない歩行者を検出するのに苦労した

![ResultImage_Kokubunji_NoShadow30sec.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/cb7a784d-1d9e-350d-6d7e-ef9805d5f9a7.jpeg)
「歩行者の行動の可視化ってなに？映像中から歩行者見つけて枠で囲めばいいんじゃないの？」と、考えていた時期が私にもありました。しかし「映像を解析する」という観点で見た場合、それでは足りないとお客さんに教えてもらいました。
ここでは「映像（歩行者の行動を撮影したもの）を可視化する」というのにどのような要件が必要で、それをどう実現したかを解説します。とはいえトップ画像にすべて集約されているので、一目でお分かりかと思います。

#サマリー
**・可視化することで得たい結果
・歩行者の特性と可視化すべき特性
・動かない歩行者とその表現
・滞留マーカーの設定
・まとめ**

#可視化することで得たい結果
お客さんからよく言われるのが、「映像の解析結果を1枚の画像で表現してほしい。それを報告書に貼ると、説得力が段違いだから」です。
確かにCSVデータに数字がぐちゃぐちゃ並んでいると、よほど気合を入れないと読み方すらわからないですよね。よってウチでは可視化した情報を1枚の絵にまとめるようにしています。それがトップ画像ですね。
これは作業としては以下のような手順を踏んでいます。
**１）映像にある歩行者の動く方向など必要な可視化情報を設定する
２）映像をYOLOで物体検出して、トラッキングする
３）設定した可視化情報で描画を行う**
実際には、３）の描画は映像の全フレームに対して行います。結果として最終フレームがお客さんに提出すべき画像になるわけですが、映像の再生時間があまりに長いと映像がゴチャゴチャしてくるので、1分か5分毎とか(時間は歩行者数による)にリセットしてそれを複数提出するようにしています。なおトップ画像は30秒の結果です。ちなみに27分間の映像を解析すると、[こんな前衛絵画みたいな状態](https://camo.qiitausercontent.com/f3b764f93ac292b8951a5ea6c58e40a38f41fc9c/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3134303636332f62323639353439632d336661642d393731312d626638632d3965613633366435353634382e6a706567)になってしまいます。

#歩行者の特性と可視化すべき特性
歩行者の特性は以下の通りです。
**・出現場所と移動方向
・移動ルート
・移動スピード
・単独かグループか
・歩行者自身の属性（年齢・性別など）**
これらは言い換えると「誰が誰とどこから来てどれくらいのスピードでどこに向かったか？」ということですね。日本語にすると簡単ですが、解析は複雑な要素があり難易度が高いです。

このうちトップ画像で実現（可視化）しているのは、「移動ルート」です。この映像ではそもそも上下左右の4方向に移動先があり、歩行者は4方向のうちどれかに向かって歩いています。
移動方向の可視化については記事でも解説していますが、軌跡に色を4色付けて「GoLeftは緑」「GoRightはピンク」「GoUpは青」「GoDownは赤」となっています。XY軸みたいにざっくり2本の直交するカウンターラインを設定して、それぞれにGoLeft・GoRight、GoUp・GoDownという合計4方向の方向ラインを設定しています。軌跡をオフにして、カウンターラインと方向ラインの設定を分かりやすくしたのが下記の画像です。
![Test04軌跡サンプル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/0e375afa-dc82-7d25-b4c0-adaad8695a7b.png)

「じゃあ白いラインは何なんだよ？」と疑問に思われた方。素晴らしい注意力です。
白いラインは「この映像解析時間中にカウンターラインを越えなかった歩行者」です。つまり映像内での登場時間が短すぎて、移動する方向が検出できなかった歩行者になります。

また「やらなかった・できなかった」ですが、歩行者自身の属性はやりませんでした。個人情報的なアレですね。やろうと思えばYOLOに学習させれば物体検出の際に属性まで検出させることは可能と思います。
「単独かグループか」は今回はできませんでした。歩行者の量が多く、駅前という撮影場所の特性から「たまたま同じ方向（駅の改札）に向かって、近い距離で歩いている歩行者」が想定以上に多く、グルーピング判定の精度（信頼性）が悪かったからです。もし適度にばらけていて、目的地もばらばらであったら、同一方向に進む一定以下の距離の人たちをグループとしてみなすことができたかもしれません。なおPedesBladeでの実装はしていませんが、解析結果のCSVを使えば後処理でできそうな気もします。エリアごと（カメラから近い・遠い）で割り振る「グループ判定定数」を変えて、IDごとにどのグループに属するか判断する方法ですね。

あと「移動スピード」もやってないです。描画機能としては実装はしていますが、トップ画像ではオフにしています。理由としては、映像にパースがかかっているため、同じ歩行速度でも画面の奥（カメラから離れる）と移動ピクセル数が少なくなり、画面の手前（カメラに近い）と移動ピクセル数が多くなるからです。
ちなみに移動速度の違いは「描画する線の太さ」で速度を表しており（早いほど太い）、オンにすると以下のような画像になります。
![ResultImage_Kokubunji_NoShadow30sec.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/b240700a-7d5b-35da-24bc-207b571ba91b.jpeg)
![線の太さ詳細.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/252db635-b5c3-3a10-155b-f0b9739e387d.jpeg)
拡大するとこんな感じです。交差しているピンクの線の太さが違うのが分かりますね。
線内部のドットはフレームごとの歩行者の位置（バウンディングボックスの中心）で、その間隔が広い＝スピードが速い、ということになります。これも実装している機能ですが、線の太さが一定の細さになるとブチブチ切れているように見えるので、トップ画像ではこの機能は描画オフにしています。

#動かない歩行者とその表現

普通は歩いている人を歩行者と言いますが、何らかの理由で立ち止まっている歩行者もいます。答えから言っちゃうと、この映像の場合はお店の前で順番待ちをしている、案内板を一定時間見つめている、とかですね。これらは移動していない歩行者、として別途可視化する必要があります。というのも、軌跡だけだと立ち止まっているかどうかが分からないからですね。
そこで今回は**「滞留マーカー」**という概念を新しく作って、可視化することにしました。
![ResultImage_Kokubunji_NoShadow30sec滞留円番号付き.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/e7bc1c98-38a4-d661-0b48-c8d4fa8a441b.jpeg)

上の画像は映像をオフにして、後から描画したものだけを黒背景に置き、キャプションをつけたものです。
黄色い円が滞留マーカーと呼んでいるもので、特徴的に3か所ほどできています。映像と見比べると「なぜ立ち止まっているか」の理由が分かるのですが、滞留円(群)①は案内板を二人組が見ているため、滞留円②はお店の順番（入店）待ち、滞留円③は背番号の付いた服を着た人がたまたま荷物の整理？をしているためですね。
作図結果を見ると、歩行者は滞留マーカーがあるエリアを避けて移動している事が分かります。

歩行者が滞留する場合、代表的なものとして以下のパターンがあります。
**・移動して滞留してまた移動する（案内板を見て移動する）
・映像の最初から最後までずっと同じ場所に滞留している（人を待っている）
・基本的には同じ場所に滞留しつつも行動を伴う（ティッシュ配りなど）
・滞留しているが、じりじり移動する（お店の入店待ち）**

滞留を正しく可視化するには、これらの特徴もちゃんと表現したいところです。
なおこのシステムを開発するにあたり、あれこれ調査はしたのですが「立ち止まっている歩行者の表現やその名称」について、標準となりそうなものが見つからなかったので新しい言葉と概念を作ってしまいました。すでになんか便利な定義があるのであれば、教えていただければ幸いです。

#滞留マーカーの設定

滞留マーカーを設定しているパラメーターは以下の通りです。

    "STAY_COLOR_": "滞留マーカー色",
    "STAY_COLOR": "#FFFF00",
    "STAY_ALPHA_": "滞留マーカー透明度",
    "STAY_ALPHA": 0.1,
    "STAY_RAD_RATIO_": "滞留マーカー倍率",
    "STAY_RAD_RATIO": 10,
    "STAY_DIST_PER_STEP_": "1ステップ(FRAME_THINNING)ごとの移動距離の上限 ≒ 円の直径",
    "STAY_DIST_PER_STEP": 20,
    "STAY_MIN_STEPS_": "連続ステップ数(これ以上で描画)",
    "STAY_MIN_STEPS": 5,

色や透明度は別として、なぜ「滞留マーカー倍率」なんてのが存在するか説明します。
これは人間には身長や厚みがあるからです。終わり。
もう少し詳しく説明すると、軌跡はバウンディングボックスの中点をトラッキングすることで作図できますが、人間の大きさについては軌跡は考慮していません。
しかしながら「歩行者を阻害する影響の範囲」と考えると、滞留マーカーは人間の大きさも考慮する必要があります。点ではまずいわけですね。

そこでこのシステムでは
**１）移動距離の上限を設定する
２）１）が連続して続いた場合、STAY_MIN_STEPS以上のものを滞留として判定する
３）１）が滞留マーカー(円)の真の直径となる（移動距離が少ないバウンディングボックスの中心をすべて含む円の直径を規定する）
４）滞留マーカー倍率で滞留マーカーを拡大する**

ここで特に重要なのはSTAY_MIN_STEPSですね。
この設定をミスするとこんな感じになります。
![ResultImage_Kokubunji_NoShadow30sec.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/89001166-e4b0-7adf-4536-1a73dc8e3b5a.jpeg)
単なる歩行速度の緩急も滞留として描画してしてしまうため、本当の滞留が何かわからなくなります。

倍率についても調整が必要で、例えば倍率違いのサンプルは以下の通りです。
**１）倍率等倍**
![滞留円の直径検証_倍率1倍.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/eb41a2e3-63b8-c737-a8e0-f0b571bef5c5.png)

**２）倍率2倍**
![滞留円の直径検証_倍率2倍.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/e18b062e-8183-c905-70b2-c1cf502e7dc5.png)

１）の画像では軌跡上にステップごとのバウンディングボックスの中点の位置を出していますので、「間隔が狭い部分の連続5か所以上」が滞留マーカーに含まれているのがお分かりと思います（正確には間隔の狭い点が連続5か所以上あるものでそれらをすべて含む円を描画している）。
ただしそれだと数学的には正しいのですが、人間の大きさや厚みを考慮していないため、映像的には？となってしまいます。
滞留マーカーを強調したい場合は、パラメータをいじってこんな感じになります。
![ResultImage_Kokubunji_NoShadow30sec.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/4860e776-4045-7d1d-6cd0-726e236701e7.jpeg)


#まとめ
**・映像解析はCSV吐き出して終わりではない。どこまで何を可視化するかが重要。
・何をどこまで可視化するか？要件が増えると結果がゴチャゴチャしてくるので選別が必要
・歩行者は滞留する場合があり、その表現が重要
・そもそもトラッキングできないと、滞留は検出できない
・ここで滞留マーカーと呼んでいるものについて、良い定義があれば教えてください
・ソース販売しています。お気軽にお問い合わせください（3人月分くらいです）**

最後までお読みいただき、ありがとうございました。