どうも、月見(@Suzuka14144156)です。
今回の記事では、Pythonでオプティカルフローを実装する方法・やり方を解説したいと思います。
よって、この記事では、このような悩みをお持ちの方におすすめです。
- オプティカルフローとは?
- オプティカルフローはどのように使うの?
- Pythonでどのように実装するの?
参考にした本
created by Rinker
¥3,630
(2025/01/22 08:00:37時点 楽天市場調べ-詳細)
オプティカルフローとは?
- オプティカルフローとは、動画中の物体の動きをベクトルで表したもの
以下の画像は、円が画面左下から右上に動く様子を示したものです。
動線の軌跡をベクトルで表示しています。
これがオプティカルフローです。
Pythonでオプティカルフローを実装するには
OpenCVという画像処理のライブラリを使用します。
Pythonでオプティカルフローのための環境の構築
以下のコードをコマンドプロンプトで入力することで、OpenCVがインストール可能です。
pip install opencv-python
Pythonでオプティカルフローを試すための動画
以下のリンク先からダウンロード可能です。
opencv/samples/data/vtest.avi at master · opencv/opencv
Open Source Computer Vision Library. Contribute to opencv/opencv development by creating an account on GitHub.
ディレクトリ構成
pyコードとvtest.aviを同じフォルダに格納してください。
オプティカルフローのPythonのコード(1)
import numpy as np
import cv2
cap = cv2.VideoCapture('vtest.avi')
# params for ShiTomasi corner detection
feature_params = dict( maxCorners = 100,
qualityLevel = 0.3,
minDistance = 7,
blockSize = 7 )
# Parameters for lucas kanade optical flow
lk_params = dict( winSize = (15,15),
maxLevel = 2,
criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
# Create some random colors
color = np.random.randint(0,255,(100,3))
# Take first frame and find corners in it
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params)
# Create a mask image for drawing purposes
mask = np.zeros_like(old_frame)
while(1):
ret,frame = cap.read()
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# calculate optical flow
p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
# Select good points
good_new = p1[st==1]
good_old = p0[st==1]
# draw the tracks
for i,(new,old) in enumerate(zip(good_new,good_old)):
a,b = new.ravel()
c,d = old.ravel()
a,b,c,d =int(a),int(b),int(c),int(d)
mask = cv2.line(mask, (a,b),(c,d), color[i].tolist(), 2)
frame = cv2.circle(frame,(a,b),5,color[i].tolist(),-1)
img = cv2.add(frame,mask)
cv2.imshow('frame',img)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
# Now update the previous frame and previous points
old_gray = frame_gray.copy()
p0 = good_new.reshape(-1,1,2)
cv2.destroyAllWindows()
cap.release()
a,b,c,d =int(a),int(b),int(c),int(d)は、整数に変換しています。
Opencvのバージョンが、OpenCV(4.6.0)の場合は、整数に変換しないとエラーを返します。
チュートリアルでのコードは、この部分が抜けているのでエラーになります。
実行結果
人々の動線にラインが描かれます。
オプティカルフローのPythonのコード(2)
import cv2
import numpy as np
cap = cv2.VideoCapture("vtest.avi")
ret, frame1 = cap.read()
prvs = cv2.cvtColor(frame1,cv2.COLOR_BGR2GRAY)
hsv = np.zeros_like(frame1)
hsv[...,1] = 255
while(1):
ret, frame2 = cap.read()
next = cv2.cvtColor(frame2,cv2.COLOR_BGR2GRAY)
flow = cv2.calcOpticalFlowFarneback(prvs,next, None, 0.5, 3, 15, 3, 5, 1.2, 0)
mag, ang = cv2.cartToPolar(flow[...,0], flow[...,1])
hsv[...,0] = ang*180/np.pi/2
hsv[...,2] = cv2.normalize(mag,None,0,255,cv2.NORM_MINMAX)
rgb = cv2.cvtColor(hsv,cv2.COLOR_HSV2BGR)
cv2.imshow('frame2',rgb)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
elif k == ord('s'):
cv2.imwrite('opticalfb.png',frame2)
cv2.imwrite('opticalhsv.png',rgb)
prvs = next
cap.release()
cv2.destroyAllWindows()
実行結果
動画の動きのある部分のみを抽出することができます。
これを応用して、元画像の動きがある部分のみを抽出する方法を以下で解説します。
オプティカルフローのPythonのコード(3)
import cv2
import numpy as np
cap = cv2.VideoCapture('vtest.avi')
ret, frame1 = cap.read()
# 前のフレームとの差分をとるための変数を初期化
prvs = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)
hsv_mask = np.zeros_like(frame1)
while True:
ret, frame2 = cap.read()
if not ret:
break
# 現在のフレームをグレースケールに変換
next = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
# オプティカルフローを計算
flow = cv2.calcOpticalFlowFarneback(prvs, next, None, 0.5, 3, 15, 3, 5, 1.2, 0)
# オプティカルフローの角度と大きさを計算
mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])
# 色相の値を角度に、彩度の値を255に固定して、hsv画像を作成
hsv_mask[..., 0] = ang * 180 / np.pi / 2
hsv_mask[..., 1] = 255
hsv_mask[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)
hsv_mask = cv2.cvtColor(hsv_mask,cv2.COLOR_HSV2BGR)
# マスキング処理
mask = cv2.inRange(hsv_mask, np.array([0, 0, 0]), np.array([30, 50, 50]))
mask = 255 - mask
masked_frame = cv2.bitwise_and(frame2, frame2, mask=mask)
cv2.imshow('masked video', masked_frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 次のフレームの計算のために現在のフレームを保存
prvs = next
cap.release()
cv2.destroyAllWindows()
実行結果
人が動いている部分だけを抽出する動画(画像)を生成できます。
Pythonで画像処理の勉強方法
本
私は、以下の本で勉強しました。
かなり詳しく書かれており、とてもオススメの本です。
created by Rinker
¥3,630
(2025/01/22 08:00:37時点 楽天市場調べ-詳細)
Udemy
Udemyはオンライン口座です。
一度購入すれば、ずっと閲覧できるのでオススメです。
【Pythonで学ぶ】OpenCVでの画像処理入門
OpenCVの導入・画像の基礎知識からエッジの検出・特徴抽出、特徴追跡など様々な画像処理を紹介。実践力強化のため、パーティクルフィルターも原理を理解した後、自力で実装します。
まとめ
今回の記事では、Pythonでオプティカルフローを実装する方法・やり方を解説しました。
今回の記事は、以上です。
コメント