|
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() |
|
|