Python OpenCV カメラ画像からオプティカルフローを取得して遊んでみました


Python + Opencv3.1 で カメラ画像からオプティカルフロー(移動ベクトル)を取得し、これをパラメータとして利用してちょっと遊んでみました。

移動ベクトルを取得してもじゃもじゃするコードは、OpenCV 3.1 のサンプルコード opt_flow.py を参考にして書いてみました。

■ オプティカルフローを利用して描画する。

def draw_flow(img, gray, flow, step=16):
    h, w = img.shape[:2]
    y, x = np.mgrid[step/2:h:step, step/2:w:step].reshape(2,-1).astype(int)
    fx, fy = flow[y,x].T
    lines = np.vstack([x, y, x+fx, y+fy]).T.reshape(-1, 2, 2)
    lines = np.int32(lines)

    # vis = np.zeros((img.shape[0], img.shape[1], 3), np.uint8)
    vis = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR) # グレー画像を背景に使用
    vis = 255 - vis # ネガ反転
    rad = int(step/2)

    i = 0 # ループカウンタ
    for (x1, y1), (x2, y2) in lines:
        pv = img[y1, x1]
        col = (int(pv[0]), int(pv[1]), int(pv[2]))
        r = rad - int(rad * abs(fx[i]) *.05) # ドットの半径を移動ベクトルの量に応じて小さくする
        cv2.circle(vis, (x1, y1), abs(r), col, -1)
        i+=1
    cv2.polylines(vis, lines, False, (255, 255, 0))
    return vis

■ カメラのフレームからオプティカルフローを取得して描画関数に渡して画像を表示する。

while(cap.isOpened()):
    # カメラのフレームをキャプチャ
    ret, frame = cap.read()
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    flow = cv2.calcOpticalFlowFarneback(prevgray, gray, None, 0.5, 3, 15, 3, 5, 1.2, 0)
    # flow[縦軸データ, 横軸データ, (x,y)]
    # print flow[0,0,:] # @ x,y ともに 0 番目のベクトルの大きさ, 角度(であってる?)
    prevgray = gray

    # プレビュー
    cv2.imshow('detect preview', draw_flow(frame, gray, flow, 16))

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
        cap.release()
     
     cv2.destroyAllWindows()

以前 ActionScript3 で同じようなことをやろうとしたときは途中で挫折したのですが(笑)、Python + OpenCV だと NumPy の配列操作が強力なこともあって短いコードで済むし簡単で楽しいですね。