This commit is contained in:
Manav Rathi 2024-05-14 14:05:04 +05:30
parent 8efe47cffb
commit 77bacc518c
No known key found for this signature in database
4 changed files with 85 additions and 93 deletions

View file

@ -5,15 +5,14 @@ import {
Face,
MLSyncContext,
MLSyncFileContext,
type FaceAlignment,
type Versioned,
} from "services/ml/types";
import { imageBitmapToBlob } from "utils/image";
import { imageBitmapToBlob, warpAffineFloat32List } from "utils/image";
import {
areFaceIdsSame,
extractFaceImagesToFloat32,
getFaceId,
getLocalFile,
getOriginalImageBitmap,
isDifferentOrOld,
} from "utils/machineLearning";
import mlIDbStorage from "utils/storage/mlIDbStorage";
import ReaderService from "./readerService";
@ -304,3 +303,58 @@ class FaceService {
}
export default new FaceService();
export function areFaceIdsSame(ofFaces: Array<Face>, toFaces: Array<Face>) {
if (
(ofFaces === null || ofFaces === undefined) &&
(toFaces === null || toFaces === undefined)
) {
return true;
}
return primitiveArrayEquals(
ofFaces?.map((f) => f.id),
toFaces?.map((f) => f.id),
);
}
function primitiveArrayEquals(a, b) {
return (
Array.isArray(a) &&
Array.isArray(b) &&
a.length === b.length &&
a.every((val, index) => val === b[index])
);
}
export function isDifferentOrOld(
method: Versioned<string>,
thanMethod: Versioned<string>,
) {
return (
!method ||
method.value !== thanMethod.value ||
method.version < thanMethod.version
);
}
async function extractFaceImagesToFloat32(
faceAlignments: Array<FaceAlignment>,
faceSize: number,
image: ImageBitmap,
): Promise<Float32Array> {
const faceData = new Float32Array(
faceAlignments.length * faceSize * faceSize * 3,
);
for (let i = 0; i < faceAlignments.length; i++) {
const alignedFace = faceAlignments[i];
const faceDataOffset = i * faceSize * faceSize * 3;
warpAffineFloat32List(
image,
alignedFace,
faceSize,
faceData,
faceDataOffset,
);
}
return faceData;
}

View file

@ -1,14 +1,8 @@
import log from "@/next/log";
import { Face, MLSyncContext, Person } from "services/ml/types";
import {
findFirstIfSorted,
getAllFacesFromMap,
getLocalFile,
getOriginalImageBitmap,
isDifferentOrOld,
} from "utils/machineLearning";
import { getLocalFile, getOriginalImageBitmap } from "utils/machineLearning";
import mlIDbStorage from "utils/storage/mlIDbStorage";
import FaceService from "./faceService";
import FaceService, { isDifferentOrOld } from "./faceService";
class PeopleService {
async syncPeopleIndex(syncContext: MLSyncContext) {
@ -92,3 +86,28 @@ class PeopleService {
}
export default new PeopleService();
function findFirstIfSorted<T>(
elements: Array<T>,
comparator: (a: T, b: T) => number,
) {
if (!elements || elements.length < 1) {
return;
}
let first = elements[0];
for (let i = 1; i < elements.length; i++) {
const comp = comparator(elements[i], first);
if (comp < 0) {
first = elements[i];
}
}
return first;
}
function getAllFacesFromMap(allFacesMap: Map<number, Array<Face>>) {
const allFaces = [...allFacesMap.values()].flat();
return allFaces;
}

View file

@ -11,46 +11,18 @@ import {
FaceAlignment,
MlFileData,
Person,
Versioned,
} from "services/ml/types";
import { EnteFile } from "types/file";
import { getRenderableImage } from "utils/file";
import { clamp, warpAffineFloat32List } from "utils/image";
import mlIDbStorage from "utils/storage/mlIDbStorage";
export function getAllFacesFromMap(allFacesMap: Map<number, Array<Face>>) {
const allFaces = [...allFacesMap.values()].flat();
return allFaces;
}
export async function getLocalFile(fileId: number) {
const localFiles = await getLocalFiles();
return localFiles.find((f) => f.id === fileId);
}
export async function extractFaceImagesToFloat32(
faceAlignments: Array<FaceAlignment>,
faceSize: number,
image: ImageBitmap,
): Promise<Float32Array> {
const faceData = new Float32Array(
faceAlignments.length * faceSize * faceSize * 3,
);
for (let i = 0; i < faceAlignments.length; i++) {
const alignedFace = faceAlignments[i];
const faceDataOffset = i * faceSize * faceSize * 3;
warpAffineFloat32List(
image,
alignedFace,
faceSize,
faceData,
faceDataOffset,
);
}
return faceData;
}
export function getFaceId(detectedFace: DetectedFace, imageDims: Dimensions) {
const xMin = clamp(
detectedFace.detection.box.x / imageDims.width,
@ -192,56 +164,3 @@ export async function getAllPeople(limit: number = undefined) {
.sort((p1, p2) => p2.files.length - p1.files.length)
.slice(0, limit);
}
export function findFirstIfSorted<T>(
elements: Array<T>,
comparator: (a: T, b: T) => number,
) {
if (!elements || elements.length < 1) {
return;
}
let first = elements[0];
for (let i = 1; i < elements.length; i++) {
const comp = comparator(elements[i], first);
if (comp < 0) {
first = elements[i];
}
}
return first;
}
export function isDifferentOrOld(
method: Versioned<string>,
thanMethod: Versioned<string>,
) {
return (
!method ||
method.value !== thanMethod.value ||
method.version < thanMethod.version
);
}
function primitiveArrayEquals(a, b) {
return (
Array.isArray(a) &&
Array.isArray(b) &&
a.length === b.length &&
a.every((val, index) => val === b[index])
);
}
export function areFaceIdsSame(ofFaces: Array<Face>, toFaces: Array<Face>) {
if (
(ofFaces === null || ofFaces === undefined) &&
(toFaces === null || toFaces === undefined)
) {
return true;
}
return primitiveArrayEquals(
ofFaces?.map((f) => f.id),
toFaces?.map((f) => f.id),
);
}