File size: 2,763 Bytes
a718a55
 
 
 
a72e046
3cad4d8
a718a55
 
 
a72e046
a718a55
757e5d5
3cad4d8
757e5d5
a72e046
 
 
757e5d5
 
a72e046
3cad4d8
 
 
a72e046
 
 
 
 
 
 
 
a718a55
 
 
 
 
a72e046
 
 
 
a718a55
 
 
a72e046
 
757e5d5
a72e046
 
 
a718a55
a72e046
a718a55
 
3cad4d8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a718a55
 
757e5d5
 
 
 
a718a55
 
 
757e5d5
3cad4d8
 
 
a718a55
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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  # fallback

    # 一時AVIファイルで書き出す
    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()

    # mp4へ変換
    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()