どうも~、IoT探検家のシンジです。
皆さん、交通量調査の仕事って見たことはありますか?


今回は、交通量調査の仕事をAIとラズパイを使って「交通量カウンター」を自作して自動化してみました。
用意したもの
・ラズパイ本体(Raspberry Pi 4)
・4インチのLCDモニター
・外付けのカメラ
・モバイルバッテリー
・キーボード
・microSDカード




屋外でラズパイを使いたいのでモバイルバッテリーを用意しました。ラズパイ4 モデルBには3A出力の電源が求められるので、それを満たすものを購入。(参考:Raspberry Piに最適なモバイルバッテリー)

自作の流れ
1)ラズパイの初期設定
2)ラズパイのタブレット化
3)物体追跡モデルを準備
4) 「交通量カウンター」完成
1)ラズパイの初期設定
まずは、Raspberry Pi(ラズベリー パイ)、略してラズパイという小型コンピュータを用意して、初期設定をします。
詳細は「[Python / 電子工作]ラズパイの初期設定をしてみた」を御覧ください。

2)ラズパイのタブレット化
次にLCDモニターを別途用意して、組み立ててラズパイのタブレット化します。
詳細は「[Python / 電子工作]ラズパイで手のひらサイズのタブレットを自作してみた」を御覧ください。

3)物体追跡モデルを準備
ここからは人間がおこなっている交通量調査の仕事をAIの物体追跡モデルで置き換えていきます。
まずは交通量調査でおこなっている作業内容を分類してみると、以下のように大きく分けることができました。
A) 走行している車やバイクなどの車両を見つける
B) 車両の台数をカウント
人は簡単にAとBをおこなっているように見えますが、Aでは車と他の物体(歩行者や自転車)を区別したり、Bでは複数の車が走行していても、1台1台を別々の車と認識してカウントしています。
そのため、人間の作業をAIの物体追跡モデルで置き換えるために、工程を次のように分類し直しました。
a) 車両を物体検出
b) 1台1台の車両に固有のIDを割り当て、移動を追跡して、台数をカウント
a) 車両を物体検出
まずは車両を物体検出できるようにします。
物体検出(Object Detection)
画像・映像中の物体に対して位置(矩形)とクラスを推定する技術
物体検出には多くのやり方があり、最近はSSD (Single Shot Multibox Detector)やFaster R-CNNのような精度の高いディープラーニングを利用したモデルが話題になっています。
ただ今回、物体検出するのに使うラズパイは、デスクトップ型のPCと比べると、計算処理に関わるメモリの量が小さいため、ディープラーニングのような容量の大きなモデルを利用すると、物体を検出するまでに時間が掛かってしまうことがあります。
そのため今回はディープラーニングのモデルは使わずに、OpenCVを使って複数の画像処理を組み合わせて、物体検出を実現してみました。(参考にしたサイト:Object Tracking with Opencv and Python ➡下の3枚の画像を引用)
背景オブジェクト作成

mog = cv2.createBackgroundSubtractorMOG()
道路を走る車両だけを検出するためには、画像に映る物体らしきものを見つける必要があり、まずはcreateBackgroundSubtractorMOGメソッドで背景オブジェクトを作成します。
輪郭検出

cnts = cv2.findContours(mog, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
背景オブジェクトに対して、findContoursメソッドで物体の輪郭を検出します。

for c in cnts:
if cv2.contourArea(c) > 100:
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(roi, (x, y), (x + w, y + h), (0, 255, 0), 3)
そして上のようなコードで、ある一定の大きさ以上の輪郭だけを残すことで車両だけを物体検出できました。
b) 1台1台の車両に固有のIDを割り当て、移動を追跡して、台数をカウント
物体追跡(Object Tracking)
映像中の移動物体を追跡する技術
次はa)で検出した車両の追跡です。時間が経過するごとに車両は場所を移動するので、それを捉える必要があります。
from scipy.spatial import distance as dist
D = dist.cdist(CentroidA, CentroidB)
そのためにこのようなコードで、時間ごとのフレーム内の車両の中心点の座標間の距離を測り、(同じ車両であれば移動距離は小さいはずなので)その距離が最小の車両を同一の車両と見なして、固有のIDを持つ配列に入れます。
そして、他の中心点と距離に関連がない車両は新規と見なして、配列に新規登録し、フレームから消えた車両は配列から除外。
y = [c[1] for c in to.centroids]
delta = centroid[1] - np.mean(y)
if delta < 0: self.direction = "up"
elif delta > 0:
self.direction = "down"
また、移動方向を中心点から計算することで、2車線の道路に対応できます。
これで物体追跡モデルの大枠が完成しました。


上の画像はYouTube上の道路を定点観測する動画ファイルに対して物体追跡モデルをラズパイで動かしてみたものです。(Upは緑の横線を下方向から上へ超えたらカウントされ、Downは上から下へ超えたらカウントされます。)
4) 「交通量カウンター」完成
それでは物体追跡モデルを実際の道路で使って「交通量カウンター」の実演をしてみましょう。

これらの部品を組み合わせて「交通量カウンター」を組み立てました~😊。

そして近所の横断歩道の欄干に設置して、カウント開始。


交通量調査の仕事をAIで自動化できました~。
振り返り
今回の「交通量カウンター」の自作の振り返りです。
・ラズパイのような計算処理に関わるメモリの量が小さいコンピュータを使って「交通量カウンター」を作る場合には、画像処理を工夫して物体追跡モデルを用意する必要がある
・今回、「交通量カウンター」を使ったのは7月の午前中の時間帯に2時間ほどでしたが、ラズパイ本体が高温になりました。終日利用する時にはヒートシンクやクーラーによる対策が必要になりそう…
・今回の「交通量カウンター」の自作にかかった時間は16時間ほどでした。
Youtubeで見る
コード
今回の実装で使ったコードはこちらにおいてあります。
https://github.com/01shinji/machinelearning/tree/master/traffic_counter
コメント
コメント一覧 (2件)
コメント失礼します
こちらのものを試してみたいのですが、ソースコードの公開は行っていないのでしょうか?
コメントありがとうございます。ソースコードですが今月中(2022年1月)に公開しようと思います。少しお待ちくださいませ~