aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx2
-rw-r--r--src/client/views/search/FaceRecognitionHandler.tsx61
2 files changed, 26 insertions, 37 deletions
diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
index d1db19e43..46d90db86 100644
--- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
+++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
@@ -80,7 +80,6 @@ export class UniqueFaceView extends ObservableReactComponent<UniqueFaceProps> {
// assign the face in the image that's closest to the face collection to be the face that's assigned to the collection
if (face_match) {
- FaceRecognitionHandler.ImageDocAssociateUniqueFace(imgDoc, face_match, this._props.faceDoc);
FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, face_match, this._props.faceDoc);
}
}
@@ -109,7 +108,6 @@ export class UniqueFaceView extends ObservableReactComponent<UniqueFaceProps> {
*/
removeFaceImageFromUniqueFace = undoable((imgDoc: Doc) => {
FaceRecognitionHandler.UniqueFaceRemoveFaceImage(imgDoc, this._props.faceDoc);
- FaceRecognitionHandler.ImageDocDisassociateUniqueFace(imgDoc, this._props.faceDoc);
}, 'remove doc from face');
render() {
diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx
index 487c35d90..f00c3fdf1 100644
--- a/src/client/views/search/FaceRecognitionHandler.tsx
+++ b/src/client/views/search/FaceRecognitionHandler.tsx
@@ -16,8 +16,7 @@ import { DocumentManager } from '../../util/DocumentManager';
* collection along with the numerical representation of the face, its face descriptor.
*
* Image Doc's that are added to one or more face collection Docs will be given these metadata fields:
- * <image data field>_Face<N> - a numerical representation of the Nth face found in the image
- * <image data field>_Faces - a list of all the numerical face representations found in the image. (TODO: this is inelegant as it duplicates each Face<N>)
+ * <image data field>_faceDescriptors - a list of all the numerical face representations found in the image.
*
* unique face Doc's are created for each person identified and are stored in the Dashboard's uniqueFaces field
*
@@ -31,20 +30,34 @@ export class FaceRecognitionHandler {
private _loadedModels: boolean = false;
private _pendingLoadDocs: Doc[] = [];
- private static imgDocFaceField = (imgDoc: Doc, faceDoc: Doc) => `${Doc.LayoutFieldKey(imgDoc)}_${FaceRecognitionHandler.UniqueFaceLabel(faceDoc)}`;
+
+ /**
+ * return the metadata field name where unique face Docs are stored
+ * @param imgDoc image with faces
+ * @returns name of field
+ */
+ private static ImageDocFaceField = (imgDoc: Doc) => `${Doc.LayoutFieldKey(imgDoc)}_faces`;
+
+ /**
+ * Returns an array of faceDocs for each face recognized in the image
+ * @param imgDoc image with faces
+ * @returns faceDoc array
+ */
+ private static ImageDocFaces = (imgDoc: Doc) => DocListCast(imgDoc[`${Doc.LayoutFieldKey(imgDoc)}_faces`]);
+
/**
* initializes an image with an empty list of face descriptors
* @param imgDoc image to initialize
*/
private static initImageDocFaceDescriptors = (imgDoc: Doc) => {
- imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_Faces`] = new List<List<number>>();
+ imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_faceDescriptors`] = new List<List<number>>();
};
/**
* returns the face descriptors for each face found on an image Doc
* @param imgDoc
* @returns list of face descriptors
*/
- public static ImageDocFaceDescriptors = (imgDoc: Doc) => imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_Faces`] as List<List<number>>;
+ public static ImageDocFaceDescriptors = (imgDoc: Doc) => imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_faceDescriptors`] as List<List<number>>;
/**
* Adds a face descriptor for a face found in an image
@@ -52,34 +65,11 @@ export class FaceRecognitionHandler {
* @param faceDescriptor descriptor of a face
*/
public static ImageDocAddFaceDescriptor = (imgDoc: Doc, faceDescriptor: List<number>) => {
- Cast(imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_Faces`], listSpec('number'), null).push(faceDescriptor as unknown as number);
+ Cast(imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_faceDescriptors`], listSpec('number'), null).push(faceDescriptor as unknown as number);
};
- /**
- * Adds metadata to an image Doc associating it to a unique face that corresponds to a face found in the image
- * @param imgDoc image Doc containing faces
- * @param faceDescriptor descriptor for the face
- * @param faceDoc unique face
- */
- public static ImageDocAssociateUniqueFace = (imgDoc: Doc, faceDescriptor: List<number>, faceDoc: Doc) => {
- const faceFieldKey = FaceRecognitionHandler.imgDocFaceField(imgDoc, faceDoc);
- if (imgDoc[DocData][faceFieldKey]) {
- Cast(imgDoc[DocData][faceFieldKey], listSpec('number'), null).push(faceDescriptor as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that
- } else {
- imgDoc[DocData][faceFieldKey] = new List<List<number>>([faceDescriptor]);
- }
- };
/**
- * Removes metadata from an image Doc to deassociate it from a unique face
- * @param imgDoc image Doc containing faces
- * @param faceDoc unique face
- */
- public static ImageDocDisassociateUniqueFace = (imgDoc: Doc, faceDoc: Doc) => {
- const faceFieldKey = FaceRecognitionHandler.imgDocFaceField(imgDoc, faceDoc);
- imgDoc[DocData][faceFieldKey] = undefined;
- };
- /**
* returns a list of all face collection Docs on the current dashboard
* @returns face collection Doc list
*/
@@ -121,17 +111,19 @@ export class FaceRecognitionHandler {
public static UniqueFaceAddFaceImage = (img: Doc, faceDescriptor: List<number>, faceDoc: Doc) => {
Doc.AddDocToList(faceDoc, 'face_images', img);
Cast(faceDoc.face_descriptors, listSpec('number'), null).push(faceDescriptor as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that
+ Doc.AddDocToList(img[DocData], FaceRecognitionHandler.ImageDocFaceField(img), faceDoc);
};
/**
* Removes a face from a unique Face Doc, and updates the unique face's set of face image descriptors
- * @param imgDoc - image with faces to remove
+ * @param img - image with faces to remove
* @param faceDoc - unique face Doc
*/
- public static UniqueFaceRemoveFaceImage = (imgDoc: Doc, faceDoc: Doc) => {
- Doc.RemoveDocFromList(faceDoc[DocData], 'face_images', imgDoc);
- // TODO: remove face descriptor from images' list of face descriptors (below doesn't work)
- // faceDoc[DocData].face_descriptors = new List<List<number>>(FaceRecognitionHandler.UniqueFaceDescriptors(faceDoc).filter(fd => !(imgDoc[DocData][FaceRecognitionHandler.imgDocFaceField(imgDoc, faceDoc)] as List<List<number>>).includes(fd)));
+ public static UniqueFaceRemoveFaceImage = (img: Doc, faceDoc: Doc) => {
+ Doc.RemoveDocFromList(faceDoc[DocData], 'face_images', img);
+ const descriptorsEqual = (a:List<number>, b:List<number>) => a === b ? true : a.length === b.length ? a.every((element, index) => element === b[index]) : false;
+ faceDoc[DocData].face_descriptors = new List<List<number>>(FaceRecognitionHandler.UniqueFaceDescriptors(faceDoc).filter(fd => !FaceRecognitionHandler.ImageDocFaceDescriptors(img).some(desc => descriptorsEqual(fd, desc))));
+ Doc.RemoveDocFromList(img[DocData], FaceRecognitionHandler.ImageDocFaceField(img), faceDoc);
};
constructor() {
@@ -211,7 +203,6 @@ export class FaceRecognitionHandler {
const matchedUniqueFace = this.findMatchingFaceDoc(fd.descriptor) ?? this.createUniqueFaceDoc(Doc.ActiveDashboard);
// Add image to unique face's image collection, and assign image metadata referencing unique face
FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, faceDescriptor, matchedUniqueFace);
- FaceRecognitionHandler.ImageDocAssociateUniqueFace(imgDoc, faceDescriptor, matchedUniqueFace);
// save the descriptor for the image's list of faces
FaceRecognitionHandler.ImageDocAddFaceDescriptor(imgDoc, faceDescriptor);
}