| import cv2 |
| import mediapipe as mp |
| import tempfile |
| import gradio as gr |
| import os |
| import subprocess |
|
|
| mp_face_mesh = mp.solutions.face_mesh |
|
|
| def process_video_with_landmarks(video_path): |
| cap = cv2.VideoCapture(video_path) |
| if not cap.isOpened(): |
| return "❌ エラー: 動画ファイルを開けませんでした。形式を確認してください。" |
|
|
| width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) |
| height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) |
| fps = cap.get(cv2.CAP_PROP_FPS) |
| if fps == 0: |
| fps = 25 |
|
|
| |
| temp_avi = tempfile.NamedTemporaryFile(delete=False, suffix=".avi") |
| out = cv2.VideoWriter(temp_avi.name, cv2.VideoWriter_fourcc(*'XVID'), fps, (width, height)) |
|
|
| face_mesh = mp_face_mesh.FaceMesh( |
| static_image_mode=False, |
| max_num_faces=1, |
| refine_landmarks=True, |
| min_detection_confidence=0.5, |
| min_tracking_confidence=0.5 |
| ) |
|
|
| while cap.isOpened(): |
| ret, frame = cap.read() |
| if not ret: |
| break |
|
|
| rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) |
| results = face_mesh.process(rgb) |
|
|
| if results.multi_face_landmarks: |
| for face_landmarks in results.multi_face_landmarks: |
| for lm in face_landmarks.landmark: |
| x = int(lm.x * width) |
| y = int(lm.y * height) |
| cv2.circle(frame, (x, y), 1, (255, 0, 0), -1) |
|
|
| out.write(frame) |
|
|
| cap.release() |
| out.release() |
| face_mesh.close() |
|
|
| |
| temp_mp4 = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") |
| ffmpeg_cmd = [ |
| "ffmpeg", |
| "-y", |
| "-i", temp_avi.name, |
| "-vcodec", "libx264", |
| "-crf", "23", |
| "-preset", "medium", |
| temp_mp4.name |
| ] |
|
|
| try: |
| subprocess.run(ffmpeg_cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) |
| except subprocess.CalledProcessError: |
| return "❌ ffmpegによるmp4変換に失敗しました。" |
|
|
| return temp_mp4.name |
|
|
| def gradio_interface(video_file): |
| if isinstance(video_file, str) and os.path.isfile(video_file): |
| return process_video_with_landmarks(video_file) |
| else: |
| return "❌ 無効なファイルがアップロードされました。" |
|
|
| iface = gr.Interface( |
| fn=gradio_interface, |
| inputs=gr.Video(label="動画ファイルをアップロード"), |
| outputs=gr.File(label="再生可能なランドマーク付きmp4動画"), |
| title="Face Mesh ランドマーク付き動画出力(再生保証)", |
| description="動画に顔ランドマーク(青点)を描画し、再生互換性のあるmp4形式で出力します。" |
| ) |
|
|
| iface.launch() |
|
|