checkLiveness method

Future<bool> checkLiveness(
  1. Image image
)

Runs the ONNX model to get liveness score Returns a score between 0 and 1, where higher = more likely to be real

Implementation

Future<bool> checkLiveness(imglib.Image image) async {
  // Preprocess image to model input format
  final input = _preprocessImage(image);
  final runOptions = OrtRunOptions();
  // Create input tensor
  // Model expects [1, 3, 256, 256] based on training config (resize = dict(height=256, width=256))
  final inputOrt = OrtValueTensor.createTensorWithDataList(
    input,
    [1, 3, 256, 256], // Shape: [batch, channels, height, width]
  );

  // Run inference
  final inputs = {_session.inputNames.first: inputOrt};
  final outputs = await _session.runAsync(
    runOptions,
    inputs,
  );

  // Get output
  final outputTensor = outputs?.first;
  if (outputTensor == null) {
    throw Exception('No output from model');
  }

  // Extract score from output
  final outputData = outputTensor.value as List<List<double>>;
  debugPrint('[ONNX AntiSpoof] Raw output: $outputData');
  debugPrint(
      '[ONNX AntiSpoof] outputData[0].length: ${outputData[0].length}');

  // The output format depends on your model
  // Common formats:
  // 1. [batch, 2] - probabilities for [fake, real]
  // 2. [batch, 1] - single confidence score
  bool isReal = false;
  if (outputData[0].length == 2) {
    List<double> out = outputData[0];
    double realProb = out[0];
    // double spoofProb = out[1];
    if (realProb >= livenessThreshold) {
      isReal = true;
    }
    // Binary classification: [fake_prob, real_prob]
    // score = spoofProb; // Real face probability
  } else if (outputData[0].length == 1) {
    // Single score output
    // score = outputData[0][0];
  } else if (outputData[0].length == 3) {
    final fakeProb = outputData[0][0]; // Index 0
    final realProb = outputData[0][1]; // Index 1
    final unknownProb = outputData[0][2]; // Index 2

    debugPrint(
        '[ONNX AntiSpoof] Fake: $fakeProb, Real: $realProb, Unknown: $unknownProb');

    // Method 1: Use argmax (like original code)
    final maxIndex =
        outputData[0].indexOf(outputData[0].reduce((a, b) => a > b ? a : b));

    if (maxIndex == 1) {
      isReal = true;
      debugPrint(
          '[ONNX AntiSpoof] outputData[0].length == 3 Decision: REAL (argmax = 1)');
    } else {
      // Method 2: Fallback - compare real vs fake directly
      // Use this if argmax doesn't work well
      if (realProb > fakeProb) {
        isReal = true;
        debugPrint(
            '[ONNX AntiSpoof]outputData[0].length == 3 Decision: REAL (realProb > fakeProb)');
      } else {
        debugPrint(
            '[ONNX AntiSpoof]outputData[0].length == 3 Decision: FAKE');
      }
    }

    // Multi-class: take max or specific index
    // score = outputData[0].reduce((a, b) => a > b ? a : b);
  }

  // Release resources
  inputOrt.release();
  outputTensor.release();
  runOptions.release();
  return isReal;
}