MarkDownがよくわかっていないので、あんまりきれいにはかけないかもです。
備忘録的に進めていければと思います。
①きっかけ
非GPS環境で飛ぶようなドローンを使ってSfM処理をしようとすると、必要なラップ率を満たすように画像を作成するのが難しいから。
②解決方法
特徴点の移動量を取得したすべてのフレームに対して計算して、各特徴点のマグニチュードを計算し、その平均値の変動量から計算すればいいのでは
③コーディング
がんばれ、ChatGPT君。
import cv2
import os
import numpy as np
from tqdm import tqdm
from multiprocessing import Process, cpu_count
def optical_flow_magnitude(gray1, gray2):
flow = cv2.calcOpticalFlowFarneback(gray1, gray2, None, 0.5, 3, 15, 3, 5, 1.2, 0)
mag, _ = cv2.cartToPolar(flow[..., 0], flow[..., 1])
return np.mean(mag)
def process_video(video_file, input_dir, output_dir, threshold):
video_path = os.path.join(input_dir, video_file)
video = cv2.VideoCapture(video_path)
frame_count = 0
ret, prev_frame = video.read()
prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)
cv2.imwrite(os.path.join(output_dir, f'frame{frame_count:04d}.png'), prev_frame)
with tqdm(desc=f"Processing {video_file}", total=int(video.get(cv2.CAP_PROP_FRAME_COUNT))) as pbar:
while video.isOpened():
ret, frame = video.read()
pbar.update(1)
if not ret:
break
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
mag = optical_flow_magnitude(prev_gray, gray)
if mag > threshold:
frame_count += 1
output_path = os.path.join(output_dir, f'frame{frame_count:04d}.png')
cv2.imwrite(output_path, frame)
prev_gray = gray
video.release()
def main():
input_dir = './input'
output_dir = './output'
threshold = 5
os.makedirs(output_dir, exist_ok=True)
video_files = [f for f in os.listdir(input_dir) if f.endswith('.MOV')]
processes = []
num_processes = min(cpu_count(), len(video_files))
for i in range(num_processes):
p = Process(target=process_video, args=(video_files[i], input_dir, output_dir, threshold))
p.start()
processes.append(p)
for p in processes:
p.join()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
カレントディレクトリのInputフォルダ内にmp4でデータを入れて、閾値を調整したら実行。