【ちょいプロ】Youtubeのテニスのサーブ動画で骨格抽出してみる

概要

2026年の1月からテニスのスクールに週1回で通い始めた私はテニスにドハマりして、今では週に2,3回テニスをするほどになっています。

テニスをする上で大事なことの一つに、フォームのキレイさがあります。綺麗なフォームでテニスができるというのは、筋肉の連動性を上手く使っていることとほぼ同義で、最小限の動きでパワーを出すことができます。

ただそこの習得が難しい

素人目線からすると、プロがどう動いていて自分はどこができていないのか捉えることが難しいです。

そこを少しでも見やすくなればいいなと思ったのが動機です。後付けで、最近のモデルはどこまで骨格抽出できそうなのかなというのも知りたくてやりました。

さて、今回はサーブに焦点を当てて試みました。また、Youtubeのリンクを指定することでその動画から骨格抽出してみるという感じにしましたので、実行環境さえあれば好きなYoutube動画を指定して骨格抽出できそうです。

事前準備

Geminiさんに方針を尋ねたら、「yt-dlpとopencv、mediapipeがいいよ!」と言われたのでそちらで実装しました。無料版のGeminiさんだと提示されたmediapipe周りのコードが古くて使えなかったので書き直しました。

ここで、yt-dlpとは何ぞや!mediapipeとは何ぞや!となったので簡単にまとめておきます。

  • yt-dlp:動画サイト(Youtubeをはじめとする様々なサイト)から動画を取得するツール
  • MediaPipe:Google開発の、人工知能と機械学習の手法を扱えるフレームワーク

MediaPipeについて詳しく知りたい方はこちらを参照ください。LLMや画像、テキスト、音声と幅広く対応しているみたいです。すごい!

使用環境・ライブラリ

  • python == 3.10.14
  • numpy == 2.2.5
  • opencv-python == 4.13.0
  • mediapipe==0.10.35
  • yt-dlp==2026.3.17

インストール方法

pythonの環境はできているものとして、各ライブラリのインストール方法は以下です。

python -m pip install numpy opencv-python yt-dlp mediapipe

インストールされたか確認したい場合は以下のようなコマンドを実行してください。

ex ) numpyの場合

python -c "import numpy; print(numpy.__version__)"

MediaPipeのモデルをダウンロード

以下のリンクにアクセスしてモデルをダウンロードし、メイン関数で指定する必要があります。

参考リンク→ 姿勢ランドマーク検出ガイド

今回は以下の画像内にある、「Pose Landmarker (Lite)」のバージョン「最新」を使用しました。「最新」をクリックすると勝手にダウンロードがされるので、それを自分のコードで指定しやすい場所に格納しておいてください。

ソースコード

早速ですが、ソースコードに移りたいと思います。

作成した関数は一つだけになりました。あとはメイン関数でぶん回しております。

import部分

import cv2
import numpy as np
import mediapipe as mp
from mediapipe.tasks.python.vision import drawing_utils
from mediapipe.tasks.python.vision import drawing_styles
from mediapipe.tasks.python import vision
import yt_dlp

1. 画像に検出されたランドマークを描画する関数

def draw_landmarks_on_image(rgb_image, detection_result):
  pose_landmarks_list = detection_result.pose_landmarks
  annotated_image = np.copy(rgb_image)

  pose_landmark_style = drawing_styles.get_default_pose_landmarks_style()
  pose_connection_style = drawing_utils.DrawingSpec(color=(0, 255, 0), thickness=2)

  for pose_landmarks in pose_landmarks_list:
    drawing_utils.draw_landmarks(
        image=annotated_image,
        landmark_list=pose_landmarks,
        connections=vision.PoseLandmarksConnections.POSE_LANDMARKS,
        landmark_drawing_spec=pose_landmark_style,
        connection_drawing_spec=pose_connection_style)

  return annotated_image

こちらに関しては、サンプルコードをそのまま持ってきました。サンプルコードはこちら

draw_landmarksというメソッドで描画できるみたいですね。あとはオプションみたいなところです。

2. メイン関数

def main():
    BaseOptions = mp.tasks.BaseOptions
    PoseLandmarker = mp.tasks.vision.PoseLandmarker
    PoseLandmarkerOptions = mp.tasks.vision.PoseLandmarkerOptions
    VisionRunningMode = mp.tasks.vision.RunningMode

    model_path = 'pose_landmarker_lite.task'
    options = PoseLandmarkerOptions(
        base_options=BaseOptions(model_asset_path=model_path),
        running_mode=VisionRunningMode.IMAGE)
    detector = vision.PoseLandmarker.create_from_options(options)

    video_url = "https://youtu.be/xxxxxxxx"  # YoutubeのURLを指定してください。

    ydl_opts = {
        'format': 'best[ext=mp4]',  # MP4形式のベスト画質を取得
        'quiet': True
    }

    with yt_dlp.YoutubeDL(ydl_opts) as ydl:
        info = ydl.extract_info(video_url, download=False)
        video_stream_url = info['url']  # 動画ストリームの直接URL

    # OpenCVで動画ストリームを開く
    cap = cv2.VideoCapture(video_stream_url)
    cv2.namedWindow('Window', cv2.WINDOW_NORMAL)

    if not cap.isOpened():
        print("動画を開けませんでした。")
        exit()

    while cap.isOpened():
        success, frame = cap.read()
        if not success:
            print("動画の終わりに達したか、フレームを読み込めませんでした。")
            break

        # MediaPipe用にBGRからRGBに変換
        mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data = frame)
        detection_result = detector.detect(mp_image)

        annotated_image = draw_landmarks_on_image(frame, detection_result)
        # 画面に表示
        cv2.imshow('YouTube Pose Estimation', annotated_image)

        # 'q' キーを押すと終了
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    # 後処理
    cap.release()
    cv2.destroyAllWindows()

yt-dlpで動画を取得して、毎フレームで骨格抽出と描画し表示させているプログラムになりました。

動作確認

サンプルにはチャンネル名「テニス映像館とicooyテニス個別レッスンアカデミー」様の「R. Federer Serve in Slow Motion」を使用させていただきました。

プログラムを実行すると以下のようなウィンドウが表示されます。ローカルには保存されず、そこで表示されるだけなのでご注意を。

骨格抽出結果画像
骨格抽出結果画像

なかなかにいい感じに骨格抽出できていそうですが、サーブを打つ直前になると大分検出位置がブレてしまっていますね。また、この動画からはわかりませんが、このMediaPipeのモデルでは検出できる人は1人まででした。複数人映っている場合、検出がさらにブレてしまいます(片方の人ともう片方の人を行ったり来たりしてしまう)。

まとめ

今回は、YoutubeのURLを指定してあげるとその動画を取得して骨格抽出してもらうプログラムを作ってみました。

MediaPipeyt-dlpと初めて知ったツールもありましたので、今後使えそうだなと知識を得られました。

今回使用したLite版のモデルでは、骨格抽出が上手くいっている部分もありましたが改善が必要だなという印象でした。人だけを抽出もしくは目立たせたり、完全版のモデルを使用するなどいろいろ考えられそうです。

元々の目的だった、テニスの上達に使えるかと言われれば........となりますね( ´艸`)

今回のちょいプロは以上です。ではではまた別の記事で!

参考文献

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です