Preview
This commit is contained in:
@@ -4,10 +4,9 @@ import {
|
||||
faceCrop,
|
||||
wipClusterDebugPageContents,
|
||||
type ClusterDebugPageContents,
|
||||
type FaceFileNeighbour,
|
||||
type FaceFileNeighbours,
|
||||
type ClusterPreviewFaceWF,
|
||||
type ClusterPreviewWF,
|
||||
} from "@/new/photos/services/ml";
|
||||
import type { Face } from "@/new/photos/services/ml/face";
|
||||
import {
|
||||
FlexWrapper,
|
||||
FluidContainer,
|
||||
@@ -15,7 +14,7 @@ import {
|
||||
} from "@ente/shared/components/Container";
|
||||
import EnteSpinner from "@ente/shared/components/EnteSpinner";
|
||||
import BackButton from "@mui/icons-material/ArrowBackOutlined";
|
||||
import { Box, IconButton, styled, Typography } from "@mui/material";
|
||||
import { Box, IconButton, Stack, styled, Typography } from "@mui/material";
|
||||
import { useRouter } from "next/router";
|
||||
import { AppContext } from "pages/_app";
|
||||
import React, { useContext, useEffect, useMemo, useRef, useState } from "react";
|
||||
@@ -53,8 +52,9 @@ export default function ClusterDebug() {
|
||||
{`${clusterRes.clusters.length} clusters`}
|
||||
</Typography>
|
||||
<Typography variant="small" color="text.muted">
|
||||
Showing only top 20 and bottom 10 clusters (and only up to 50 faces in
|
||||
each, sorted by cosine distance to highest scoring face in the cluster).
|
||||
Showing only top 20 and bottom 10 clusters (and only up to 50
|
||||
faces in each, sorted by cosine distance to highest scoring face
|
||||
in the cluster).
|
||||
</Typography>
|
||||
<hr />
|
||||
<Container>
|
||||
@@ -112,7 +112,7 @@ const ClusterPhotoList: React.FC<ClusterPhotoListProps> = ({
|
||||
width,
|
||||
clusterRes,
|
||||
}) => {
|
||||
const { faceFNs, clusterIDForFaceID } = clusterRes;
|
||||
const { clusterPreviewWFs, clusterIDForFaceID } = clusterRes;
|
||||
const [itemList, setItemList] = useState<ItemListItem[]>([]);
|
||||
const listRef = useRef(null);
|
||||
|
||||
@@ -125,8 +125,8 @@ const ClusterPhotoList: React.FC<ClusterPhotoListProps> = ({
|
||||
const listItemHeight = 120 * shrinkRatio + 24 + 4;
|
||||
|
||||
useEffect(() => {
|
||||
setItemList(itemListFromFaceFNs(faceFNs, columns));
|
||||
}, [columns, faceFNs]);
|
||||
setItemList(itemListFromClusterPreviewWFs(clusterPreviewWFs, columns));
|
||||
}, [columns, clusterPreviewWFs]);
|
||||
|
||||
useEffect(() => {
|
||||
listRef.current?.resetAfterIndex(0);
|
||||
@@ -138,7 +138,7 @@ const ClusterPhotoList: React.FC<ClusterPhotoListProps> = ({
|
||||
const generateKey = (i: number) =>
|
||||
Array.isArray(itemList[i])
|
||||
? `${itemList[i][0].enteFile.id}/${itemList[i][0].face.faceID}-${itemList[i].slice(-1)[0].enteFile.id}/${itemList[i].slice(-1)[0].face.faceID}-${i}`
|
||||
: `${itemList[i].faceID}-${i}`;
|
||||
: `${itemList[i]}-${i}`;
|
||||
|
||||
return (
|
||||
<VariableSizeList
|
||||
@@ -163,13 +163,13 @@ const ClusterPhotoList: React.FC<ClusterPhotoListProps> = ({
|
||||
>
|
||||
{!Array.isArray(item) ? (
|
||||
<LabelContainer span={columns}>
|
||||
{`score ${item.score.toFixed(2)} blur ${item.blur.toFixed(0)}`}
|
||||
{`cluster size ${item.toFixed(2)}`}
|
||||
</LabelContainer>
|
||||
) : (
|
||||
item.map((faceFN, i) => (
|
||||
item.map((faceWF, i) => (
|
||||
<FaceItem
|
||||
key={i.toString()}
|
||||
{...{ faceFN, clusterIDForFaceID }}
|
||||
{...{ faceWF, clusterIDForFaceID }}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
@@ -181,19 +181,20 @@ const ClusterPhotoList: React.FC<ClusterPhotoListProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
type ItemListItem = Face | FaceFileNeighbour[];
|
||||
// type ItemListItem = Face | FaceFileNeighbour[];
|
||||
type ItemListItem = number | ClusterPreviewFaceWF[];
|
||||
|
||||
const itemListFromFaceFNs = (
|
||||
faceFNs: FaceFileNeighbours[],
|
||||
const itemListFromClusterPreviewWFs = (
|
||||
clusterPreviewWFs: ClusterPreviewWF[],
|
||||
columns: number,
|
||||
) => {
|
||||
const result: ItemListItem[] = [];
|
||||
for (let index = 0; index < faceFNs.length; index++) {
|
||||
const { face, neighbours } = faceFNs[index];
|
||||
result.push(face);
|
||||
for (let index = 0; index < clusterPreviewWFs.length; index++) {
|
||||
const { clusterSize, faces } = clusterPreviewWFs[index];
|
||||
result.push(clusterSize);
|
||||
let lastIndex = 0;
|
||||
while (lastIndex < neighbours.length) {
|
||||
result.push(neighbours.slice(lastIndex, lastIndex + columns));
|
||||
while (lastIndex < faces.length) {
|
||||
result.push(faces.slice(lastIndex, lastIndex + columns));
|
||||
lastIndex += columns;
|
||||
}
|
||||
}
|
||||
@@ -210,12 +211,12 @@ const getShrinkRatio = (width: number, columns: number) =>
|
||||
(columns * 120);
|
||||
|
||||
interface FaceItemProps {
|
||||
faceFN: FaceFileNeighbour;
|
||||
faceWF: ClusterPreviewFaceWF;
|
||||
clusterIDForFaceID: Map<string, string>;
|
||||
}
|
||||
|
||||
const FaceItem: React.FC<FaceItemProps> = ({ faceFN, clusterIDForFaceID }) => {
|
||||
const { face, enteFile, cosineSimilarity } = faceFN;
|
||||
const FaceItem: React.FC<FaceItemProps> = ({ faceWF, clusterIDForFaceID }) => {
|
||||
const { face, enteFile, cosineSimilarity } = faceWF;
|
||||
const { faceID } = face;
|
||||
|
||||
const [objectURL, setObjectURL] = useState<string | undefined>();
|
||||
@@ -252,9 +253,15 @@ const FaceItem: React.FC<FaceItemProps> = ({ faceFN, clusterIDForFaceID }) => {
|
||||
src={objectURL}
|
||||
/>
|
||||
)}
|
||||
<Typography variant="small" color="text.muted" textAlign="right">
|
||||
{cosineSimilarity.toFixed(2)}
|
||||
</Typography>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography variant="small" color="text.muted">
|
||||
{`${face.blur.toFixed(0)} blr`}
|
||||
</Typography>
|
||||
|
||||
<Typography variant="small" color="text.muted">
|
||||
{`cos ${cosineSimilarity.toFixed(2)}`}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</FaceChip>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -352,7 +352,10 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => {
|
||||
const t = Date.now();
|
||||
|
||||
// A flattened array of faces.
|
||||
const faces0 = [...enumerateFaces(faceIndexes)];
|
||||
// TODO-Cluster ad-hoc filtering and slicing
|
||||
const faces0 = [...enumerateFaces(faceIndexes)]
|
||||
.filter((f) => f.blur > 50)
|
||||
.slice(0, 1000);
|
||||
// TODO-Cluster testing code, can be removed once done
|
||||
const faces = Array(1)
|
||||
.fill(0)
|
||||
@@ -433,7 +436,7 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => {
|
||||
// Use a higher cosine similarity threshold if either of the two
|
||||
// faces are blurry.
|
||||
const threshold =
|
||||
existingFace.blur < 100 || newFace.blur < 100 ? 0.84 : 0.7;
|
||||
existingFace.blur < 100 || newFace.blur < 100 ? 0.9 : 0.7;
|
||||
if (csim > threshold && csim > nnCosineSimilarity) {
|
||||
nnCluster = existingCluster;
|
||||
nnCosineSimilarity = csim;
|
||||
|
||||
@@ -366,14 +366,15 @@ export interface ClusterPreviewWF {
|
||||
faces: ClusterPreviewFaceWF[];
|
||||
}
|
||||
|
||||
interface ClusterPreviewFaceWF {
|
||||
export interface ClusterPreviewFaceWF {
|
||||
face: Face;
|
||||
enteFile: EnteFile;
|
||||
cosineSimilarity: number;
|
||||
}
|
||||
|
||||
export interface ClusterDebugPageContents {
|
||||
faceFNs: FaceFileNeighbours[];
|
||||
// faceFNs: FaceFileNeighbours[];
|
||||
clusterPreviewWFs: ClusterPreviewWF[];
|
||||
clusters: FaceCluster[];
|
||||
clusterIDForFaceID: Map<string, string>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user