猫の手ツール

Algorithm & UI/UX

WASMによる高速顔認識と
正規化座標によるCanvas操作の最適化

集合写真から個々の顔を切り出すには、推定された顔の範囲を元画像の座標へ変換する必要があります。MediaPipeとCanvas APIを駆使した、クライアントサイド完結型ツールの実装の裏側を解説します。

このツールの入力から出力まで

現行コードの確認日:

入力
集合写真を選び、切り出す顔枠と余白、四角・円形の形式を指定します。
処理
FaceDetectorの顔枠に余白を加え、元の処理画像から顔ごとにCanvasへ描きます。円形ではクリップを掛けて周囲を透明にします。
出力
出力は顔ごとのPNGで、円形モードの周囲は透明です。

まず確認する点:枠が写真の端へはみ出すと余白を十分取れません。一括保存はZIP生成ではないため、保存先に人数分のファイルがあるか確認します。

仕上がりの例

集合写真から2人の顔を、それぞれ切り出した例です。

加工前・加工後
左は屋外で2人が並んだ写真。右は2人の顔を別々に切り出した画像。

サンプルにはAIで生成した架空の人物画像を使用しています。切り出した2枚は、それぞれ別の画像として保存したものです。

加工前・加工後

左は屋外で2人が並んだ写真。右は2人の顔を別々に切り出した画像。

掲載画像はサイトにある既存の公開作例です。保存済みの資料ではAIで作成した架空の人物・手の画像を使用しています。今回の確認日が、この作例を実行した日を表すわけではありません。

保存済み検証記録の条件を見る

資料の種類は「既存の公開作例」です。公開作例と保存済み記録で素材や色などが異なる場合があるため、下の数値は保存済み検証記録の条件として読んでください。

2人の子どもが写る写真から、それぞれの顔を正方形の画像として切り出した例です。

記録の入力画像
1802×983px (JPEG)
記録の出力画像
129×129px (PNG)、100×100px (PNG)

この作例には操作値の記録がないため、同じ設定で再現できるとは断定しません。本文の数値は現行の実装仕様です。

資料ファイルの作成日は実行日として扱っていません。個別端末の処理速度や、ほかの写真に対する検出・加工の精度を測定した資料でもありません。

実装の確認箇所:src/pages/ai/face-det/bulk-crop/index.astro。以下のコード抜粋と出力条件は、この本番実装に基づいて説明します。

仕組みを読み進めるときは、MediaPipeの顔検出(顔枠の入力・出力と検出漏れの扱い)、Canvas APIと画像処理(画像寸法、drawImage、画素と透明度の扱い)が参考になります。

1. MediaPipeによるエッジAI推論

本ツール最大のこだわりは、すべての画像処理をユーザーのブラウザ内(ローカル環境)で完結させている点です。 これを実現するために、Googleが開発したMediaPipe Face DetectionをWebAssembly(WASM)形式で組み込んでいます。

サーバーへ画像を送信しないため、顔写真を処理サーバーへアップロードする工程はありません。ただし、AIモデルの読込には通信と初期化の待ち時間があり、写真の内容や端末によって検出速度も変わります。

正規化された顔枠を切り出し範囲に変える計算です。boxはxCenter、yCenter、width、heightを0〜1の割合で持ち、paddingは画面の余白設定値です。

function cropBounds(box, w, h, padding) {
  const scale = 1 + padding / 100;
  const width = box.width * w * scale;
  const height = box.height * h * scale;
  const x = Math.max(0, box.xCenter * w - width / 2);
  const y = Math.max(0, box.yCenter * h - height / 2);
  return {x, y, width: Math.min(w - x, width),
    height: Math.min(h - y, height)};
}

2. 正規化座標によるマルチデバイス対応

Canvas上に描画される顔の枠(バウンディングボックス)は、ピクセル絶対値ではなく、0.0〜1.0の範囲に正規化された座標で管理しています。

この工夫により、高解像度な写真でもプレビュー用の小さな画面でも、同一のデータ構造で座標を扱えます。画面リサイズやスマートフォンの縦横回転が発生しても、保持した割合に描画先の幅・高さを掛け直して、枠を描画できます。

3. iOS環境に特化したUXハック

ブラウザツールにおいて、iPhone(iOS)の画像保存は大きな壁となります。 通常の <a download> タグが一部のブラウザやSNS内蔵ビューワーで動作しない問題に対処するため、Web Share APIを条件分岐で組み込んでいます。

PCやAndroidでは直接ダウンロードを実行し、iOSでは対応を確認してOSの共有メニューを呼び出します。表示される保存先や共有項目は端末・ブラウザに依存します。

出力の仕様と確認する点

入力は長辺2000px以下へ縮小してから顔を検出します。検出漏れの枠は手動で追加し、不要な枠は削除してから切り出します。小さな顔や横顔、重なった顔がすべて検出されるとは限りません。

余白は顔枠を倍率で広げる設定です。画像端にある顔は切り出せる範囲が狭くなります。円形モードは切り出し枠に楕円のクリップを掛けるため、枠の縦横比によっては真円になりません。

出力は顔ごとのPNGで、円形モードの周囲は透明です。一括保存はZIPではなく、共有メニューまたは複数ファイルの連続ダウンロードです。ブラウザの保存制限がある場合は個別画像を保存します。