Meanshift・Camshiftの理論
Meanshift・Camshiftはピクセルの密度最大の場所を追いかけるのが特徴です。
つまり、画像中に写る物体を発見・追跡するためのものになります。
Meanshiftのアルゴリズムは、下記の流れになります。
1、ある場所から探索窓が出発する(パラメーターで指定)
2、探索窓内の画素値の重心を計算する
3、探索窓の中心を重心に移す
4、2と3を繰り返す
これによって、ピクセル密度が最大の箇所を特定していきます。
Camshiftは探索窓が可変になるところが異なります。
注意点としては、1のパラメーター次第でアウトプットが異なります。
機械学習を嗜んでいる方であれば、局所解に陥る可能性があるといった表現が分かりやすいと思います。つまり、学習率みたいなものを指定していると思ってください。
import cv2
cap = cv2.VideoCapture('180607_A_101.mp4')
ret, frame = cap.read()
h, w, ch = frame.shape
rct = (600, 500, 200, 300) # 開始点パラメータ (x座標, y座標, 探索窓width, 探索窓height)
cv2.namedWindow('win', cv2.WINDOW_NORMAL)
cv2.resizeWindow('win', 1200, 800)
cri = (cv2.TERM_CRITERIA_COUNT | cv2.TERM_CRITERIA_EPS, 30, 1) # 収束条件(30回動いたらもしくは1ピクセルも動かなくなったら)
while(True):
threshhold = 100
ret, frame = cap.read()
if ret == False:
break
img_g = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
ret, img_bin = cv2.threshold(img_g, threshhold,255, cv2.THRESH_BINARY)
# ret, rct = cv2.meanShift(img_bin, rct, cri) # meanshift
ret, rct = cv2.CamShift(img_bin, rct, cri) # camshift
x, y, w, h = rct
frame = cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 3)
cv2.imshow('win', frame)
if cv2.waitKey(20) & 0xFF == ord('q'):
break
cv2.waitKey(0) & 0xFF
cv2.destroyAllWindows()
cv2.waitKey(1)
cap.release()
背景差分
背景差分の原理は簡単で、現在のフレームから背景フレームを差し引いて上げたものです。
そうすると、背景と異なるところだけを抽出できます。
import cv2
import numpy as np
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', 1200, 800)
cap = cv2.VideoCapture('video.mp4')
ret, frame = cap.read()
h, w, ch = frame.shape
frame_back = np.zeros((h, w, ch), dtype=np.float32)
while True:
ret, frame = cap.read()
if ret == False:
break
frame_diff = cv2.absdiff(frame.astype(np.float32), frame_back) # 初期時は元画像が表示
cv2.accumulateWeighted(frame, frame_back, 0.03) # 3%ずつ前の情報が入ってくる=>移動している部分が白っぽくなる
cv2.imshow('img', frame_diff.astype(np.uint8))
if cv2.waitKey(20) & 0xFF == ord('q'):
break
cv2.waitKey(0) & 0xFF
cv2.destroyAllWindows()
cv2.waitKey(1)
cap.release()
補足
パーティクルフィルター
パーティクルフィイルターとは、乱数を用いた状態推定法です。
どのように行っているかというと、
1、二次元の画像上に乱数を使って、n個のパーティクルをばらまく
2、パーティクルの尤度を計算(相関を見る)
3、リサンプリング(尤度に応じて選択=>乱数でn個のパーティクルを選び直す)
4、パーティクルの状態を更新(座標をランダムウォークさせる)