[mob] FaceMlService static method for full pipeline
This commit is contained in:
parent
e3b8d8975f
commit
618b152f17
1 changed files with 85 additions and 77 deletions
|
@ -204,83 +204,9 @@ class FaceMlService {
|
||||||
try {
|
try {
|
||||||
switch (function) {
|
switch (function) {
|
||||||
case FaceMlOperation.analyzeImage:
|
case FaceMlOperation.analyzeImage:
|
||||||
final int enteFileID = args["enteFileID"] as int;
|
final FaceMlResult result =
|
||||||
final String imagePath = args["filePath"] as String;
|
await FaceMlService.analyzeImageSync(args);
|
||||||
final int faceDetectionAddress =
|
sendPort.send(result.toJsonString());
|
||||||
args["faceDetectionAddress"] as int;
|
|
||||||
final int faceEmbeddingAddress =
|
|
||||||
args["faceEmbeddingAddress"] as int;
|
|
||||||
|
|
||||||
final resultBuilder =
|
|
||||||
FaceMlResultBuilder.fromEnteFileID(enteFileID);
|
|
||||||
|
|
||||||
dev.log(
|
|
||||||
"Start analyzing image with uploadedFileID: $enteFileID inside the isolate",
|
|
||||||
);
|
|
||||||
final stopwatchTotal = Stopwatch()..start();
|
|
||||||
final stopwatch = Stopwatch()..start();
|
|
||||||
|
|
||||||
// Decode the image once to use for both face detection and alignment
|
|
||||||
final imageData = await File(imagePath).readAsBytes();
|
|
||||||
final image = await decodeImageFromData(imageData);
|
|
||||||
final ByteData imgByteData = await getByteDataFromImage(image);
|
|
||||||
dev.log('Reading and decoding image took '
|
|
||||||
'${stopwatch.elapsedMilliseconds} ms');
|
|
||||||
stopwatch.reset();
|
|
||||||
|
|
||||||
// Get the faces
|
|
||||||
final List<FaceDetectionRelative> faceDetectionResult =
|
|
||||||
await FaceMlService.detectFacesSync(
|
|
||||||
image,
|
|
||||||
imgByteData,
|
|
||||||
faceDetectionAddress,
|
|
||||||
resultBuilder: resultBuilder,
|
|
||||||
);
|
|
||||||
|
|
||||||
dev.log(
|
|
||||||
"${faceDetectionResult.length} faces detected with scores ${faceDetectionResult.map((e) => e.score).toList()}: completed `detectFacesSync` function, in "
|
|
||||||
"${stopwatch.elapsedMilliseconds} ms");
|
|
||||||
|
|
||||||
// If no faces were detected, return a result with no faces. Otherwise, continue.
|
|
||||||
if (faceDetectionResult.isEmpty) {
|
|
||||||
dev.log(
|
|
||||||
"No faceDetectionResult, Completed analyzing image with uploadedFileID $enteFileID, in "
|
|
||||||
"${stopwatch.elapsedMilliseconds} ms");
|
|
||||||
sendPort.send(resultBuilder.buildNoFaceDetected().toJsonString());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
stopwatch.reset();
|
|
||||||
// Align the faces
|
|
||||||
final Float32List faceAlignmentResult =
|
|
||||||
await FaceMlService.alignFacesSync(
|
|
||||||
image,
|
|
||||||
imgByteData,
|
|
||||||
faceDetectionResult,
|
|
||||||
resultBuilder: resultBuilder,
|
|
||||||
);
|
|
||||||
|
|
||||||
dev.log("Completed `alignFacesSync` function, in "
|
|
||||||
"${stopwatch.elapsedMilliseconds} ms");
|
|
||||||
|
|
||||||
stopwatch.reset();
|
|
||||||
// Get the embeddings of the faces
|
|
||||||
final embeddings = await FaceMlService.embedFacesSync(
|
|
||||||
faceAlignmentResult,
|
|
||||||
faceEmbeddingAddress,
|
|
||||||
resultBuilder: resultBuilder,
|
|
||||||
);
|
|
||||||
|
|
||||||
dev.log("Completed `embedFacesSync` function, in "
|
|
||||||
"${stopwatch.elapsedMilliseconds} ms");
|
|
||||||
|
|
||||||
stopwatch.stop();
|
|
||||||
stopwatchTotal.stop();
|
|
||||||
dev.log("Finished Analyze image (${embeddings.length} faces) with "
|
|
||||||
"uploadedFileID $enteFileID, in "
|
|
||||||
"${stopwatchTotal.elapsedMilliseconds} ms");
|
|
||||||
|
|
||||||
sendPort.send(resultBuilder.build().toJsonString());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
|
@ -875,6 +801,7 @@ class FaceMlService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Analyzes the given image data by running the full pipeline for faces, using [analyzeImageSync] in the isolate.
|
||||||
Future<FaceMlResult?> analyzeImageInSingleIsolate(EnteFile enteFile) async {
|
Future<FaceMlResult?> analyzeImageInSingleIsolate(EnteFile enteFile) async {
|
||||||
_checkEnteFileForID(enteFile);
|
_checkEnteFileForID(enteFile);
|
||||||
await ensureInitialized();
|
await ensureInitialized();
|
||||||
|
@ -931,6 +858,87 @@ class FaceMlService {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<FaceMlResult> analyzeImageSync(Map args) async {
|
||||||
|
try {
|
||||||
|
final int enteFileID = args["enteFileID"] as int;
|
||||||
|
final String imagePath = args["filePath"] as String;
|
||||||
|
final int faceDetectionAddress = args["faceDetectionAddress"] as int;
|
||||||
|
final int faceEmbeddingAddress = args["faceEmbeddingAddress"] as int;
|
||||||
|
|
||||||
|
final resultBuilder = FaceMlResultBuilder.fromEnteFileID(enteFileID);
|
||||||
|
|
||||||
|
dev.log(
|
||||||
|
"Start analyzing image with uploadedFileID: $enteFileID inside the isolate",
|
||||||
|
);
|
||||||
|
final stopwatchTotal = Stopwatch()..start();
|
||||||
|
final stopwatch = Stopwatch()..start();
|
||||||
|
|
||||||
|
// Decode the image once to use for both face detection and alignment
|
||||||
|
final imageData = await File(imagePath).readAsBytes();
|
||||||
|
final image = await decodeImageFromData(imageData);
|
||||||
|
final ByteData imgByteData = await getByteDataFromImage(image);
|
||||||
|
dev.log('Reading and decoding image took '
|
||||||
|
'${stopwatch.elapsedMilliseconds} ms');
|
||||||
|
stopwatch.reset();
|
||||||
|
|
||||||
|
// Get the faces
|
||||||
|
final List<FaceDetectionRelative> faceDetectionResult =
|
||||||
|
await FaceMlService.detectFacesSync(
|
||||||
|
image,
|
||||||
|
imgByteData,
|
||||||
|
faceDetectionAddress,
|
||||||
|
resultBuilder: resultBuilder,
|
||||||
|
);
|
||||||
|
|
||||||
|
dev.log(
|
||||||
|
"${faceDetectionResult.length} faces detected with scores ${faceDetectionResult.map((e) => e.score).toList()}: completed `detectFacesSync` function, in "
|
||||||
|
"${stopwatch.elapsedMilliseconds} ms");
|
||||||
|
|
||||||
|
// If no faces were detected, return a result with no faces. Otherwise, continue.
|
||||||
|
if (faceDetectionResult.isEmpty) {
|
||||||
|
dev.log(
|
||||||
|
"No faceDetectionResult, Completed analyzing image with uploadedFileID $enteFileID, in "
|
||||||
|
"${stopwatch.elapsedMilliseconds} ms");
|
||||||
|
return resultBuilder.buildNoFaceDetected();
|
||||||
|
}
|
||||||
|
|
||||||
|
stopwatch.reset();
|
||||||
|
// Align the faces
|
||||||
|
final Float32List faceAlignmentResult =
|
||||||
|
await FaceMlService.alignFacesSync(
|
||||||
|
image,
|
||||||
|
imgByteData,
|
||||||
|
faceDetectionResult,
|
||||||
|
resultBuilder: resultBuilder,
|
||||||
|
);
|
||||||
|
|
||||||
|
dev.log("Completed `alignFacesSync` function, in "
|
||||||
|
"${stopwatch.elapsedMilliseconds} ms");
|
||||||
|
|
||||||
|
stopwatch.reset();
|
||||||
|
// Get the embeddings of the faces
|
||||||
|
final embeddings = await FaceMlService.embedFacesSync(
|
||||||
|
faceAlignmentResult,
|
||||||
|
faceEmbeddingAddress,
|
||||||
|
resultBuilder: resultBuilder,
|
||||||
|
);
|
||||||
|
|
||||||
|
dev.log("Completed `embedFacesSync` function, in "
|
||||||
|
"${stopwatch.elapsedMilliseconds} ms");
|
||||||
|
|
||||||
|
stopwatch.stop();
|
||||||
|
stopwatchTotal.stop();
|
||||||
|
dev.log("Finished Analyze image (${embeddings.length} faces) with "
|
||||||
|
"uploadedFileID $enteFileID, in "
|
||||||
|
"${stopwatchTotal.elapsedMilliseconds} ms");
|
||||||
|
|
||||||
|
return resultBuilder.build();
|
||||||
|
} catch (e, s) {
|
||||||
|
dev.log("Could not analyze image: \n e: $e \n s: $s");
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<String?> _getImagePathForML(
|
Future<String?> _getImagePathForML(
|
||||||
EnteFile enteFile, {
|
EnteFile enteFile, {
|
||||||
FileDataForML typeOfData = FileDataForML.fileData,
|
FileDataForML typeOfData = FileDataForML.fileData,
|
||||||
|
|
Loading…
Reference in a new issue