passive_liveness 0.0.2 copy "passive_liveness: ^0.0.2" to clipboard
passive_liveness: ^0.0.2 copied to clipboard

Ultra-lightweight passive face liveness detection using LiteRT (TensorFlow Lite) for Flutter on iOS and Android.

passive_liveness #

pub package License: MIT Platform

An ultra-lightweight, high-performance passive face anti-spoofing (liveness) detection package for Flutter powered by LiteRT (TensorFlow Lite) edge inference on Android and iOS.


Features #

  • High-Performance Edge Inference: Uses MiniFASNet v2 SE model via flutter_litert, offloading inference to a dedicated background Dart isolate (IsolateInterpreter) with XNNPack ARM NEON SIMD vectorization.
  • 📷 Zero-Copy Camera Stream Processing: Preprocesses raw Flutter CameraImage byte buffers (NV21 / YUV420 on Android, BGRA8888 on iOS) directly to TFLite tensors without main-thread image decoding.
  • 🖼️ Static Photo & File Detection: Uses Flutter's built-in C++ Skia engine codecs (dart:ui) to evaluate liveness from static images (File or Uint8List) with zero external image package dependencies.
  • 📱 Android Rotated Bounding Box Mapping: Built-in isRotatedBoundingBox auto-detection and FaceBoundingBox.toRawBufferSpace() transformation for portrait ML Kit face detection bounding boxes on Android (, 90°, 180°, 270°).
  • 💡 Low-Light Adaptive Gamma Contrast Expansion: Non-linear gamma power-law contrast enhancement ($\gamma \approx 0.60 - 0.88$) that expands 3D skin texture gradients in dim room lighting.

Installation #

Add passive_liveness to your project:

flutter pub add passive_liveness

Usage #

1. Initialize Detector Engine #

Initialize PassiveLivenessDetector. The bundled MiniFAS model is loaded automatically:

import 'package:passive_liveness/passive_liveness.dart';

final detector = PassiveLivenessDetector();
await detector.initialize();

2. Real-Time Camera Stream Detection (CameraImage) #

Pass raw CameraImage frames from camera package along with an optional face bounding box (e.g. from Google ML Kit Face Detection):

import 'dart:io';
import 'package:camera/camera.dart';
import 'package:passive_liveness/passive_liveness.dart';

void processCameraFrame(CameraImage cameraImage, Rect? faceRect, int sensorRotation) async {
  // Convert CameraImage into LivenessImageBuffer
  final buffer = LivenessImageBuffer(
    width: cameraImage.width,
    height: cameraImage.height,
    format: cameraImage.format.group == ImageFormatGroup.bgra8888
        ? LivenessImageFormat.bgra8888
        : (cameraImage.planes.length == 1
            ? LivenessImageFormat.nv21
            : LivenessImageFormat.yuv420),
    planes: cameraImage.planes
        .map((p) => LivenessImagePlane(
              bytes: p.bytes,
              bytesPerRow: p.bytesPerRow,
              bytesPerPixel: p.bytesPerPixel,
            ))
        .toList(),
  );

  // Convert Rect to FaceBoundingBox
  final boundingBox = faceRect != null ? FaceBoundingBox.fromRect(faceRect) : null;

  final LivenessResult result = await detector.detectLivenessFromBuffer(
    buffer,
    boundingBox: boundingBox,
    rotation: sensorRotation, // e.g., 270 on Android front camera, 90 on iOS
    isRotatedBoundingBox: Platform.isAndroid, // Maps portrait ML Kit face box to raw landscape buffer space
  );

  if (result.isReal) {
    print('Real human face! Real score: ${result.realScore.toStringAsFixed(3)}');
  } else {
    print('Spoof face detected! Spoof score: ${result.spoofScore.toStringAsFixed(3)}');
  }
}

3. Detect Liveness from Static Photo File (File) #

Evaluate a photo file picked via image_picker or taken with takePicture():

import 'dart:io';
import 'package:passive_liveness/passive_liveness.dart';

Future<void> checkPhotoLiveness(File imageFile, Rect? faceRect) async {
  final boundingBox = faceRect != null ? FaceBoundingBox.fromRect(faceRect) : null;

  final LivenessResult result = await detector.detectLivenessFromImageFile(
    imageFile,
    boundingBox: boundingBox,
  );

  print('Is Real: ${result.isReal}');
  print('Real Score: ${result.realScore}');
  print('Inference Time: ${result.inferenceTime.inMilliseconds}ms');
}

4. Detect Liveness from Image Bytes (Uint8List) #

Evaluate liveness directly from in-memory image bytes:

import 'dart:typed_data';
import 'package:passive_liveness/passive_liveness.dart';

Future<void> checkBytesLiveness(Uint8List imageBytes, {Rect? faceRect}) async {
  final boundingBox = faceRect != null ? FaceBoundingBox.fromRect(faceRect) : null;

  final LivenessResult result = await detector.detectLivenessFromImageBytes(
    imageBytes,
    boundingBox: boundingBox,
  );

  print('Is Real: ${result.isReal}');
  print('Real Score: ${result.realScore}');
}

Clean Up #

When you are done using the detector (e.g. in a State's dispose method):

@override
void dispose() {
  detector.dispose();
  super.dispose();
}

Core Classes Reference #

Class Description
PassiveLivenessDetector Main engine class for initializing the model and running inferences.
LivenessImageBuffer Lightweight container for camera raw byte planes (NV21, YUV420, BGRA8888).
FaceBoundingBox Coordinates (x, y, width, height) defining the face area. Supports .fromRect(Rect) and .toRawBufferSpace().
LivenessResult Detection result containing isReal, realScore, spoofScore, logitDiff, and inferenceTime.

Model Attribution & Credits #

This package utilizes the MiniFASNet v2 SE passive face anti-spoofing model architecture, derived and converted from facenox/face-antispoof-onnx (MiniFASNetV2 SE trained with Fourier Transform frequency spectrum loss).


Author #

Andika Tri Prasetya


License #

This project is licensed under the OSI-approved MIT License - see the LICENSE file for details.

7
likes
0
points
518
downloads

Publisher

unverified uploader

Weekly Downloads

Ultra-lightweight passive face liveness detection using LiteRT (TensorFlow Lite) for Flutter on iOS and Android.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, flutter_litert

More

Packages that depend on passive_liveness