コードの解説
簡単にですが、OpenCVによる人数カウントのコードの解説を書きます。
コード自体はここから前編を御覧ください。
動画の設定
動画ソースは以下の箇所を変更します。ソースはファイルでも、httpでもrtspでも動作しました。あまりいないとは思いますが、もしEagle Eye NetworksのLiveをソースとして使用する場合には直接指定できなかったので、一度VLCで受取り、それを再度RTSPでストリーミングすることでうまくいきました。ご参考までに。
#Open video file
cap = cv2.VideoCapture('C:\\Work_Documents\\sandbox\\OpenCV\\with_EEN\\viaVLC\\camera0490_02.mp4')
#cap = cv2.VideoCapture('http://127.0.0.1:8080')
分解精度
カウントを行なうFPSを記載します。15とある場合には、15FPSに一度居場所をチェックすることになります。短すぎるとカウントが行われないことがあり、長すぎると他の人の位置と入れ違ったりすることがあります。
このフレームの長さが「直前の座標と現在の座標」の項目で使用される交差の判定を行なう線分の一つとなります。そのため短すぎると交差したかのチェックが行えず、長すぎると現在の対象が消えた時点で最も近い全く別の点との線分を作成してしまうので、これもまた注意が必要です。
fps = 15 #int(cap.get(5)+4)
print 'Current FPS is ' + str(fps)
移動体検出用のアルゴリズム
今回は移動体検出用のアルゴリズムはBackground SubtractorのKNN版を使用しました。もちろんMOG2のほうがスコアがいいことがありますので、照明環境や背景、人物のコントラスト、影の発生具合に応じて変えて頂いたほうがいいと思います。個人的にはライブで長時間カウントするのであれば、GMGにしてみたいような気もします。
fgbg = cv2.createBackgroundSubtractorKNN(detectShadows = True) #Create the background substractor
直前の座標と現在の座標
ここが一番悩んだポイントで、かつ誰かいいアイデアが無いかなーと感じているポイントです。
とある線分を過去と現在の2点間で交差したかどうか、というのを今回のカウント方法に採用したのはいいのですが、直前の点をどうやって自分の点と判断するのか、の解が浮かびませんでした。
今は1判断フレーム前の全行列から、KNNでもっとも今の点から「近しいか」を判別して採用する方法にしています。ということは、誤ることも多いのかも・・・というのが今の一番の懸念です。
# find a nearest neighbour point
def serchNN(p0, ps):
L = np.array([])
for i in xrange(ps.shape[0]):
L = np.append(L,np.linalg.norm(ps[i]-p0))
return ps[np.argmin(L)]
凸包と矩形
現在の抽出オブジェクトから凸包を作成し、そこからオブジェクトを囲む輪郭を作成します。その後に輪郭の中心点を作成します。
# apply convexHull to the contour
def convHull(cnt):
epsilon = 0.1*cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
hull = cv2.convexHull(cnt, returnPoints = True)
return hull
# detect a centroid from a coutour
def centroidPL(cnt):
M = cv2.moments(cnt)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
return cx,cy
ループ処理
上述の関数などを、for c in contours:
のループ内で処理しています。処理している順番は、
- 現フレームが処理するフレームかを判断し
- 各輪郭の領域サイズを計算し
- 凸包を輪郭から作り
- 輪郭から矩形を作り
- 矩形から中心点を計算し
- 前フレームの行列データがあったら
- 前フレーム行列から最近傍の点を探し
- 前フレームと現フレーム間で線を引き
- 線分同士が交差しているかチェックし
- 物体のフローティングテキストを更新し
- 中心点を描画し
- 矩形か輪郭を描画し
- カウント数の表示文字を更新し
- 線分を描画し
- 上記をFrameウィンドウ、背景差分、輪郭の画像をそれぞれのウィンドウに表示し
- 現在の行列を前フレームの行列として置き換えて
1の処理に戻ります。
最後に
OpenCVでの人物カウントには色々とやりかたや手法があると思います。
このコードが皆さんのコード作成の手助けになれば幸いです。
そしていいコードができましたら、是非フィードバックをお願いします。