react-native-vision-camera-face-detector

repository·main·Indexed 43 days ago

https://github.com/luicfrr/react-native-vision-camera-face-detector

A Frame Processor Plugin for React Native Vision Camera that provides real-time and static image face detection by integrating Google MLKit. Version 2.1.0 supports facial landmarks, contours, and classifications via the <Camera /> component, useFaceDetectorOutput hook, or useFaceDetector for advanced frame processor usage.

Tokens
10K
Snippets
33
Records
38
Agent score
56%

What's inside react-native-vision-camera-face-detector

  1. Troubleshoot face detection errors

    main

    Common issues and solutions:

    • Regular javascript function cannot be shared. Try decorating the function with the 'worklet' keyword...
      • If using react-native-reanimated, ensure you have completed the necessary setup steps for worklets.
    • Execution failed for task ':react-native-vision-camera-face-detector:compileDebugKotlin'...
      • This is likely related to the Gradle cache. Try clearing your Gradle cache or following known community solutions for Kotlin compilation errors in this package.
    • Xcode not showing iOS 26.0 Simulators
      • This is due to MLKit requiring an ARM64 simulator slice which is currently unavailable. Workaround: Test face detection on a physical device.
  2. Use the Camera component for real-time face detection

    main

    The simplest way to implement face detection is by using the provided <Camera /> component from react-native-vision-camera-face-detector. This component accepts props like runClassifications, runContours, and runLandmarks to enable specific detection features, and an onFacesDetected callback to handle the results.

    Note: You must request camera permissions using Camera.requestCameraPermission() before using the component.

    import { StyleSheet, Text, View } from 'react-native'
    import { useEffect } from 'react'
    import { useCameraDevice } from 'react-native-vision-camera'
    import { Camera, Face } from 'react-native-vision-camera-face-detector'
    
    export default function App() {
      const device = useCameraDevice('front')
    
      useEffect(() => {
        (async () => {
          const status = await Camera.requestCameraPermission()
          console.log({ status })
        })()
      }, [device])
    
      function handleFacesDetected(faces: Face[]) { 
        console.log('faces', faces.length)
      }
    
      return (
        <View style={{ flex: 1 }}>
          {!!device ? (
            <Camera
              runClassifications
              runContours
              runLandmarks
              performanceMode={'fast'}
              onFacesDetected={handleFacesDetected}
              style={StyleSheet.absoluteFill}
              device={device}
            />
          ) : (
            <Text>No Device</Text>
          )}
        </View>
      )
    }
  3. Use useFaceDetector with Frame Processors

    main

    For advanced usage, you can use useFaceDetector within a Vision Camera Frame Processor. It is highly recommended to run face detection asynchronously using an asyncRunner to avoid blocking the camera preview.

    Warning: Do not destructure hybrid objects returned by the hooks (e.g., avoid const { detectFaces } = useFaceDetector(...)).

    When using this method, you are responsible for calling frame.dispose() to prevent memory leaks.

    import { StyleSheet, Text, View } from 'react-native'
    import { useEffect } from 'react'
    import { Camera, useCameraDevice, useFrameProcessor } from 'react-native-vision-camera'
    import { useFaceDetector } from 'react-native-vision-camera-face-detector'
    import { Worklets } from 'react-native-worklets-core'
    
    export default function App() {
      const device = useCameraDevice('front')
      const faceDetector = useFaceDetector({
        // detection options
      })
      const asyncRunner = useAsyncRunner()
      const frameOutput = useFrameOutput({
        onFrame: (frame) => {
          'worklet'
          
          const wasHandled = asyncRunner.runAsync(() => {
            'worklet'
            const faces = faceDetector.detectFaces(frame)
            // ... do something with detected faces
            frame.dispose()
          })
          
          if (!wasHandled) {
            frame.dispose()
          } 
        }
      })
    
      useEffect(() => {
        (async () => {
          const status = await Camera.requestCameraPermission()
          console.log({ status })
        })()
      }, [device])
    
      return (
        <View style={{ flex: 1 }}>
          {!!device ? (
            <Camera
              style={StyleSheet.absoluteFill}
              device={device}
              isActive={true}
              outputs={[frameOutput]}
            />
          ) : (
            <Text>No Device</Text>
          )}
        </View>
      )
    }
  4. Detect faces in static images

    main

    You can perform face detection on static images (e.g., from a gallery or local assets) using the useImageFaceDetector hook. The detectFaces method accepts several types of input:

    • Bundled assets: Using require('./path/to/image.jpg')
    • URI strings: file://, content://, or http(s)://
    • Objects: { uri: string }

    Warning: Do not destructure hybrid objects returned by the hook.

    import { useImageFaceDetector } from 'react-native-vision-camera-face-detector'
    
    // ❌ don't destruct hybrid objects ❌
    const faceDetector = useImageFaceDetector({ 
      // detection options
    })
    
    // Using a bundled asset
    const faces1 = await faceDetector.detectFaces(
      require('./assets/photo.jpg')
    )
    
    // Using a local file path or content URI
    const faces2 = await faceDetector.detectFaces(
      'file:///storage/emulated/0/Download/pic.jpg'
    )
    
    // Using an object
    const faces3 = await faceDetector.detectFaces({
      uri: 'content://media/external/images/media/12345'
    })
    
    console.log({ faces1, faces2, faces3 })
  5. Use useFaceDetectorOutput for Camera Outputs

    main

    You can connect face detection to a camera session using the useFaceDetectorOutput hook. This hook returns an output object that you pass to the outputs prop of the <Camera /> component. This is useful when following the Vision Camera 'Camera Outputs' pattern.

    import { StyleSheet, Text, View } from 'react-native'
    import { useEffect } from 'react'
    import { Camera, useCameraDevice } from 'react-native-vision-camera'
    import { useFaceDetectorOutput } from 'react-native-vision-camera-face-detector'
    
    export default function App() {
      const device = useCameraDevice('front')
      const faceDetectorOutput = useFaceDetectorOutput({
        // detection options
      })
    
      useEffect(() => {
        (async () => {
          const status = await Camera.requestCameraPermission()
          console.log({ status })
        })()
      }, [device])
    
      return (
        <View style={{ flex: 1 }}>
          {!!device ? (
            <Camera
              style={StyleSheet.absoluteFill}
              device={device}
              isActive={true}
              outputs={[faceDetectorOutput]}
            />
          ) : (
            <Text>No Device</Text>
          )}
        </View>
      )
    }
  6. Configure Metro for the face-detector-example project

    main

    The metro.config.js in the face-detector-example directory is configured to handle peer dependencies correctly within a monorepo-like structure. It prevents multiple versions of the same peer dependency from being loaded by blacklisting the versions located in the project root and aliasing them to the versions found in the example's local node_modules via extraNodeModules.

    const { getDefaultConfig } = require( 'expo/metro-config' )
    const path = require( 'path' )
    const escape = require( 'escape-string-regexp' )
    const pak = require( '../package.json' )
    const root = path.resolve( __dirname, '..' )
    const defaultConfig = getDefaultConfig( __dirname )
    const modules = Object.keys( { ...pak.peerDependencies } )
    
    module.exports = {
      ...defaultConfig,
      projectRoot: __dirname,
      watchFolders: [ root ],
      resolver: {
        ...defaultConfig.resolver,
        blockList: modules.map( ( m ) => (
          new RegExp( `^${ escape( path.join( root, 'node_modules', m ) ) }\/.*$` )
        ) ),
        extraNodeModules: modules.reduce( ( acc, name ) => {
          acc[ name ] = path.join( __dirname, 'node_modules', name )
          return acc
        }, {} )
      },
      transformer: {
        ...defaultConfig.transformer,
        getTransformOptions: async () => ( {
          transform: {
            experimentalImportSupport: false,
            inlineRequires: true
          }
        } )
      }
    }
  7. Configure Android and iOS Build Properties via expo-build-properties

    main

    Use the expo-build-properties plugin to set specific SDK versions and deployment targets required for the face detector to function correctly.

    Android Requirements:

    • minSdkVersion: 26 (Android 8)
    • compileSdkVersion: 36
    • targetSdkVersion: 36
    • buildToolsVersion: '36.0.0'

    iOS Requirements:

    • deploymentTarget: '16.4'

    Example configuration:

    plugins: [
      [
        'expo-build-properties',
        {
          android: {
            minSdkVersion: 26,
            compileSdkVersion: 36,
            targetSdkVersion: 36,
            buildToolsVersion: '36.0.0'
          },
          ios: {
            deploymentTarget: '16.4'
          }
        }
      ]
    ]
    plugins: [
      [ 'expo-image-picker', { 
        photosPermission: 'The app accesses your photos to let you share them with your friends.' 
      } ],
      [ 'expo-build-properties', {
        android: {
          minSdkVersion: 26,
          compileSdkVersion: 36,
          targetSdkVersion: 36,
          buildToolsVersion: '36.0.0'
        },
        ios: {
          deploymentTarget: '16.4'
        }
      } ]
    ]