callWithScore method
Future<({List<List<double> > landmarks, double? score})>
callWithScore(
- Mat faceCrop, {
- Float32List? buffer,
Returns the 468 3D landmark points in normalized coordinates plus the
model's face-presence score in the range 0.0 to 1.0 (higher means more
confident the crop contains a face). score is null when the model does
not expose a presence output.
Example:
final faceCropMat = cv.imdecode(bytes, cv.IMREAD_COLOR);
final result = await faceLandmark.callWithScore(faceCropMat);
final meshPoints = result.landmarks;
final presence = result.score;
faceCropMat.dispose();
Implementation
Future<({List<List<double>> landmarks, double? score})> callWithScore(
cv.Mat faceCrop, {
Float32List? buffer,
}) async {
final CompiledModel? compiledModel = _compiledModel;
if (compiledModel != null) {
// Copying runAsync is the official LiteRT pattern for host-side data
// (the C++ Write/Read API is lock+memcpy+unlock); the Metal accelerator
// only supports MetalBufferPacked tensor buffers, so host zero-copy is
// not available on the GPU path.
final ImageTensor pack = convertImageToTensor(
faceCrop,
outW: _inW,
outH: _inH,
buffer: buffer ?? _scratchBuf,
);
final List<Float32List> outputs = await compiledModel.runAsync([
pack.tensorNHWC,
]);
return (
landmarks: _unpackLandmarks(
outputs[_bestIdx],
_inW,
_inH,
pack.padding,
clamp: true,
normalizeZ: true,
),
score: _scoreIdx == -1 ? null : sigmoidClipped(outputs[_scoreIdx][0]),
);
}
final ImageTensor pack = convertImageToTensor(
faceCrop,
outW: _inW,
outH: _inH,
buffer: buffer ?? _scratchBuf,
);
if (_iso == null) {
_views.inputs[0].setAll(0, pack.tensorNHWC);
_itp!.invoke();
return (
landmarks: _unpackLandmarks(
_views.outputs[_bestIdx],
_inW,
_inH,
pack.padding,
clamp: true,
normalizeZ: true,
),
score: _scoreIdx == -1
? null
: sigmoidClipped(_views.outputs[_scoreIdx][0]),
);
} else {
fillNHWC4D(pack.tensorNHWC, _input4dCache, _inH, _inW);
final List<List<List<List<List<double>>>>> inputs = [_input4dCache];
await _iso!.runForMultipleInputs(inputs, _outputsCache);
final Float32List bestFlat = flattenDynamicTensor(
_outputsCache[_bestIdx],
);
final double? score = _scoreIdx == -1
? null
: sigmoidClipped(flattenDynamicTensor(_outputsCache[_scoreIdx])[0]);
return (
landmarks: _unpackLandmarks(
bestFlat,
_inW,
_inH,
pack.padding,
clamp: true,
normalizeZ: true,
),
score: score,
);
}
}