You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native:如何通过expo-camera定时裁剪人脸并接入TensorFlow.js?

可行实现技巧

我之前在开发类似的Expo + TensorFlow.js人脸处理应用时,也遇到过这个问题——Expo Camera官方文档确实没给出直接的人脸裁剪+TFJS处理的流程,但有几个实用的技巧可以帮你实现需求,分享给你:

方法一:利用Expo Camera内置人脸检测+定时器裁剪

Expo Camera自带的人脸检测会返回人脸的边界框坐标,我们可以结合定时器,每隔1秒基于这些坐标裁剪人脸,再传入TFJS模型:

  1. 启用Camera人脸检测
    首先在Camera组件中配置人脸检测参数,确保能拿到人脸的bounding box:

    import { Camera } from 'expo-camera';
    
    <Camera
      ref={cameraRef}
      style={styles.camera}
      type={Camera.Constants.Type.front}
      faceDetectorSettings={{
        mode: Camera.Constants.FaceDetector.Mode.fast,
        detectLandmarks: Camera.Constants.FaceDetector.Landmarks.none,
        runClassifications: Camera.Constants.FaceDetector.Classifications.none,
      }}
      onFacesDetected={handleFacesDetected}
    />
    
  2. 添加定时器控制处理频率
    用setInterval每隔1秒触发一次人脸裁剪,但要注意防抖——比如只有当检测到人脸时才执行,避免空操作:

    const [faces, setFaces] = useState([]);
    let processTimer = null;
    
    const handleFacesDetected = ({ faces }) => {
      setFaces(faces);
    };
    
    useEffect(() => {
      processTimer = setInterval(async () => {
        if (faces.length === 0) return;
        await processFaces(faces);
      }, 1000);
    
      return () => clearInterval(processTimer);
    }, [faces]);
    
  3. 转换坐标并裁剪人脸
    Expo Camera返回的人脸坐标是相对于预览画面的,需要转换成实际图片的坐标,再用expo-image-manipulator裁剪:

    import * as ImageManipulator from 'expo-image-manipulator';
    
    const processFaces = async (faces) => {
      // 先捕获当前相机帧(低分辨率,减少性能消耗)
      const photo = await cameraRef.current.takePictureAsync({
        quality: 0.3,
        base64: true,
        skipProcessing: true,
      });
    
      // 转换人脸坐标:预览画面 -> 实际图片
      const { width: cameraWidth, height: cameraHeight } = await cameraRef.current.getCameraPreviewSizeAsync();
      const { width: imageWidth, height: imageHeight } = photo;
      const scaleX = imageWidth / cameraWidth;
      const scaleY = imageHeight / cameraHeight;
    
      for (const face of faces) {
        const adjustedFace = {
          x: face.bounds.origin.x * scaleX,
          y: face.bounds.origin.y * scaleY,
          width: face.bounds.size.width * scaleX,
          height: face.bounds.size.height * scaleY,
        };
    
        // 裁剪人脸区域
        const croppedImage = await ImageManipulator.manipulateAsync(
          photo.uri,
          [{ crop: adjustedFace }],
          { base64: true }
        );
    
        // 转换为TFJS张量并传入模型处理
        const tensor = await tf.browser.fromPixelsAsync(croppedImage.base64);
        // 这里替换成你的模型推理逻辑
        const result = await yourModel.predict(tensor);
        // 记得清理张量,避免内存泄漏
        tensor.dispose();
        result.dispose();
      }
    };
    

方法二:直接捕获相机帧+TFJS人脸检测

如果Expo Camera内置的人脸检测不够灵活,你可以直接每隔1秒捕获相机帧,用TFJS自带的人脸检测模型(比如BlazeFace)检测并裁剪,再传入自定义模型:

  1. 捕获低分辨率相机帧
    同样用takePictureAsync每隔1秒获取帧,优先用低分辨率减少计算压力:

    useEffect(() => {
      const timer = setInterval(async () => {
        const photo = await cameraRef.current.takePictureAsync({
          quality: 0.2,
          base64: true,
        });
        await processFrameWithTFJS(photo);
      }, 1000);
    
      return () => clearInterval(timer);
    }, []);
    
  2. 用TFJS检测并裁剪人脸
    先加载TFJS的BlazeFace模型,检测人脸后用tf.image.cropAndResize裁剪:

    import * as tf from '@tensorflow/tfjs';
    import * as faceDetection from '@tensorflow-models/blazeface';
    
    let faceModel = null;
    
    useEffect(() => {
      // 初始化TFJS和人脸检测模型
      const initModels = async () => {
        await tf.ready();
        faceModel = await faceDetection.load();
      };
      initModels();
    }, []);
    
    const processFrameWithTFJS = async (photo) => {
      if (!faceModel) return;
    
      // 将base64图片转换为TFJS张量
      const imageTensor = await tf.browser.fromPixelsAsync(`data:image/jpeg;base64,${photo.base64}`);
      // BlazeFace需要的输入尺寸是128x128,先缩放
      const resizedTensor = tf.image.resizeBilinear(imageTensor, [128, 128]);
    
      // 检测人脸
      const predictions = await faceModel.estimateFaces(resizedTensor);
      resizedTensor.dispose();
    
      for (const pred of predictions) {
        // 将BlazeFace返回的归一化坐标转换为实际图片坐标
        const x = pred.topLeft[0] * photo.width;
        const y = pred.topLeft[1] * photo.height;
        const width = pred.bottomRight[0] - x;
        const height = pred.bottomRight[1] - y;
    
        // 裁剪人脸张量
        const croppedTensor = tf.image.cropAndResize(
          imageTensor.expandDims(0), // 增加batch维度
          [[y / photo.height, x / photo.width, (y + height)/photo.height, (x + width)/photo.width]], // 归一化的裁剪框
          [0], // 索引
          [224, 224] // 输出尺寸(根据你的模型要求调整)
        );
    
        // 传入自定义模型处理
        const modelResult = await yourCustomModel.predict(croppedTensor);
        // 清理张量
        croppedTensor.dispose();
        modelResult.dispose();
      }
    
      imageTensor.dispose();
    };
    

关键性能优化点

  • 降低捕获分辨率:用quality参数减少图片大小,避免TFJS处理时卡顿。
  • 及时清理张量:每次处理完都用tf.dispose()或tf.tidy()清理,防止内存泄漏。
  • 防抖处理:如果连续两帧的人脸坐标变化很小,可以跳过重复处理,节省资源。

内容的提问来源于stack exchange,提问作者Mertcan Seğmen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 22:37:43