【Unit4 ブログリレー1日目】 こんにちは、Unit4(m3.comのサイトプロモーションを行うグループ)でエンジニアをしている岸田です。 業務ではポイント関連のシステムや医療従事者向けのアプリの開発を主に担当しています。趣味ではここ2年弱ほどゴルフに熱中しており、最近簡単めなコースで90台前半のスコアを出せるようになってきました。

ゴルフのスイングは数ミリのズレで大きく打球が変わり、スイング時に意識するポイントも人の感覚によって大きく変わってきます。今までの練習ではポイントに絞って取り組んできましたが、気にするべきポイントが増えてきて、ツールなしでの練習が大変になってきました。公開されている数多くのゴルフアプリは、標準的なスイングとの比較で総合点数を表示するような仕組みのものが多いです。自分の見たいスイングチェックをピンポイントでしてくれるものは、見つけられませんでした。
そのような経緯もあり、今回自分のためのゴルフアプリを作ることにしました。
スマホで撮ったスイング動画をサーバ側(GCP Cloud Functions / Python)に送ると、解析してフォームのフィードバックを返す——そんなアプリを作って、日々ゴルフスイングと一緒に改善しています。
この記事では、そのアプリを支える技術構成(React Native + Supabase + Cloud Functions)を軸に、動画解析まわりのライブラリ選定と、AIを用いた開発フローの高速化のための工夫点について紹介します。
- 作っているもの
- 全体アーキテクチャ
- 動画・スイング解析の実装(Cloud Functions / Python)
- 解析ライブラリの検討事項
- Claude Code を使った改善プロセス
- 現時点での学びと今後
- おわりに
- We are hiring!
作っているもの
スイング動画を撮って解析にかけると、フォームのフィードバックが返ってくるアプリです。解析結果は「見せ方」を機能ごとに変えていて、大きく次の構成になっています。
- 骨格・姿勢のオーバーレイ(基本機能): 検出した骨格を動画に重ねて表示します。まず自分のフォームを目で確認できることを土台にしています。 また、インパクト時とバックスイング時に当たるフレームを検出してすぐ表示できるようにしています。
- 過去のスイングとの比較: 過去のスイング等の任意の動画と並べて、フォームの変化を追えるようにしています。
- チェックリストによるクリア判定: 肩や腕の角度、テンポといったメトリクスに対して、あらかじめ設定したチェックリストの条件をクリアしているかを判定して見せます。
操作の流れはシンプルで、アプリ内で動画を撮影するか、端末に保存済みの動画を選んで解析にかけると、数十秒ほどで結果画面が表示されます。撮影とファイル選択のどちらにも対応しているので、その場で撮ったスイングも、あとから見返したい過去の動画も同じように解析にかけられます。
これらの機能は、次のセクションで紹介する MediaPipe による姿勢推定の結果を、それぞれの見せ方に加工して成り立っています。


全体アーキテクチャ
- クライアント: React Native(Android)
- 認証・データ: Supabase(Auth, Database(Postgres), RLS)
- 解析処理: GCP Cloud Functions(Python) ← 動画を受け取ってスイング解析する(HTTP 呼び出しでトリガ)
[React Native App] | 1. 認証・データ read/write +--------------------------> [Supabase (Auth / Postgres, RLS)] | | 2. HTTP 呼び出し(動画を送って解析リクエスト) +--------------------------> [Cloud Functions (Python / MediaPipe)] | | 3. スイング解析 | 4. 解析結果を返す v +<-------------------------- [結果(骨格・メトリクス)] | | 5. 結果を Supabase に保存 +--------------------------> [Supabase (Postgres, RLS)]
解析処理をオンデバイスではなくサーバ側に置いたのには、いくつか理由があります。
1つ目は、解析ロジックを Python で書きたかったことです。姿勢推定や数値処理まわりは Python のライブラリが充実していて、MediaPipe をはじめとした資産をそのまま活かせます。2つ目は、端末差と負荷を切り離したかったこと。解析をサーバに寄せておけば、端末ごとの性能差やバッテリー消費を気にせず、同じ処理結果を返せます。そして3つ目に、将来的にスイングのデータを収集・管理していくことを視野に入れていたためです。データが集まる場所をサーバ側に持っておくと、後からの拡張がしやすくなります。
トリガには Storage トリガではなく HTTP 呼び出しを選びました。アプリ側で「いつ解析するか」を制御でき、結果を待って数十秒後に結果画面へ遷移する、という流れを素直に組めるためです。
動画・スイング解析の実装(Cloud Functions / Python)
ここからは記事の中心である解析処理を見ていきます。アプリからの HTTP 呼び出しを受けて、Cloud Functions(Python)の内部では次の流れで処理を進めています。
- 動画を受け取る — スイング動画は HTTP リクエストのボディに含めて送られてきます。Functions 側ではそれを受け取り、後続の処理にかけます。
- スイング区間を切り出す — OpenCV で動画を扱い、動画全体をそのまま解析するのではなく、スイングをしている区間だけを切り出します。区間はアプリ側でユーザーに指定してもらう方式にしています。準備動作や撮影の前後には解析に不要な時間が含まれるため、指定された区間に絞ることで処理量を抑え、解析の精度も安定させています。
- 骨格を検出する — 切り出した区間の各フレームを MediaPipe にかけて骨格(姿勢)を検出します。ここでフレームごとの関節座標が得られます。
- メトリクスを計算する — 検出した関節座標をもとに、肩や腕の角度、スイングのテンポといったメトリクスを計算します。「作っているもの」で触れたチェックリスト判定や過去との比較は、このメトリクスを土台にしています。
- 結果を返す — 骨格の座標とメトリクスを結果としてまとめ、HTTP レスポンスとしてアプリに返します。アプリはこの結果を受け取って、オーバーレイや数値として画面に表示し、必要に応じて Supabase に保存します。
スイング区間だけを切り出すのは、この処理の中でも効いている工夫です。動画全体を無条件に解析すると、フレーム数の分だけ推論回数が増えて時間がかかります。解析対象を「スイングしている区間」に絞ることで、無駄な推論を減らしつつ、狙った動きに対して安定した結果を出せるようにしています。

解析ライブラリの検討事項
姿勢推定(骨格検出)には MediaPipe と OpenPose を比較検討し、現在は MediaPipe を採用しています。
前提として、このアプリはまだ初期段階です。だからこそ「まず動くものを、できるだけ小さいコスト(手間・お金・学習コスト)で形にする」ことを優先しました。この観点で見ると、両者の性格の違いがそのまま選定の決め手になりました。
| ライブラリ | セットアップ | CPU 推論 | スイング用途での精度 | 初期コスト |
|---|---|---|---|---|
| MediaPipe | 依存が軽く導入が楽 | GPU なしでも実用的 | 用途に対して十分 | 低い |
| OpenPose | ビルド・モデル配置の手間が大きめ | GPU 前提の色が濃い | 高精度だが用途にはオーバー気味 | 高め |
OpenPose は高精度な姿勢推定で実績のあるライブラリですが、その力を活かすには GPU を前提にした環境づくりが必要で、初期段階のアプリで CPU 実行の Cloud Functions に載せるには重さが目立ちました。
一方 MediaPipe は導入が手軽で、GPU のない Cloud Functions 上でも実用的な速度で動きました。スイングの骨格検出という用途に対しては精度も十分で、初期段階に求めていた「小さいコストでまず動かす」という要件にきれいに合いました。以上から、現時点では MediaPipe を採用しています。
なお、動画からフレームを取り出す処理には OpenCV を使っています。フレーム抽出そのものは OpenCV に任せ、取り出したフレームを MediaPipe に渡す、という役割分担です。
Claude Code を使った改善プロセス
このアプリの新機能の実装には、Claude Code を活用しています。個人開発は使える時間が限られるので、実装のスピードをどう上げるかは大きなテーマでした。
進め方としては、仕様をまとめて一気に投げるのではなく、小さく対話しながら進めるスタイルを取っています。作りたい機能を少しずつ相談し、実装してもらい、動かして確認する。この小さなサイクルを回すほうが、個人開発の手触りには合っていました。
なお、このアプリはクライアント(React Native)と解析サーバ(Python)の両方から成りますが、フロントエンドとバックエンドの両方に手を入れること自体は普段の開発でも自然にやっていることなので、個人開発でも同じように両側を行き来しながら進めています。
要望をアプリに溜めて、次の改善につなげる
伝え方には少し工夫をしています。アプリの機能の1つとして「要望を書き留める機能」を用意し、使っていて気になった点をそこに追記していきます。そして Claude Code には、その要望のテーブルを参照させて、溜まった内容から次の追加開発を進めてもらう、という流れにしています。
ねらいは、製品を使って気づいたことを、そのまま次の開発の入力にすることです。気になった点をその都度プロンプトに書き起こすのではなく、アプリの中に溜めておき、Claude Code にそこを参照させる。こうしておくと「使う → 気づく → 溜める → 実装してもらう」というサイクルが、アプリ自身の機能として自然に回ります。
まだテストによる自動チェックや優先順位づけまでは仕組み化できていませんが、フィードバックを溜めて開発に回す入口を作れたことは、個人開発の限られた時間で改善を続けるうえで確かに効いています。
現時点での学びと今後
個人開発でも、React Native でクライアントを作り、Cloud Functions(Python)に MediaPipe を載せて解析を回す、という構成でスイング解析を形にできました。 AI活用以前に自力でアプリを作っていた頃と比べて、開発スピードが桁違いに速くなっています。 技術選定については「初期段階だからこそ小さいコストで動かす」という軸で進めましたが、その判断は今のところ手触りとして正解だったと感じています。
今後やりたいことは主に次の4点です。
- 解析の精度・機能強化 — 手首などの細かい部位の検知やゴルフシャフト、ゴルフボールなどの物体検知に拡張させていきたい。
- 改善サイクルの自動化を進める — いまは要望を溜めて開発に回す入口を作った段階なので、テストによるチェックや優先順位づけ、中長期的なゴール設定などを含めて、改善の流れをもう一歩自動化していきたい。
- バックエンドを Firebase へ寄せる — このアプリはデータベースに Supabase を使うところから始め、その後に解析処理を GCP の Cloud Functions で組みました。結果としてバックエンドが Supabase と GCP に分かれているので、解析基盤と同じ GCP 系の Firebase に寄せて、構成の見通しを良くしていきたいと考えています。
- 技術の力でゴルフも上達する — この解析アプリの改善と一緒にスコアのほうも改善しスコア80台を目指したいです。
おわりに
スマホのスイング動画を、React Native + Supabase + Cloud Functions(Python / MediaPipe)という構成で解析するアプリを紹介しました。個人開発でも、技術選定の軸を決めて、必要な部分にサーバサイド解析を組み込めば、動画解析を軸にしたアプリを形にできます。
同じように「趣味を題材に何か作ってみたい」という方の参考になればうれしいです。
We are hiring!
エムスリーではエンジニアを絶賛募集中です! エムスリーでのプロダクト開発に興味がある方、ぜひカジュアル面談にご応募ください!