diff --git a/output_posenet.py b/output_posenet.py index 55be065..a172b35 100644 --- a/output_posenet.py +++ b/output_posenet.py @@ -1,7 +1,9 @@ import os import re +import time import cv2 +import numpy as np from util.ears_ai import EarsAI @@ -37,22 +39,61 @@ key=lambda x: int(re.search(r"(\d+)", x).group(1)), ) + processing_times = [] + fps_list = [] + for image_file_name in png_files: print(f"Processing image: {image_file_name}") + # フレームを読み込み frame = cv2.imread(os.path.join(frames_dir, image_file_name)) if frame is None: continue + # 処理時間の計測開始 + start_time = time.time() + # PoseNetで骨格検出 pose_overlay_img, *_ = ears_ai.pose_detect(frame, None) + # 処理時間の計測終了 + end_time = time.time() + processing_time = end_time - start_time + processing_times.append(processing_time) + + # FPSの計算 + fps = 1.0 / processing_time + fps_list.append(fps) + + # FPSをフレームに描画 + fps_text = f"FPS: {fps:.1f}" + cv2.putText( + pose_overlay_img, + fps_text, + (10, 30), + cv2.FONT_HERSHEY_SIMPLEX, + 1, + (0, 255, 0), + 2, + ) + # 結果を保存 cv2.imwrite( os.path.join(output_dir, image_file_name), cv2.cvtColor(pose_overlay_img, cv2.COLOR_RGB2BGR), ) + # 統計情報の計算 + avg_fps = np.mean(fps_list) + avg_processing_time = np.mean(processing_times) + + print("\n処理統計:") + print(f"平均FPS: {avg_fps:.1f}") + print(f"平均推論時間: {avg_processing_time*1000:.1f}ms") + print(f"総フレーム数: {len(png_files)}") + + return avg_fps, avg_processing_time + def create_video_from_images(image_dir, output_path, fps=30): """画像シーケンスから動画を作成""" @@ -101,11 +142,16 @@ video_to_frames(video_path, frames_dir) print("2. Processing frames with PoseNet...") - process_frames_with_posenet(frames_dir, pose_frames_dir) + avg_fps, avg_processing_time = process_frames_with_posenet( + frames_dir, pose_frames_dir + ) print("3. Creating output video...") create_video_from_images(pose_frames_dir, output_video_path) + print("\n最終結果:") + print(f"平均FPS: {avg_fps:.1f}") + print(f"平均推論時間: {avg_processing_time*1000:.1f}ms") print("Processing complete!") diff --git a/video_fps_converter.py b/video_fps_converter.py new file mode 100644 index 0000000..92b0635 --- /dev/null +++ b/video_fps_converter.py @@ -0,0 +1,182 @@ +import argparse +import json +import os +import platform +import subprocess +from pathlib import Path + + +def get_ffmpeg_path(): + """FFmpegの実行ファイルのパスを取得する""" + # デフォルトのFFmpegパス + if platform.system() == "Windows": + # Windowsの場合、一般的なインストール場所を確認 + common_paths = [ + r"C:\Program Files\FFmpeg\bin\ffmpeg.exe", + r"C:\FFmpeg\bin\ffmpeg.exe", + os.path.join( + os.getenv("USERPROFILE"), "Downloads", "ffmpeg", "bin", "ffmpeg.exe" + ), + ] + for path in common_paths: + if os.path.exists(path): + return path + return "ffmpeg" # システムパスに設定されている場合はそのまま'ffmpeg'を返す + + +def get_ffprobe_path(ffmpeg_path: str = None) -> str: + """FFprobeの実行ファイルのパスを取得する""" + if ffmpeg_path: + # FFmpegのパスからFFprobeのパスを推測 + ffprobe_path = ffmpeg_path.replace("ffmpeg", "ffprobe") + if os.path.exists(ffprobe_path): + return ffprobe_path + return "ffprobe" # システムパスに設定されている場合 + + +def get_video_duration(input_path: str, ffmpeg_path: str = None) -> float: + """動画の長さを秒単位で取得""" + ffprobe_path = get_ffprobe_path(ffmpeg_path) + + # FFprobeの存在確認 + try: + subprocess.run([ffprobe_path, "-version"], capture_output=True, check=True) + except (subprocess.SubprocessError, FileNotFoundError): + raise RuntimeError( + "FFprobeが見つかりません。FFmpegが正しくインストールされているか確認してください。" + ) + + command = [ + ffprobe_path, + "-v", + "error", + "-show_entries", + "format=duration", + "-of", + "json", + input_path, + ] + + try: + result = subprocess.run(command, capture_output=True, text=True, check=True) + info = json.loads(result.stdout) + if "format" not in info or "duration" not in info["format"]: + raise ValueError("動画の長さ情報が取得できません") + return float(info["format"]["duration"]) + except subprocess.CalledProcessError as e: + print(f"FFprobeエラー出力: {e.stderr}") + raise RuntimeError(f"動画情報の取得に失敗しました: {e.stderr}") + except json.JSONDecodeError: + raise RuntimeError("動画情報のJSON解析に失敗しました") + + +def convert_video_fps( + input_path: str, + output_path: str, + target_fps: int = 30, + speed: float = 1.0, + target_duration: float = None, + ffmpeg_path: str = None, +) -> None: + """ + 動画のフレームレートと再生速度を変換する関数 + + Parameters: + input_path (str): 入力動画のパス + output_path (str): 出力動画のパス + target_fps (int): 目標のフレームレート(デフォルト: 30) + speed (float): 再生速度の倍率(デフォルト: 1.0、1未満で遅く、1より大きいと速く) + target_duration (float): 目標とする動画の長さ(秒)。指定すると--speedは無視されます + ffmpeg_path (str): FFmpegの実行ファイルのパス(省略可) + """ + if not Path(input_path).exists(): + raise FileNotFoundError(f"入力ファイルが見つかりません: {input_path}") + + ffmpeg_cmd = ffmpeg_path if ffmpeg_path else get_ffmpeg_path() + + # 目標時間が指定されている場合、speedを計算 + if target_duration is not None: + original_duration = get_video_duration(input_path, ffmpeg_cmd) + speed = original_duration / target_duration + print(f"元の長さ: {original_duration:.1f}秒") + print(f"目標時間に合わせた速度: {speed:.2f}倍") + + try: + # 速度調整用のフィルター設定 + # setptsフィルターで速度を調整(1/speed) + speed_filter = f"setpts={1/speed}*PTS" + + command = [ + ffmpeg_cmd, + "-i", + input_path, + "-fps_mode", + "cfr", + "-filter:v", + f"{speed_filter},fps={target_fps}", # 速度調整とFPS変換を連結 + "-c:v", + "libx264", + "-preset", + "medium", + "-crf", + "23", + "-filter:a", + f"atempo={speed}", # 音声の速度も調整 + "-y", + output_path, + ] + + process = subprocess.run( + command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True + ) + + if process.returncode != 0: + raise RuntimeError(f"FFmpegエラー: {process.stderr}") + + print(f"変換が完了しました。出力ファイル: {output_path}") + print(f"設定: FPS={target_fps}, 速度={speed:.2f}倍") + + except Exception as e: + print(f"エラーが発生しました: {str(e)}") + raise + + +def main(): + parser = argparse.ArgumentParser( + description="動画のフレームレートと再生速度を変換します" + ) + parser.add_argument("input", help="入力動画のパス") + parser.add_argument("output", help="出力動画のパス") + parser.add_argument( + "--fps", type=int, default=30, help="目標フレームレート(デフォルト: 30)" + ) + parser.add_argument( + "--speed", + type=float, + default=1.0, + help="再生速度の倍率(デフォルト: 1.0、1未満で遅く、1より大きいと速く)", + ) + parser.add_argument( + "--target-duration", + type=float, + help="目標とする動画の長さ(秒)。指定すると--speedは無視されます", + ) + parser.add_argument("--ffmpeg-path", help="FFmpegの実行ファイルのパス(省略可)") + + args = parser.parse_args() + + try: + convert_video_fps( + args.input, + args.output, + args.fps, + args.speed, + args.target_duration, + args.ffmpeg_path, + ) + except Exception as e: + print(f"プログラムの実行中にエラーが発生しました: {str(e)}") + + +if __name__ == "__main__": + main()