HappyShot

https://github.com/yashikota/happy-shot

Next.js

TypeScript

Python

GCP

Linux

動画を送ると、自動で最適な集合写真を保存・生成するサービス

こた

JIN

GEN1

推しアイデア

「動画をアップロードするだけで完璧な集合写真が自動で撮れる」 誰かが目をつむってしまうことを心配せずに、誰でも簡単にストレスフリーで完璧な集合写真を手に入れることができる。

作った背景

集合写真はシャッターのタイミングが難しく、誰かが目をつむったり動いたりして撮り直すことも。HappyShotは、そんな悩みを解決するために開発されました。

推し技術

AIをふんだんに活用した笑顔判定と顔方向検出で、動画をアップロードするだけで楽々ベストショットをゲット&シェアできます!

プロジェクト詳細

HappyShot

動画を送るだけで、最高のベストショットが手に入る!

デモURL: https://happy-shot.vercel.app/01jm64jeqy1aa45ej53hvr1rjf

※注意

AIの部分を同期処理でやっているので複数のリクエストがあるとパンクします😵 発表中は送らないようにお願いします(._.)

背景

集合写真を撮るときに、誰かが目をつむっていたり、動いてしまって何回も撮り直した経験はありませんか?また、タイマー撮影ではシャッターのタイミングが難しく、全員が自然な表情を作るのは難しくありませんか?この課題を解決するため、HappyShotを開発しました。

大まかな流れ

image

1. 動画をLINEもしくはサーバーにアップロード

2. 1フレーム毎に画像として切り出し

3. 画像に対してすべての人の顔の方向認識

4. 全員がカメラを向いていると保存対象A

5. 保存対象Aに対して表情認識

6. 7割が笑顔だと保存対象B

7. 保存対象A,Bから最終的に保存する画像を決定

image

機能

1. 顔の方向認識

目的 誰がカメラを見ているかを判別し、最適な撮影タイミングを見つける。

詳細 動画からフレームを抽出し、dlibで顔の向きを検出。顔の向きスコアを算出し、グラフ化して2回微分で頂点を検出。スコアが低いフレームや瞬きの可能性があるものを除外し、最終的に笑顔判定を行って最適なフレームを返す。

⬇️フレーム処理前

image

⬇️顔の向き検出結果

image

  1. 顔の向きを検出してスコア化 各フレームに写っている人物の顔を検出し、その顔の向きを評価する。顔の向きは、正面を100点としてスコアを付ける。顔の向き推定にはdlibを使用。
  2. 顔の向きスコアの平均を算出 そのフレームに写っている全ての人物の顔の向きスコアを平均し、その値をそのフレームのスコアとして記録。
  3. フレームに対してスコアの推移をグラフ化 全てのフレームについて、顔の向きスコアの推移をグラフ化する。しかし、最初のままだとグラフはギザギザしているため、平滑化処理を行って滑らかな曲線にする。
  4. グラフを2回微分して上に凸の頂点を検出 平滑化したグラフを2回微分し、上に凸の頂点(最もスコアが上がった点)を見つける。この頂点は注目すべきフレームを示している。
  5. フレームのスコアの低いものを除外 頂点周辺のフレームのうち、顔の向きの平均スコアが低いものから30%を除外。
  6. 目の比率を計算し、瞬きしていそうな画像を除外 目の比率を計算し、瞬きしている可能性のあるフレームを30%除外。

2. 表情解析

目的 笑顔やリラックスした自然な表情を自動で識別し、最も魅力的な瞬間を選定する。

詳細 顔検出や表情認識を行うライブラリとして、py-featを採用した。

# Detectorの初期化(GPU使用) detector = Detector( face_model="retinaface", landmark_model="mobilefacenet", au_model='svm', emotion_model="resmasknet", device="cuda" )

使用したモデル  顔検出: RetinaFace  特徴点検出: MobileFaceNet  表情認識: SVM  感情認識: ResMaskNet

流れ

  1. 顔を検出 顔の方向認識後、画像内で顔を検出する。検出された顔が次の処理対象となる。
  2. 特徴点検出 検出された顔に対して特徴点検出を行い、顔の重要な部分(目、鼻、口など)の位置を特定する。
  3. 表情認識 顔の特徴点をもとに、顔の表情認識を行う。これにより、顔の表情がどういった感情を表しているのかが分析される。
  4. 感情認識 表情認識の結果をもとに、顔の感情を認識する。感情は、「怒り」、「嫌悪」、「恐れ」、「幸せ」、「悲しみ」、「驚き」、「中性」に分類される。
  5. 「幸せ」と分類された顔を笑顔として判定 感情認識の結果、「幸せ」と分類された顔を笑顔として判定する。その顔が笑顔であると判断された場合、その顔は保存対象として選ばれる。
  6. 複数の顔が検出された場合の処理 画像内に複数の顔が検出された場合、その顔の70%以上が笑顔であれば、その画像を保存対象として選ぶ。

3. 最適なシーンの選択

目的 タイミングが完璧なシーンを選び出し、撮り直しの手間を省く。

詳細 顔の向きや表情を元に動画内の各フレームを詳細に分析し、最適なシーンを選択。全員がカメラを見ており、笑顔と想定される表情をしている瞬間を特定し、そのシーンを自動的に保存。これにより何度も撮影し直すことなく、ベストな瞬間を簡単に手に入れることができる。

4.LINEBOTを使用した動画のアップロードと通知

目的 ユーザーが手軽にHappyShotを利用できるようにするため、LINE Botを活用して動画のアップロードや処理完了の通知を行う。

詳細 LINE Botを活用することで、ユーザーは専用アプリを開かずにLINE上でHappyShotを利用できるようになる。ユーザーがLINEのトーク画面で動画を送信すると、Botが動画を受け取り、自動的にHappyShotのサーバーへアップロードを行う。HappyShotが動画から最適なシーンを抽出すると、LINE Botが処理完了の通知をLINEにて行う。image

工夫した点

フロントエンド

  • ユーザー体験向上: アップロード中は進捗バーと状態メッセージでユーザーにフィードバックを提供し、操作状況が一目で分かるようになっている。またグリッドギャラリーレイアウトにすることでPC/スマホ問わず使いやすいUIになるようにして、レスポンシブデザインで直感的なUIを提供できるように心がけた。
  • 効率的なファイルアップロード: XMLHttpRequestの進捗イベントを利用し、アップロード進捗をリアルタイムで追跡する仕組みを実装している。
  • 条件に応じたUI切り替え: 動画ファイルが選択されていない場合やアップロード中の場合、ボタンの状態や表示内容が適切に変化するなど、状況に応じたUI更新を行っている。
  • 再利用可能なコンポーネント: Header、Card、ButtonなどのUIコンポーネントを活用し、共通部分を簡潔かつ一貫性のあるデザインで再利用できるように工夫されている。
  • ルーティングのシンプルな実装: Next.jsのuseRouterを活用し、アップロード後の自動遷移やアルバム閲覧時のID入力による遷移をシンプルかつ直感的に実装している。
  • 利便性の向上: 生成されたprocessIdのコピー機能や、Web Share APIによる共有ボタンを実装し、ユーザーがコンテンツをすぐに友人や他のサービスと共有できるようにしている。
  • 新技術の採用: BunやBiomeといった新しめの技術スタックを採用した

バックエンド

  • APIサーバー fastAPIを用いて動画アップロード・フレーム処理を行うAPIサーバーを作成している。
  • 顔の向き検出システム このシステムの工夫は、顔の向きの検出から始まり、スコア化、平滑化、微分による頂点検出、瞬きや笑顔判定までの一連の流れにある。これにより、顔の向きや表情を効果的に評価し、最適なフレームを精度高く選定できる仕組みが実現されている。
  • 表情解析 このシステムでは、まずGPUが利用可能かを自動で判別し、可能ならGPUを、なければCPUを使うようにして処理の効率を最適化している。また、笑顔の検出に関しては、単に顔が笑っているかどうかを判断するのではなく、画像内のすべての顔の感情を解析し、"happiness" の割合が一定以上の場合にのみ保存する仕組みを取り入れている。さらに、画像データはメモリ上で直接処理し、不要なディスクI/Oを減らすことで、処理速度を向上させる工夫もしている。こうした工夫によって、環境に応じたパフォーマンスの最適化と精度の高い笑顔判定を実現している。
  • LINE BOTサーバー LINE BOTを動作させるためのサーバーを用意。ただしHTTPではLINE側が受け付けなかったためCloudflare Tunnelを使用してHTTPS化を行った。また段階的に通知を行うようにした。

インフラ

今回はGoogle CloudにGPUサーバーを構築して、そのうえでAIの運用とサーバーの運用を行った。

画像保存のためのオブジェクトストレージもセルフホストしたS3互換のMinioを採用している。

またこれらのクラウド基盤をCoolifyというVercel AlternativeなOSSで構築することでセルフホストの楽しさとDXを両立した技術スタックになっている。

また、画像配信のためのサーバーも当初はGoogle Cloudでやるつもりだったが、HTTPとHTTPSの混合になりエラーになったため、急遽別の手段が求められた。

最初は愚直にCloud Runでやろうと思ったが、さくらインターネットが現在ベータ版を公開しているAppRunが無料で使えることを思い出し良い機会だと思いトライしてみた。

結果としてCloud Runを触ったことがある人なら迷うことなくスムーズにデプロイまでできてDXが良かった。

CI/CD

ハッカソンいえども汚いコードは自分の首を絞めることになるので、GitHub Actionsを活用したCIとVercelでのCDを行った。

CIはフロントエンド、バックエンド両方でlintとformatを行い不一致があれば落とすようになっている。

このCIもフロントエンドではBiomeを、バックエンドではruffを採用することでよくあるCI待ちを減らした運用を心掛けた。

また、フロントのCDではVercelを活用したデプロイを行うことで迅速な開発が行えた。

技術構成

image

フロントエンド

ランタイム:Bun フレームワーク:Next.js UIライブラリ:Shadcn/ui デプロイ先:Vercel ライブラリ: react-image-grid-gallery

ストレージサーバー

CoolifyでMinioを自前デプロイ

クラウドサービスを使う手もあったが、セルフホストの経験も持っていたほうがよいだろうということで、せっかくのハッカソンなので構築した。 サクラのクラウド AppRunを用いて画像提出&配信サーバーを構築

LINE BOT

誰もLINE BOTの経験はなかったが、せっかくのハッカソンなのでやろうということで0時を超えたところから挑戦してみた。

途中から方針転換を行い動画をアップロードする形にしたが、単にWebアプリケーションだけだと処理が長いためいつ終わったのかがわからないため通知ができるようなプラットフォームにも展開することを決めた。

LINEにて機能を提供することにより老若男女幅広く使われるアプリケーションにすることができると思われる。

https://lin.ee/m88Js2h

展望

  • 今回は集合写真というシチュエーションで作成したが、今後はより汎用的、抽象的な課題にも対応できるようなプロダクトにしていきたい
    • 例えばイルカショーの動画からベストな瞬間を抜き出したり、ドライブレコーダーの映像から絶景の瞬間を抜き出したり
  • グループ撮影向けのAIガイド機能
    • 撮影前にAIがリアルタイムで指示を出す機能。

こた

@kota