Преглед на файлове

[mob][face] Storage width/height along with area and visibility

Neeraj Gupta преди 1 година
родител
ревизия
d19d7ffe79

+ 6 - 2
mobile/lib/face/db.dart

@@ -272,12 +272,16 @@ class FaceMLDataDB {
     final List<Map<String, dynamic>> maps = await db.query(
       facesTable,
       columns: [
-        fileIDColumn,
         faceIDColumn,
-        faceDetectionColumn,
+        fileIDColumn,
         faceEmbeddingBlob,
         faceScore,
+        faceDetectionColumn,
         faceBlur,
+        imageHeight,
+        imageWidth,
+        faceArea,
+        faceVisibilityScore,
         mlVersionColumn,
       ],
       where: '$fileIDColumn = ?',

+ 8 - 0
mobile/lib/face/db_fields.dart

@@ -8,6 +8,10 @@ const faceDetectionColumn = 'detection';
 const faceEmbeddingBlob = 'eBlob';
 const faceScore = 'score';
 const faceBlur = 'blur';
+const faceArea = 'area';
+const faceVisibilityScore = 'visibility';
+const imageWidth = 'width';
+const imageHeight = 'height';
 const faceClusterId = 'cluster_id';
 const mlVersionColumn = 'ml_version';
 
@@ -18,6 +22,10 @@ const createFacesTable = '''CREATE TABLE IF NOT EXISTS $facesTable (
   $faceEmbeddingBlob BLOB NOT NULL,
   $faceScore  REAL NOT NULL,
   $faceBlur REAL NOT NULL DEFAULT $kLapacianDefault,
+  $imageHeight	INTEGER NOT NULL DEFAULT 0,
+  $imageWidth	INTEGER NOT NULL DEFAULT 0,
+  $faceArea	INTEGER NOT NULL DEFAULT 0,
+  $faceVisibilityScore	INTEGER NOT NULL DEFAULT -1,
   $mlVersionColumn	INTEGER NOT NULL DEFAULT -1,
   PRIMARY KEY($fileIDColumn, $faceIDColumn)
   );

+ 8 - 0
mobile/lib/face/db_model_mappers.dart

@@ -35,6 +35,10 @@ Map<String, dynamic> mapRemoteToFaceDB(Face face) {
     faceScore: face.score,
     faceBlur: face.blur,
     mlVersionColumn: faceMlVersion,
+    faceArea: face.area(),
+    faceVisibilityScore: face.visibility,
+    imageWidth: face.fileInfo?.imageWidth ?? 0,
+    imageHeight: face.fileInfo?.imageHeight ?? 0,
   };
 }
 
@@ -46,5 +50,9 @@ Face mapRowToFace(Map<String, dynamic> row) {
     row[faceScore] as double,
     Detection.fromJson(json.decode(row[faceDetectionColumn] as String)),
     row[faceBlur] as double,
+    fileInfo: FileInfo(
+      imageWidth: row[imageWidth] as int,
+      imageHeight: row[imageHeight] as int,
+    ),
   );
 }

+ 0 - 1
mobile/lib/face/model/detection.dart

@@ -43,7 +43,6 @@ class Detection {
     );
   }
 
-  // TODO: iterate on better area calculation, potentially using actual indexing image dimensions instead of file metadata
   int getFaceArea(int imageWidth, int imageHeight) {
     return (box.width * imageWidth * box.height * imageHeight).toInt();
   }

+ 23 - 2
mobile/lib/face/model/face.dart

@@ -1,6 +1,16 @@
 import "package:photos/face/model/detection.dart";
 import 'package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart';
 
+// FileInfo contains the image width and height of the image the face was detected in.
+class FileInfo {
+  int? imageWidth;
+  int? imageHeight;
+  FileInfo({
+    this.imageWidth,
+    this.imageHeight,
+  });
+}
+
 class Face {
   final int fileID;
   final String faceID;
@@ -8,6 +18,7 @@ class Face {
   Detection detection;
   final double score;
   final double blur;
+  FileInfo? fileInfo;
 
   bool get isBlurry => blur < kLaplacianThreshold;
 
@@ -15,14 +26,24 @@ class Face {
 
   bool get isHighQuality => (!isBlurry) && hasHighScore;
 
+  int get visibility => detection.getVisibilityScore();
+
+  int area({int? w, int? h}) {
+    return detection.getFaceArea(
+      fileInfo?.imageWidth ?? w ?? 0,
+      fileInfo?.imageHeight ?? h ?? 0,
+    );
+  }
+
   Face(
     this.faceID,
     this.fileID,
     this.embedding,
     this.score,
     this.detection,
-    this.blur,
-  );
+    this.blur, {
+    this.fileInfo,
+  });
 
   factory Face.empty(int fileID, {bool error = false}) {
     return Face(

+ 7 - 1
mobile/lib/services/machine_learning/face_ml/face_ml_service.dart

@@ -538,7 +538,13 @@ class FaceMlService {
                 ),
               );
             } else {
-              faces.addAll(fileMl.faceEmbedding.faces);
+              for (final f in fileMl.faceEmbedding.faces) {
+                f.fileInfo = FileInfo(
+                  imageHeight: fileMl.height,
+                  imageWidth: fileMl.width,
+                );
+                faces.add(f);
+              }
             }
             remoteFileIdToVersion[fileMl.fileID] = fileMl.faceEmbedding.version;
           }

+ 2 - 2
mobile/lib/ui/viewer/file_details/face_widget.dart

@@ -170,13 +170,13 @@ class _FaceWidgetState extends State<FaceWidget> {
                     ),
                   if (kDebugMode)
                     Text(
-                      'V: ${widget.face.detection.getVisibilityScore()}',
+                      'V: ${widget.face.visibility}',
                       style: Theme.of(context).textTheme.bodySmall,
                       maxLines: 1,
                     ),
                   if (kDebugMode)
                     Text(
-                      'A: ${widget.face.detection.getFaceArea(widget.file.width, widget.file.height)}',
+                      'A: ${widget.face.area()}',
                       style: Theme.of(context).textTheme.bodySmall,
                       maxLines: 1,
                     ),