こんにちは、かずまなぶです(*’ω’*)
動画中の物体を追跡する方法を勉強しました。メモを貼っておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
# coding: utf-8 # In[ ]: #色検出:動画から色を抜き出す import cv2 import numpy as np capture=cv2.VideoCapture(r"C:\Users\omoiy\data\movie/mobility.mp4") while True: #ウィンドウサイズを小さくしておく(元画像が大きすぎる) cv2.namedWindow("img",cv2.WINDOW_NORMAL) cv2.resizeWindow("img",640,480) #1フレームだけ読み込む ret,frame=capture.read() if ret==False: #最終フレームなら抜ける break hsv=cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)#読み込んだ1フレームをBGRからHSV形式に変換する #黄色っぽい色を定義 lower=np.array([20,50,50])#Hue=20とすると実際は40になる upper=np.array([25,255,255]) frame_mask=cv2.inRange(hsv,lower,upper)#hsvと黄色の定義を渡す dst=cv2.bitwise_and(frame,frame,mask=frame_mask)#2値画像の論理積(共通する部分)を取り出す。mask黄色だけが抽出される #画像を表示する cv2.imshow("img",dst) if cv2.waitKey(10)==27: break cv2.destroyAllWindows() # オプティカルフロー : 動画中の特徴点を追跡する (1)特徴点を見つける (2)特徴点とその周りは同じ方向へ流れると仮定して フローベクトを求める フローベクトルを求める 特徴点の画素値I I(x,y,t)=I(x+⊿x,y+⊿y,t+⊿t) 右辺をテーラー展開して、1次の項までを採用すると I(x+⊿x,y+⊿y,t+⊿t)=I(x,y,t)[1+ (∂I/∂x)*⊿x + (∂I/∂y)*⊿y + (∂I/∂t)*⊿t] よって、元の式は I(x,y,t)=I(x,y,t)[1+ (∂I/∂x)*⊿x + (∂I/∂y)*⊿y + (∂I/∂t)*⊿t] 1=1+ (∂I/∂x)*⊿x + (∂I/∂y)*⊿y + (∂I/∂t)*⊿t (∂I/∂x)*⊿x + (∂I/∂y)*⊿y + (∂I/∂t)*⊿t=0 ここで偏微分を (∂I/∂x)=Ix (∂I/∂y)=Iy (∂I/∂t)=It とおくと I(x,y,t)=I(x,y,t)[1+ (Ix*⊿x) + (Iy*⊿y) + (It*⊿t)] なので 1=1+ (Ix*⊿x) + (Iy*⊿y) + (It*⊿t) (Ix*⊿x) + (Iy*⊿y) + (It*⊿t)=0 さらに両辺を⊿tで割ると (Ix*⊿x/⊿t) + (Iy*⊿y/⊿t) +It=0 ここで ⊿x/⊿t=u ⊿y/⊿t=v とおくと (Ix*u) + (Iy*v) +It=0 (Ix,Iy)*(u,v)+It=0 このベクトル(u,v)をフローベクトルという。 特徴点の周辺のフローベクトルと連立させて解く 参考URL:https://www.slideshare.net/hitoshinishimura75/lucas-kanade # In[ ]: import cv2 #動画サイズを小さくしておく cv2.namedWindow("img",cv2.WINDOW_NORMAL) cv2.resizeWindow("img",1200,800) #パラメータの設定 COUNT=500 # 500点 特徴点を検出する """ルーカス・カナデ法 画像ピラミッド:解像度を落とした画像を段階的に作って、軽くした状態で特徴点を分析する winSize:ウィンドウサイズ 探索窓の大きさ maxLevel:ピラミッドの階層の数 収束条件:最大反復回数 もしくは 値が動かなくなったら """ criterita=(cv2.TERM_CRITERIA_MAX_ITER|cv2.TERM_CRITERIA_EPS,20,0.03) lucas_kanade_params=dict(winSize=(10,10),maxLevel=4,criteria=criterita) #1フレームを読み込む capture=cv2.VideoCapture(r"C:\Users\omoiy\data\movie/Cosmos.mp4") ret,frame=capture.read() frame_pre=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)#グレースケール化して、一個前のフレームとして定義する while True: ret,frame=capture.read() if ret==False:#画像がなくなったらブレークする break frame_now=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)#グレースケール化した画像を現在フレームとする feature_pre=cv2.goodFeaturesToTrack(frame_pre,COUNT,0.001,5)#追いかけるべき特徴点を見つける コーナー検出精度、コーナー間の最低限の距離 if feature_pre is None:#特徴点がなかったら、再びwhile文の先頭に戻って、また次のフレームを読み込んでくる continue #うまく特徴点を見つけられたら feature_now,status,err=cv2.calcOpticalFlowPyrLK(frame_pre,frame_now,feature_pre,None,**lucas_kanade_params)#ルーカスカナデ本体 #描画する for i in range(COUNT): pre_x=feature_pre[i][0][0] pre_y=feature_pre[i][0][1] now_x=feature_now[i][0][0] now_y=feature_now[i][0][1] cv2.line(frame,(pre_x,pre_y),(now_x,now_y),(255,0,0),3) cv2.imshow("img",frame) frame_pre=frame_now.copy() if cv2.waitKey(10)==27: break cv2.destroyAllWindows() # MeanShift / CamShift ピクセル密度(画素値)が最大の場所へ向かっていく ①ある場所から探索窓が出発する(ユーザーが指定) ②探索窓内の画素値の重心を計算する ③探索窓の中心を重心に移す ②③を繰り返す CamShiftは窓の大きさが可変になる # In[ ]: import cv2 cap=cv2.VideoCapture(r"C:\Users\omoiy\data\movie/Cruse.mp4") ret,frame=cap.read() h,w,ch=frame.shape#動画サイズを抜き出す rct=(600,500,100,100)#探索窓の開始点x,y,窓の大きさ⊿x,⊿y cv2.namedWindow("win",cv2.WINDOW_NORMAL) #名前を付ける cv2.resizeWindow("win",1200,800)#動画の名前を指定して、動画サイズの変更 criteria=(cv2.TERM_CRITERIA_COUNT|cv2.TERM_CRITERIA_EPS,10,1) #反復回数の閾値(10回動いたら または 1ピクセルしか動かなくなったら) while True: threshold=100#二値化の閾値 ret,frame=cap.read()#まずは1フレームを読み込む if ret==False:#最後まで読み込んでいたらブレークで終わる break img_gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)#グレースケール化する ret,img_bin=cv2.threshold(img_gray,threshold,255,cv2.THRESH_BINARY)#グレースケールを二値化する ret,rct=cv2.CamShift(img_bin,rct,criteria)#二値化画像をmeanShift または CamShiftしてrct(四角)を得る x,y,w,h=rct#rct:四角の座標と大きさ frame=cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),3)#四角を書く #frame=cv2.rectangle(img_bin,(x,y),(x+w,y+h),(255,0,0),3)#四角を書く cv2.imshow("win",frame) # frame または img_bin if cv2.waitKey(10)==27: break cv2.destroyAllWindows() #背景差分 背景かそれ以外かを分離することができる 現在フレーム-背景フレーム=背景差分 # In[ ]: import cv2 import numpy as np cv2.namedWindow("img",cv2.WINDOW_NORMAL) cv2.resizeWindow("img",1200,800) cap=cv2.VideoCapture(r"C:\Users\omoiy\data\movie/Pepole.mp4") ret,frame=cap.read()#1フレームだけ読む h,w,ch=frame.shape frame_back=np.zeros((h,w,ch),dtype=np.float32)#float32に指定しないと差分をとれない while True: ret,frame=cap.read()#1フレームだけ読む 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(10)==27: break cv2.destroyAllWindows() # In[1]: #パーティクルフィルター import cv2 import numpy as np import random2 import likelihood as li cap=cv2.VideoCapture(r"C:\Users\omoiy\data\movie/Tram.mp4") ret,frame=cap.read() h,w=frame.shape[:2] np.random.seed(100) Np=500 px=np.zeros((Np),dtype=np.int64) py=np.zeros((Np),dtype=np.int64) lp=np.zeros((Np)) for i in range(Np): px[i]=int(np.random.uniform(0,w)) py[i]=int(np.random.uniform(0,h)) obj=[0,110,160] while True: ret,frame=cap.read() if ret==False: break lp=li.likelihood(frame,px,py,obj,Np,sigma2=0.001) pxnew=np.array(random2.choices(population=px,weights=lp,k=Np))+np.random.randint(-15,15,Np) pynew=np.array(random2.choices(population=py,weights=lp,k=Np))+np.random.randint(-15,15,Np) px=np.where(pxnew>w-1,w-1,pxnew) py=np.where(pynew>h-1,h-1,pynew) px=np.where(px<0,0,px) py=np.where(py<0,0,py) for i in range(Np): cv2.circle(frame,(px[i],py[i]),1,(0,255,0),1) cv2.imshow("img",frame) if cv2.waitKey(10)==27: break cv2.destroyAllWindows() |