React Native
@meeeetup/camera-react-native は、ML Kit を用いた Vision Camera のフレームプロセッサを通じて、検出をネイティブスレッド上で実行します。JavaScript による推論もフレームごとの JPEG エンコードも行わないため、中位クラスの Android 端末でも、パイプラインの処理は1フレームあたり数ミリ秒で済みます。
pnpm add @meeeetup/camera-react-native
peer dependencies は、いずれも利用側でインストールします。
| パッケージ | 最低バージョン |
|---|---|
react-native-vision-camera |
4.0.0 |
react-native-vision-camera-face-detector |
1.10.0 |
react-native-worklets-core |
1.5.0 |
react-native-fs |
2.20.0 |
パッシブキャプチャ
import { useRef } from "react";
import { Camera, useCameraDevice } from "react-native-vision-camera";
import { useFaceCaptureSession } from "@meeeetup/camera-react-native";
export function Kiosk({ width, height }: { width: number; height: number }) {
const camera = useRef<Camera>(null);
const device = useCameraDevice("front");
const conf = {
cameraRef: camera,
sessionType: "passive",
minFaceHeight: 0.18,
minFrontalness: 55,
captureWindowMs: 2_000,
cooldownMs: 30_000,
detectionFps: 15,
windowWidth: width,
windowHeight: height,
cameraFacing: "front",
onBatchCapture: async (faces) => {
await upload(faces);
},
} as const;
const { frameProcessor, trackedCount, ready, error } = useFaceCaptureSession(conf);
if (!device) return null;
return (
<Camera
ref={camera}
device={device}
isActive={ready && !error}
photo
frameProcessor={frameProcessor}
style={{ flex: 1 }}
/>
);
}
設定にあるキャプチャ条件は、いずれもここでもそのまま適用されます。フックはそれらを、Web SDK が使うものと同じ FaceCaptureSession にそのまま渡すため、しきい値を一度調整すれば、両方のプラットフォームで同じ値を使えます。
ネイティブ固有のオプション
| オプション | 既定値 | 内容 |
|---|---|---|
cameraRef |
必須 | Vision Camera の <Camera> への ref です。トラッカーが切り出す元になる JPEG を取得するために使います。 |
detectionFps |
15 |
フレームプロセッサの実行頻度の制限です。Vision Camera 4 で frameProcessorFps が削除されたため、間引きは worklet の内側で行っています。 |
photoCadenceMs |
1000 |
キャッシュされたスナップショットを更新する間隔です。小さくするほど、確定した切り出し画像がピーク時のフレームに近づきますが、GPU の負荷は増えます。 |
snapshotQuality |
60 |
そのスナップショットの JPEG 品質です。 |
windowWidth / windowHeight |
— | プレビューのサイズ(px)です。必ず指定してください。 これらを渡すと検出器が autoMode になり、ランドマークを回転・反転・スケールしてウィンドウ座標に変換するため、オーバーレイがプレビューと一致します。 |
cameraFacing |
"front" |
autoMode で左右反転を正しく行うために必要です。 |
フックが返す値
| フィールド | 意味 |
|---|---|
frameProcessor |
<Camera frameProcessor={…} /> に渡します。 |
ready / error |
セッションの状態です。 |
trackedCount |
現在トラッキングされている顔の数です。 |
lastDetections |
独自のオーバーレイを描画するための、正規化された検出結果です。 |
lastSnapshot |
キャッシュされたプレビュースナップショットの file:// URI と、そのサイズおよびタイムスタンプです。 |
lastTimings |
各段階の所要時間。ネイティブの検出時間と、worklet から JS への受け渡しにかかる時間です。 |
flushBatch() |
バッファされた顔を今すぐ送信します。アプリがバックグラウンドに移るときに呼び出してください。 |
鼻のランドマーク
ML Kit が提供するのは noseTip ではなく noseBase です。フックはセッションに noseLandmark: "noseBase" を自動で設定し、上下方向の傾きの基準をずらすことで、Web の MediaPipe とスコアを比較できる状態に保ちます。UseFaceCaptureSessionOptions が noseLandmark を含んでいないのもそのためで、手動で設定するとプラットフォーム間の一貫性が崩れます。
Android のビルドに関する注意
- フレームプロセッサを使うには、
babel.config.jsで worklets の設定が必要です(react-native-worklets-core/plugin)。 <Camera>がマウントされる前に、カメラの権限が許可されている必要があります。Vision Camera が自動で再試行することはありません。takeSnapshotは Vision Camera 4 では Android 専用です。iOS ではフックがtakePhoto()にフォールバックしますが、こちらは負荷が高いため、フレーム落ちが見られる場合はphotoCadenceMsを上げてください。