【MediaPipe × Streamlit】中心人物だけをマスクする動画処理アプリ

python

今回は、MediaPipeStreamlit を使って、動画内の「中心にいる人物だけをマスク表示する」アプリを作ってみました。mediapipeを利用したい動画があったとしても、複数人が映っていたり、背景がごちゃごちゃしている場合には、編集したくなる場合が多くなると思います。

今回作成したアプリは、ブラウザ上で動作する軽量アプリで、30秒以内の動画には限定されますが、アップロードすると、中心人物だけが表示された動画を自動生成します。


✅ 使用ツール&ライブラリ

  • フレームワーク:Streamlit
  • 人物検出AI:Google MediaPipe Pose
  • 処理フロー:動画 → フレームごとに人物検出 → マスク処理 → 動画生成

ライブラリ一覧

  • streamlit
  • mediapipe
  • opencv-python-headless
  • numpy
  • Pillow

✅ 環境構築

pip install streamlit mediapipe opencv-python-headless numpy pillow

ご自身のpython環境で実施する場合には、上記のパッケージのインストールが必要になります。

※ Streamlit Cloud 上でも動作確認済みです!

インターネット環境があれば、こちらのリンクからアプリを利用かのうです。その場合には環境構築などは不要です。

アプリリンク:https://centervideomask-582zpg8i3yeeb3rphyuswj.streamlit.app/


✅ アプリ概要

  1. 動画(30秒以内)をアップロード
  2. MediaPipeで人物検出
  3. 中心に最も近い人物の領域を一回り大きくマスク
  4. 処理後、即ダウンロード可能!

基本的に、中心の人物以外を消したい動画を30秒以内に編集してアップロードするだけなので、非常に簡単です。


✅ コード全文(Streamlitアプリ)

こちらがコードの中身です。ご自身のローカル環境で実施する場合には、こちらのpythonコードをコピペすれば利用可能です。

import streamlit as st
import cv2
import numpy as np
import tempfile
import os
import mediapipe as mp

st.title("Center Person Extractor using MediaPipe (Videos up to 30 seconds)")

@st.cache_resource
def load_pose_model():
    mp_pose = mp.solutions.pose
    return mp_pose.Pose(static_image_mode=False, min_detection_confidence=0.5)

pose = load_pose_model()

video_file = st.file_uploader("Upload a video file", type=["mp4", "mov", "avi"])

if video_file:
    with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as temp_video:
        temp_video.write(video_file.read())
        video_path = temp_video.name

    cap = cv2.VideoCapture(video_path)
    fps = cap.get(cv2.CAP_PROP_FPS)
    total_frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)
    duration_sec = total_frames / fps
    w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

    if duration_sec > 30:
        st.error(f"❌ This video is {duration_sec:.1f} seconds long. Please upload a video shorter than 30 seconds.")
        cap.release()
    else:
        st.success(f"Video accepted! Duration: {duration_sec:.1f} seconds")

        output_path = os.path.join(tempfile.gettempdir(), "output_masked.mp4")
        out = cv2.VideoWriter(output_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h))

        progress_bar = st.progress(0)

        frame_idx = 0
        while True:
            ret, frame = cap.read()
            if not ret:
                break

            rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            results = pose.process(rgb_frame)

            mask = np.zeros(frame.shape[:2], dtype=np.uint8)

            if results.pose_landmarks:
                landmarks = results.pose_landmarks.landmark
                xs = [lm.x for lm in landmarks]
                ys = [lm.y for lm in landmarks]

                x_min = int(min(xs) * w)
                x_max = int(max(xs) * w)
                y_min = int(min(ys) * h)
                y_max = int(max(ys) * h)

                padding_x = int((x_max - x_min) * 0.1)
                padding_y = int((y_max - y_min) * 0.1)

                x_min_exp = max(0, x_min - padding_x)
                x_max_exp = min(w, x_max + padding_x)
                y_min_exp = max(0, y_min - padding_y)
                y_max_exp = min(h, y_max + padding_y)

                mask[y_min_exp:y_max_exp, x_min_exp:x_max_exp] = 255

            masked = cv2.bitwise_and(frame, frame, mask=mask)
            out.write(masked)

            frame_idx += 1
            progress_bar.progress(frame_idx / total_frames)

        cap.release()
        out.release()

        st.success("✅ Processing complete!")

        with open(output_path, "rb") as f:
            st.download_button("Download processed video", f, file_name="center_person_masked.mp4")

✅ 実行結果

  • アップロードした動画から、中心人物だけが表示された動画が自動生成されます。
  • 処理完了後は即ダウンロード可能。

✅ 注意点

  • MediaPipeは軽量ですが、フレーム数が多いと処理時間は長くなります(30秒以内推奨)。
  • 複数人が映る場合、最も中心に近い人物のみが対象です。
  • 検出精度は背景や姿勢によって変動する場合があります。

ご質問があればX(https://x.com/shimitaro_108)まで

コメント

タイトルとURLをコピーしました