From a80c9dd589dc6a4d937c8302f4f78e968fb659fa Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Tue, 30 Apr 2024 12:35:05 +0530 Subject: [PATCH 1/2] [mob][photos] Rename method --- mobile/lib/ui/viewer/people/person_cluster_suggestion.dart | 2 +- mobile/lib/ui/viewer/search/result/person_face_widget.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mobile/lib/ui/viewer/people/person_cluster_suggestion.dart b/mobile/lib/ui/viewer/people/person_cluster_suggestion.dart index ff9b1e7559..a330eb8dec 100644 --- a/mobile/lib/ui/viewer/people/person_cluster_suggestion.dart +++ b/mobile/lib/ui/viewer/people/person_cluster_suggestion.dart @@ -273,7 +273,7 @@ class _PersonClustersState extends State { final files = suggestion.filesInCluster; final clusterID = suggestion.clusterIDToMerge; for (final file in files.sublist(0, min(files.length, 8))) { - unawaited(PersonFaceWidget.precomputeFaceCrops(file, clusterID)); + unawaited(PersonFaceWidget.precomputeNextFaceCrops(file, clusterID)); compCount++; if (compCount >= maxComputations) { break; diff --git a/mobile/lib/ui/viewer/search/result/person_face_widget.dart b/mobile/lib/ui/viewer/search/result/person_face_widget.dart index de02938619..21d8f67d8b 100644 --- a/mobile/lib/ui/viewer/search/result/person_face_widget.dart +++ b/mobile/lib/ui/viewer/search/result/person_face_widget.dart @@ -33,7 +33,7 @@ class PersonFaceWidget extends StatelessWidget { ), super(key: key); - static Future precomputeFaceCrops(file, clusterID) async { + static Future precomputeNextFaceCrops(file, clusterID) async { try { final Face? face = await FaceMLDataDB.instance.getCoverFaceForPerson( recentFileID: file.uploadedFileID!, From 29b9bee1be73d273da4a5195b18b105b04bc448b Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Tue, 30 Apr 2024 14:20:21 +0530 Subject: [PATCH 2/2] [mob][photos] Use thumbnails for generating face crop in suggestions --- .../people/person_cluster_suggestion.dart | 9 +++++---- .../search/result/person_face_widget.dart | 18 ++++++++++++++++-- mobile/lib/utils/face/face_box_crop.dart | 19 +++++++++++-------- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/mobile/lib/ui/viewer/people/person_cluster_suggestion.dart b/mobile/lib/ui/viewer/people/person_cluster_suggestion.dart index a330eb8dec..03561d46c8 100644 --- a/mobile/lib/ui/viewer/people/person_cluster_suggestion.dart +++ b/mobile/lib/ui/viewer/people/person_cluster_suggestion.dart @@ -261,21 +261,21 @@ class _PersonClustersState extends State { ], ); // Precompute face thumbnails for next suggestions, in case there are - const precompute = 6; - const maxComputations = 10; + const precomputeSuggestions = 6; + const maxPrecomputations = 10; int compCount = 0; if (allSuggestions.length > currentSuggestionIndex + 1) { for (final suggestion in allSuggestions.sublist( currentSuggestionIndex + 1, - min(allSuggestions.length, currentSuggestionIndex + precompute), + min(allSuggestions.length, currentSuggestionIndex + precomputeSuggestions), )) { final files = suggestion.filesInCluster; final clusterID = suggestion.clusterIDToMerge; for (final file in files.sublist(0, min(files.length, 8))) { unawaited(PersonFaceWidget.precomputeNextFaceCrops(file, clusterID)); compCount++; - if (compCount >= maxComputations) { + if (compCount >= maxPrecomputations) { break; } } @@ -300,6 +300,7 @@ class _PersonClustersState extends State { child: PersonFaceWidget( files[start + index], clusterID: cluserId, + useFullFile: false, ), ), ), diff --git a/mobile/lib/ui/viewer/search/result/person_face_widget.dart b/mobile/lib/ui/viewer/search/result/person_face_widget.dart index 21d8f67d8b..465ea4823d 100644 --- a/mobile/lib/ui/viewer/search/result/person_face_widget.dart +++ b/mobile/lib/ui/viewer/search/result/person_face_widget.dart @@ -19,6 +19,7 @@ class PersonFaceWidget extends StatelessWidget { final EnteFile file; final String? personId; final int? clusterID; + final bool useFullFile; // PersonFaceWidget constructor checks that both personId and clusterID are not null // and that the file is not null @@ -26,6 +27,7 @@ class PersonFaceWidget extends StatelessWidget { this.file, { this.personId, this.clusterID, + this.useFullFile = true, Key? key, }) : assert( personId != null || clusterID != null, @@ -176,6 +178,13 @@ class PersonFaceWidget extends StatelessWidget { faceCropCache.put(face.faceID, data); return data; } + if (!useFullFile) { + final Uint8List? cachedFaceThumbnail = + faceCropThumbnailCache.get(face.faceID); + if (cachedFaceThumbnail != null) { + return cachedFaceThumbnail; + } + } EnteFile? fileForFaceCrop = file; if (face.fileID != file.uploadedFileID!) { fileForFaceCrop = @@ -191,12 +200,17 @@ class PersonFaceWidget extends StatelessWidget { { face.faceID: face.detection.box, }, + useFullFile: useFullFile, ), ); final Uint8List? computedCrop = result?[face.faceID]; if (computedCrop != null) { - faceCropCache.put(face.faceID, computedCrop); - faceCropCacheFile.writeAsBytes(computedCrop).ignore(); + if (useFullFile) { + faceCropCache.put(face.faceID, computedCrop); + faceCropCacheFile.writeAsBytes(computedCrop).ignore(); + } else { + faceCropThumbnailCache.put(face.faceID, computedCrop); + } } return computedCrop; } catch (e, s) { diff --git a/mobile/lib/utils/face/face_box_crop.dart b/mobile/lib/utils/face/face_box_crop.dart index bbdd40e59c..a59bd53263 100644 --- a/mobile/lib/utils/face/face_box_crop.dart +++ b/mobile/lib/utils/face/face_box_crop.dart @@ -1,4 +1,4 @@ -import "dart:io"; +import "dart:io" show File; import "package:flutter/foundation.dart"; import "package:photos/core/cache/lru_map.dart"; @@ -12,24 +12,27 @@ import "package:photos/utils/thumbnail_util.dart"; import "package:pool/pool.dart"; final LRUMap faceCropCache = LRUMap(1000); +final LRUMap faceCropThumbnailCache = LRUMap(1000); final pool = Pool(10, timeout: const Duration(seconds: 15)); Future?> getFaceCrops( EnteFile file, - Map faceBoxeMap, + Map faceBoxeMap, { + bool useFullFile = true, + } ) async { late String? imagePath; - if (file.fileType != FileType.video) { + if (useFullFile && file.fileType != FileType.video) { final File? ioFile = await getFile(file); if (ioFile == null) { return null; } imagePath = ioFile.path; } else { - final thumbnail = await getThumbnailForUploadedFile(file); - if (thumbnail == null) { - return null; - } - imagePath = thumbnail.path; + final thumbnail = await getThumbnailForUploadedFile(file); + if (thumbnail == null) { + return null; + } + imagePath = thumbnail.path; } final List faceIds = []; final List faceBoxes = [];