detectFaces static method
Runs face detection on the provided imageBytes.
Implementation
static Future<FaceDetectionResult> detectFaces(
Uint8List imageBytes, {
double scoreThreshold = 0.55,
double nmsThreshold = -1,
}) async {
if (_session == null || _inputName == null) {
throw StateError(
'FaceValidator.initialize() must be called before detection',
);
}
if (imageBytes.isEmpty) {
return FaceDetectionResult.empty();
}
PreprocessedImage? preprocessed;
OrtValue? inputTensor;
Map<String, OrtValue> outputs = {};
try {
preprocessed = await _preprocess(imageBytes);
inputTensor = await OrtValue.fromList(preprocessed.tensor, const [
1,
1,
_inputHeight,
_inputWidth,
]);
outputs = await _session!.run({_inputName!: inputTensor});
final heatmapValue = outputs[_outputNames[0]];
final boxValue = outputs[_outputNames[1]];
final landmarkValue = outputs[_outputNames[2]];
if (heatmapValue == null || boxValue == null || landmarkValue == null) {
throw StateError('Model output tensors are missing');
}
final heatmapData = Float32List.fromList(
(await heatmapValue.asFlattenedList()).cast<double>(),
);
final boxData = Float32List.fromList(
(await boxValue.asFlattenedList()).cast<double>(),
);
final landmarkData = Float32List.fromList(
(await landmarkValue.asFlattenedList()).cast<double>(),
);
final heatmapShape = heatmapValue.shape;
final hmHeight = heatmapShape[2];
final hmWidth = heatmapShape[3];
final candidates = _decodeDetections(
heatmapData: heatmapData,
boxData: boxData,
landmarkData: landmarkData,
hmHeight: hmHeight,
hmWidth: hmWidth,
scoreThreshold: scoreThreshold,
);
final filtered = _applyNmsIfNeeded(candidates, nmsThreshold);
final faces = filtered
.map((candidate) => candidate.toFaceDetection(preprocessed!))
.whereType<FaceDetection>()
.toList(growable: false);
return FaceDetectionResult(
detections: faces,
originalWidth: preprocessed.originalWidth,
originalHeight: preprocessed.originalHeight,
);
} catch (e) {
print('Face detection failed: $e');
return FaceDetectionResult.error();
} finally {
if (inputTensor != null) {
await inputTensor.dispose();
}
await Future.wait(
outputs.values.map((value) => value.dispose()),
eagerError: false,
);
}
}