クイックスタート(React)
@meeeetup/camera-web は、カメラ・検出器・キャプチャセッションを管理するプロバイダと、そこから状態を読み取るコンポーネントを提供します。以下のコードはすべてクライアント側で動作し、利用側が送信処理を書かないかぎり、ブラウザの外にデータが出ることはありません。
pnpm add @meeeetup/camera-web
最小構成のカメラ
import { MeeeetUpCamProvider, CameraViewport, FaceGrid } from "@meeeetup/camera-web";
export function Reception() {
return (
<MeeeetUpCamProvider
mode="passive"
onBatchCapture={async (faces) => {
await fetch("/capture", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ images: faces.map((f) => f.dataUrl) }),
});
}}
>
<CameraViewport />
<FaceGrid />
</MeeeetUpCamProvider>
);
}
これだけでパッシブ構成として完結します。ビューポートがカメラの利用を要求してトラッキング枠を描画し、すべての顔について最良のフレームが選ばれ、onBatchCapture が10秒ごとに、その時点で選ばれた顔を渡して呼び出されます。
設定をオブジェクトにまとめる
キャプチャ設定は単なるデータなので、1つのオブジェクトにまとめて展開して渡します。多くの導入がこの形に落ち着きます。設定を1つのモジュールから export し、コンポーネント側で受け取る形です。
import type { PassiveCaptureOnlyMeeeetUpCamProviderProps } from "@meeeetup/camera-web";
type CaptureConf = Omit<PassiveCaptureOnlyMeeeetUpCamProviderProps, "children">;
export const conf = {
mode: "passive",
minDetectionScore: 0.6, // ignore what the detector is unsure about
minFaceHeight: 0.18, // ignore faces smaller than 18% of frame height
minFrontalness: 55, // ignore faces not turned towards the lens
captureWindowMs: 2_000, // search two seconds for the best frame
cooldownMs: 30_000, // then leave that person alone for 30s
onBatchCapture: send,
} satisfies CaptureConf;
<MeeeetUpCamProvider {...conf}>
<CameraViewport />
<FaceGrid />
</MeeeetUpCamProvider>
mode と受け取り口(パッシブでは onBatchCapture、インタラクティブでは onCapture)以外のフィールドは、すべて省略できます。省略した項目には出荷時の既定値が適用されます。一覧は設定を参照してください。
キャプチャ状態を読み取る
useMeeeetUpCam() は、セッションの現在の状態を返します。mode による判別可能なユニオン型なので、モード固有のフィールドに触れる前に絞り込んでください。
import { useMeeeetUpCam } from "@meeeetup/camera-web";
function CaptureStatus() {
const cam = useMeeeetUpCam();
if (cam.error) return <p role="alert">{cam.error}</p>;
if (!cam.ready) return <p>Starting the camera…</p>;
if (cam.mode !== "passive") return null;
return (
<div>
<p>{cam.trackedCount} in frame · {cam.totalCount} captured this session</p>
<button type="button" onClick={cam.flushBatch}>Send now</button>
<button type="button" onClick={cam.rearm}>Capture everyone again</button>
</div>
);
}
| フィールド | 意味 |
|---|---|
ready / error |
カメラとモデルの状態です。 |
trackedCount |
その瞬間にトラッキングされている顔の数です。 |
totalCount |
このセッションで1回以上選択された、異なる顔の数です。 |
livePreviews |
表示中の顔ごとの、現時点で最良の切り出し画像です。FaceGrid が表示するサムネイルにあたります。 |
selectedFaces |
バッファされ、次のバッチ送信を待っている顔です。 |
flushBatch() |
バッファを今すぐ onBatchCapture に渡します。ページが非表示になるときに呼び出してください。 |
rearm() |
すべてのキャプチャウィンドウをやり直し、すでにキャプチャ済みの顔も再び探索の対象にします。 |
devices, currentDeviceId, setDeviceId, toggleCamera |
カメラの選択。localStorage に保存されます。 |
コンポーネント
いずれもコンテキスト経由でプロバイダの状態を読み取るため、props は不要で、プロバイダの内側であればどこにでも配置できます。
| コンポーネント | 表示内容 |
|---|---|
CameraViewport |
<video> と、トラッキング用のオーバーレイキャンバスです。 |
FaceGrid |
トラッキング中の顔ごとのライブサムネイル。品質が上がるたびに更新されます。 |
FaceCounter |
トラッキング中の数とキャプチャ済みの数です。 |
DevicePicker |
カメラの選択 UI です。 |
CameraToggle |
前面・背面の切り替えです。 |
AlignmentRing, CaptureButton |
インタラクティブモード用のガイドリングとシャッターです。 |
標準コンポーネントでは実現できないレイアウトが必要な場合は、cam.videoRef と cam.overlayRef を自前の要素に渡し、残りは自分で描画してください。プロバイダは DOM の持ち主を問いません。
インタラクティブモード
プロバイダは同じで、振る舞いが変わります。対象は1人、写真は1枚で、リングの中で静止したときに撮影されます。
const conf = {
mode: "interactive",
alignmentCaptureDelayMs: 2_000,
onCapture: async (faceImage, fullFrame) => {
await register(faceImage, fullFrame);
},
} as const;
<MeeeetUpCamProvider {...conf}>
<CameraViewport />
<AlignmentRing />
<CaptureButton />
</MeeeetUpCamProvider>
上の表にあるキャプチャ条件はパッシブモードの設定です。インタラクティブモードのキャプチャは、トラッカーの選択パイプラインではなくガイドリングによって決まります。