call method
Generates a face embedding from an aligned face crop using cv.Mat.
Accepts a cv.Mat directly, providing better performance by avoiding image format conversions.
The faceCrop parameter should contain an aligned face as cv.Mat.
The Mat is NOT disposed by this method - caller is responsible for disposal.
The optional buffer parameter allows reusing a pre-allocated Float32List
for the tensor conversion to reduce GC pressure.
Returns a Float32List containing the L2-normalized embedding vector.
Example:
final faceCropMat = cv.imdecode(bytes, cv.IMREAD_COLOR);
final embedding = await faceEmbedding.call(faceCropMat);
faceCropMat.dispose();
Implementation
Future<Float32List> call(cv.Mat faceCrop, {Float32List? buffer}) async {
final ImageTensor pack = convertImageToTensor(
faceCrop,
outW: _inW,
outH: _inH,
buffer: buffer ?? _scratchBuf,
);
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 List<Float32List> outputs = await compiledModel.runAsync([
pack.tensorNHWC,
]);
return _normalizeEmbeddingImpl(outputs[0]);
}
if (_iso == null) {
_views.inputs[0].setAll(0, pack.tensorNHWC);
_itp!.invoke();
return _normalizeEmbeddingImpl(Float32List.fromList(_views.outputs[0]));
} else {
fillNHWC4D(pack.tensorNHWC, _input4dCache, _inH, _inW);
final List<List<List<List<List<double>>>>> inputs = [_input4dCache];
final Map<int, Object> outputs = <int, Object>{
0: allocTensorShape(_outputShape),
};
await _iso!.runForMultipleInputs(inputs, outputs);
final Float32List embedding = flattenDynamicTensor(outputs[0]);
return _normalizeEmbeddingImpl(embedding);
}
}