前回の記事では、OpenCV2の物体追跡APIの解析結果を、3つのWindowsに分けて、個別出力しました。
- オリジナルの画像に、特徴点の移動軌跡を重ねたフレームを、時系列で再生したウインドウ
- オリジナルの画像に、特徴点を小さな●で重ねた表示したフレームを、時系列で再生したウインドウ
- 特徴点の移動の軌跡ラインだけを、背景真っ黒な画面に表示させたものを、時系列で再生したウインドウ
今回は、Windowsが閉じた後に、後で繰り返し上記の1〜3を閲覧できるように、ファイル出力を行いました。
- 「1」の動画ファイル
- 「1」の静止画ファイル (総フレーム数個のファイル)
- 「2」の静止画ファイル (総フレーム数個のファイル)
- 「3」の静止画ファイル (総フレーム数個のファイル)
前回の記事に引き続いて、次の記事で公開されているコードを参考にしました。
実行画面
electron@diynoMacBook-Pro optical_flow % python3 optical_flow_save_files.py dance.mp4
次の動画ファイルを解析します。 :dance.mp4
フレームに追跡すべき特徴点が見つからなくなりました。
electron@diynoMacBook-Pro optical_flow %
出力ファイル
( 各フレームを処理した結果の静止画ファイル )
動画の総フレーム数分、ファイルが吐き出されます。
( オリジナルの画像に、特徴点を小さな●で重ねた表示したフレーム画像 )
( 拡大した1枚 )
( オリジナルの画像に、特徴点の移動軌跡を重ねたフレーム画像 )
( 拡大した1枚 )
( 特徴点の移動の軌跡ラインだけを、背景真っ黒な画面に表示させた画像 )
( 拡大した1枚 )
( 処理した結果の動画ファイル )
1ファイルが吐き出されます。
MacbookのQuickTimeでは再生できなかった。
動画については、fmtオブジェクトに格納する動画コーデックを色々試したが、いずれもうまく行かなかった。
この記事の最後を参照ください。
出力結果
electron@diynoMacBook-Pro optical_flow % ls result
feature_frames frame_with_trajectory_frames masked_frames
electron@diynoMacBook-Pro optical_flow %
electron@diynoMacBook-Pro optical_flow % ls result/feature_frames | wc -l
64
electron@diynoMacBook-Pro optical_flow %
electron@diynoMacBook-Pro optical_flow % ls result/frame_with_trajectory_frames | wc -l
64
electron@diynoMacBook-Pro optical_flow %
electron@diynoMacBook-Pro optical_flow % ls result/masked_frames | wc -l
64
electron@diynoMacBook-Pro optical_flow %
electron@diynoMacBook-Pro optical_flow % ls result/feature_frames | head
feature_frame0.jpeg
feature_frame1.jpeg
feature_frame10.jpeg
feature_frame11.jpeg
feature_frame15.jpeg
feature_frame16.jpeg
feature_frame17.jpeg
feature_frame18.jpeg
feature_frame19.jpeg
feature_frame20.jpeg
electron@diynoMacBook-Pro optical_flow %
electron@diynoMacBook-Pro optical_flow % ls result/frame_with_trajectory_frames | head
trajectory_frame0.jpeg
trajectory_frame1.jpeg
trajectory_frame10.jpeg
trajectory_frame11.jpeg
trajectory_frame15.jpeg
trajectory_frame16.jpeg
trajectory_frame17.jpeg
trajectory_frame18.jpeg
trajectory_frame19.jpeg
trajectory_frame20.jpeg
electron@diynoMacBook-Pro optical_flow %
electron@diynoMacBook-Pro optical_flow % ls result/masked_frames | head
masked_frame0.jpeg
masked_frame1.jpeg
masked_frame10.jpeg
masked_frame11.jpeg
masked_frame15.jpeg
masked_frame16.jpeg
masked_frame17.jpeg
masked_frame18.jpeg
masked_frame19.jpeg
masked_frame20.jpeg
electron@diynoMacBook-Pro optical_flow %
electron@diynoMacBook-Pro optical_flow % ls masked_frame_movie.mp4
masked_frame_movie.mp4
electron@diynoMacBook-Pro optical_flow %
実装コード
import numpy as np
import cv2, argparse, os
# 動画ファイル名をコマンドライン引数から受け取る
parser = argparse.ArgumentParser(description='') #
parser.add_argument('file_name')
args = parser.parse_args()
movie_file = args.file_name
print('次の動画ファイルを解析します。 :' + movie_file)
cap = cv2.VideoCapture(movie_file)
# Shi-Tomasiのコーナー検出パラメータ
feature_params = dict( maxCorners = 100,
qualityLevel = 0.3,
minDistance = 7,
blockSize = 7 )
# Lucas-Kanade法のパラメータ
lk_params = dict( winSize = (15,15),
maxLevel = 2,
criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
# ランダムに色を100個生成(値0~255の範囲で100行3列のランダムなndarrayを生成)
color = np.random.randint(0, 255, (100, 3))
# 最初のフレームの処理
end_flag, frame = cap.read()
gray_prev = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
feature_prev = cv2.goodFeaturesToTrack(gray_prev, mask = None, **feature_params)
mask = np.zeros_like(frame)
# 各フレームを解析した結果を動画として保存
# https://rikoubou.hatenablog.com/entry/2019/01/15/174751
frame_rate = 24.0 # フレームレート
size = (640, 480) # 動画の画面サイズ
fmt = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') # ファイル形式(ここではmp4)
masked_frame_writer = cv2.VideoWriter('masked_frame_movie.mp4', fmt, frame_rate, size) # ライター作成
# 各フレームを解析した結果を画像ファイルとして保存
# https://note.nkmk.me/python-makedirs-exist-ok/
os.makedirs('result/masked_frames')
os.makedirs('result/feature_frames')
os.makedirs('result/frame_with_trajectory_frames')
while(end_flag):
if feature_prev is None:
print("フレームに追跡すべき特徴点が見つかりませんでした。")
break
i = 1
# グレースケールに変換
gray_next = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# オプティカルフロー検出
feature_next, status, err = cv2.calcOpticalFlowPyrLK(gray_prev, gray_next, feature_prev, None, **lk_params)
# フレーム前後でトラックが成功した特徴点のみを
if feature_next is None:
print("フレームに追跡すべき特徴点が見つからなくなりました。")
break
# オプティカルフローを検出した特徴点を選別(0:検出せず、1:検出した)
good_prev = feature_prev[status == 1]
good_next = feature_next[status == 1]
# オプティカルフローを描画
for i, (next_point, prev_point) in enumerate(zip(good_next, good_prev)):
prev_x, prev_y = prev_point.ravel()
next_x, next_y = next_point.ravel()
mask = cv2.line(mask, (int(next_x), int(next_y)), (int(prev_x), int(prev_y)), color[i].tolist(), 2)
frame = cv2.circle(frame, (int(next_x), int(next_y)), 5, color[i].tolist(), -1)
img = cv2.add(frame, mask)
# ウィンドウに表示
cv2.imshow('window', img)
cv2.imshow('window2', frame)
cv2.imshow('window3', mask)
# ESCキー押下で終了
if cv2.waitKey(30) & 0xff == 27:
break
#動画ファイルに各フレームを出力
masked_frame_writer.write(mask) # 画像を1フレーム分として書き込み
#静止画ファイルとして各フレームを出力
#これはOK output_mask_file_name = 'masked_frame' + str(int(i)) + '.jpeg'
output_mask_file_name = 'result/masked_frames/masked_frame' + str(int(i)) + '.jpeg'
cv2.imwrite(output_mask_file_name, mask)
output_feature_file_name = 'result/feature_frames/feature_frame' + str(int(i)) + '.jpeg'
cv2.imwrite(output_feature_file_name, frame)
output_trajectory_file_name = 'result/frame_with_trajectory_frames/trajectory_frame' + str(int(i)) + '.jpeg'
cv2.imwrite(output_trajectory_file_name, img)
# 次のフレーム、ポイントの準備
gray_prev = gray_next.copy()
feature_prev = good_next.reshape(-1, 1, 2)
end_flag, frame = cap.read()
i += 1
# 終了処理
cv2.destroyAllWindows()
cap.release()
# 動画出力ファイルを閉じる
masked_frame_writer.release()
( 捕捉 )
動画ファイルの出力について
https://qiita.com/sey323/items/d7da4cee448ed5be8149
https://blog.mktia.com/save-video-with-opencv-python/
https://gist.github.com/takuma7/44f9ecb028ff00e2132e
上記の記事を参考に、
fourcc_int = int(cap.get(cv2.CAP_PROP_FOURCC))
print(fourcc_int)
したが、出力されたMP4ファイルは、MacbookのQuickTimeアプリで開なかった。
['a', 'v', 'c', '1']
と出力された。そこで、
fmt = cv2.VideoWriter_fourcc("avc1") # ファイル形式(ここではmp4)
fmt = cv2.VideoWriter_fourcc('A','V','C','1')
の両者を試してが、いずれも出力されたMP4ファイルは、MacbookのQuickTimeアプリで開なかった。
結論として、以下すべてうまく行かなかった。
fmt = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') # ファイル形式(ここではmp4)
fmt = cv2.VideoWriter_fourcc(*"mp4v") # ファイル形式(ここではmp4)
fmt = cv2.VideoWriter_fourcc("avc1") # ファイル形式(ここではmp4)
fmt = cv2.VideoWriter_fourcc('A','V','C','1')
以下の記事のように、OpenCV側で処理した後の加工済みフレーム画像をファイルに吐き出したのちに、フレーム総数分だけ吐き出された静止画像を、ffmpegで連結して動画ファイルに仕立てる方法が無難かもしれない。
今回は、3種類の加工後の各フレーム画像を、フォルダ(ディレクトリ)を分けて出力しているため、ffmpegを各フォルダに対して実行するだけでよい。