Face selection is working pretty well
Signed-off-by: James Ketrenos <james_git@ketrenos.com>
This commit is contained in:
parent
c4a6b6dad4
commit
f1c1b79672
@ -49,10 +49,9 @@ div {
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
overflow-x: clip;
|
overflow-x: clip;
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
gap: 0.25rem;
|
gap: 0.25rem;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(8.5rem, auto));
|
grid-template-columns: repeat(auto-fill, minmax(4.25rem, auto));
|
||||||
}
|
}
|
||||||
|
|
||||||
.Face {
|
.Face {
|
||||||
@ -73,14 +72,29 @@ div {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Viewer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
.PhotoPanel {
|
.PhotoPanel {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Guess {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 0.5rem;
|
||||||
|
min-width: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
.Image .FaceBox {
|
.Image .FaceBox {
|
||||||
border: 1px solid red;
|
border: 1px solid red;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -94,9 +108,6 @@ div {
|
|||||||
.Image {
|
.Image {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
background-size: contain !important;
|
|
||||||
background-repeat: no-repeat no-repeat !important;
|
|
||||||
background-position: 50% 50% !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.PhotoPanel .FaceInfo {
|
.PhotoPanel .FaceInfo {
|
||||||
@ -112,6 +123,10 @@ div {
|
|||||||
margin-top: 0.25rem;
|
margin-top: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Identities .UnknownFace {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
.UnknownFace {
|
.UnknownFace {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -158,6 +173,11 @@ div {
|
|||||||
height: 10rem;
|
height: 10rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Identities .Face .Image {
|
||||||
|
min-width: 4rem;
|
||||||
|
min-height: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
.Face .Image {
|
.Face .Image {
|
||||||
position: relative;
|
position: relative;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@ -186,6 +206,13 @@ div {
|
|||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.Viewer .PhotoPanel img {
|
||||||
|
object-fit: contain;
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.Image img {
|
.Image img {
|
||||||
object-fit: cover; /* contain */
|
object-fit: cover; /* contain */
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -195,7 +222,7 @@ div {
|
|||||||
.Cluster .Faces {
|
.Cluster .Faces {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.25rem;
|
gap: 0.25rem;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
|
||||||
width: 100%;
|
width: 100%;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
@ -129,12 +129,7 @@ const Photo = ({ photoId, onFaceClick }: any) => {
|
|||||||
<div className="Image" ref={ref}>
|
<div className="Image" ref={ref}>
|
||||||
<img
|
<img
|
||||||
alt={image.filename}
|
alt={image.filename}
|
||||||
src={`${base}/../${image.path}thumbs/scaled/${image.filename}`.replace(/ /g, '%20')}
|
src={`${base}/../${image.path}thumbs/scaled/${image.filename}`.replace(/ /g, '%20')}/>
|
||||||
style={{
|
|
||||||
objectFit: 'contain',
|
|
||||||
width: '100%',
|
|
||||||
height: '100%'
|
|
||||||
}} />
|
|
||||||
{ faces }
|
{ faces }
|
||||||
</div>
|
</div>
|
||||||
<div className="ImageInfo">{
|
<div className="ImageInfo">{
|
||||||
@ -326,20 +321,6 @@ const Cluster = ({
|
|||||||
});
|
});
|
||||||
await res.json();
|
await res.json();
|
||||||
setIdentity({ ...identity, ...values });
|
setIdentity({ ...identity, ...values });
|
||||||
setIdentities(
|
|
||||||
[...identities]
|
|
||||||
.sort((A: IdentityData, B: IdentityData) => {
|
|
||||||
/* Sort the Unknown (-1) identity to the end */
|
|
||||||
if (A.identityId === -1) {
|
|
||||||
return +1;
|
|
||||||
}
|
|
||||||
if (B.identityId === -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* Otherwise sort alphabetically by displayName */
|
|
||||||
return A.displayName.localeCompare(B.displayName);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
@ -361,20 +342,6 @@ const Cluster = ({
|
|||||||
});
|
});
|
||||||
const created = await res.json();
|
const created = await res.json();
|
||||||
setIdentity(created);
|
setIdentity(created);
|
||||||
setIdentities(
|
|
||||||
[created, ...identities]
|
|
||||||
.sort((A: IdentityData, B: IdentityData) => {
|
|
||||||
/* Sort the Unknown (-1) identity to the end */
|
|
||||||
if (A.identityId === -1) {
|
|
||||||
return +1;
|
|
||||||
}
|
|
||||||
if (B.identityId === -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* Otherwise sort alphabetically by displayName */
|
|
||||||
return A.displayName.localeCompare(B.displayName);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
@ -537,6 +504,62 @@ const Button = ({ onClick, children }: any) => {
|
|||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
/* returns true if update to identities array occurred */
|
||||||
|
const updateIdentityReferences = (
|
||||||
|
identities: IdentityData[],
|
||||||
|
identity: IdentityData) : boolean => {
|
||||||
|
|
||||||
|
if (identity.identityId === -1) {
|
||||||
|
console.warn('Identity Unknown (-1) attempting to be updated');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetIndex = identities.findIndex(
|
||||||
|
x => x.identityId === identity.identityId);
|
||||||
|
if (targetIndex === -1) {
|
||||||
|
identities.push(identity);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const target = identities[targetIndex];
|
||||||
|
|
||||||
|
/*
|
||||||
|
IdentityData fields we check to make sure they are the same:
|
||||||
|
|
||||||
|
lastName: string,
|
||||||
|
middleName: string,
|
||||||
|
firstName: string,
|
||||||
|
displayName: string,
|
||||||
|
facesCount: number,
|
||||||
|
faceId: number
|
||||||
|
!identityId: number
|
||||||
|
!relatedFaces: FaceData[],
|
||||||
|
!descriptors: number[],
|
||||||
|
*/
|
||||||
|
|
||||||
|
let same = true;
|
||||||
|
|
||||||
|
[ 'lastName', 'firstName', 'middleName',
|
||||||
|
'displayName', 'faceId', 'facesCount', 'faceId' ]
|
||||||
|
.forEach((field: string) => {
|
||||||
|
same = same && (target as any)[field] === (identity as any)[field];
|
||||||
|
});
|
||||||
|
|
||||||
|
if (same) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
identities[targetIndex] = {
|
||||||
|
...identity,
|
||||||
|
relatedFaces: target.relatedFaces
|
||||||
|
};
|
||||||
|
|
||||||
|
/* relatedFaces is a list of references to identity */
|
||||||
|
identity.relatedFaces.forEach(face => {
|
||||||
|
face.identity = identity;
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const { identityId, faceId } = useParams();
|
const { identityId, faceId } = useParams();
|
||||||
@ -574,32 +597,28 @@ const App = () => {
|
|||||||
/* If the identity changes, update its entry in the identities list
|
/* If the identity changes, update its entry in the identities list
|
||||||
* NOTE: Blocks update to 'Unknown' (-1) fake identity */
|
* NOTE: Blocks update to 'Unknown' (-1) fake identity */
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!identity || identities.length === 0 || identity.identityId === -1) {
|
if (identity.identityId === -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (let key in identities) {
|
|
||||||
if (identities[key].identityId === identity.identityId) {
|
if (!updateIdentityReferences(identities, identity)) {
|
||||||
let same = true;
|
return;
|
||||||
[ 'displayName', 'firstName', 'lastName', 'middleName' ]
|
|
||||||
.forEach((field: string) => {
|
|
||||||
same = same
|
|
||||||
&& (identities[key] as any)[field] === (identity as any)[field];
|
|
||||||
});
|
|
||||||
if (!same) {
|
|
||||||
console.log(`Updating `, identity, identities[key]);
|
|
||||||
identities[key] = {
|
|
||||||
...identity,
|
|
||||||
relatedFaces: identities[key].relatedFaces
|
|
||||||
};
|
|
||||||
/* relatedFaces is a list of references to identity */
|
|
||||||
identity.relatedFaces.forEach(face => {
|
|
||||||
face.identity = identity;
|
|
||||||
});
|
|
||||||
setIdentities([...identities]);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setIdentities(
|
||||||
|
[...identities]
|
||||||
|
.sort((A: IdentityData, B: IdentityData) => {
|
||||||
|
/* Sort the Unknown (-1) identity to the end */
|
||||||
|
if (A.identityId === -1) {
|
||||||
|
return +1;
|
||||||
|
}
|
||||||
|
if (B.identityId === -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Otherwise sort alphabetically by displayName */
|
||||||
|
return A.displayName.localeCompare(B.displayName);
|
||||||
|
})
|
||||||
|
);
|
||||||
}, [identity, setIdentities, identities]);
|
}, [identity, setIdentities, identities]);
|
||||||
|
|
||||||
/* If the identity changes, scroll it into view in the Identities list */
|
/* If the identity changes, scroll it into view in the Identities list */
|
||||||
@ -720,7 +739,7 @@ const App = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const markSelectedIncorrectIdentity = async () => {
|
const removeFaceFromIdentity = async () => {
|
||||||
if (!identity) {
|
if (!identity) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -735,9 +754,9 @@ const App = () => {
|
|||||||
|
|
||||||
removeFacesFromIdentity(results.removed);
|
removeFacesFromIdentity(results.removed);
|
||||||
deselectAll();
|
deselectAll();
|
||||||
if (identity.faceId !== results.faceId) {
|
if (results.faceId !== undefined
|
||||||
setIdentity({...identity, ...{ faceId: results.faceId }});
|
&& identity.faceId !== results.faceId) {
|
||||||
setIdentities([...identities]);
|
setIdentity({...identity, faceId: results.faceId });
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
@ -778,7 +797,6 @@ const App = () => {
|
|||||||
target.faceId = results.faceId;
|
target.faceId = results.faceId;
|
||||||
}
|
}
|
||||||
deselectAll();
|
deselectAll();
|
||||||
setIdentities([...identities]);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
@ -798,7 +816,7 @@ const App = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const markSelectedNotFace = async () => {
|
const updateFasAsNotFace = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await window.fetch(
|
const res = await window.fetch(
|
||||||
`${base}/api/v1/faces`, {
|
`${base}/api/v1/faces`, {
|
||||||
@ -871,7 +889,8 @@ const App = () => {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (identity.identityId !== identityId) {
|
if (identity.identityId !== identityId
|
||||||
|
|| identity.facesCount === 0) {
|
||||||
[...document.querySelectorAll('.Cluster .Faces img')]
|
[...document.querySelectorAll('.Cluster .Faces img')]
|
||||||
.forEach((img: any) => {
|
.forEach((img: any) => {
|
||||||
img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
||||||
@ -901,8 +920,8 @@ const App = () => {
|
|||||||
<Button onClick={guessIdentity}>Guess</Button>
|
<Button onClick={guessIdentity}>Guess</Button>
|
||||||
</>}
|
</>}
|
||||||
{ selected.length !== 0 && <>
|
{ selected.length !== 0 && <>
|
||||||
<Button onClick={markSelectedIncorrectIdentity}>Remove</Button>
|
<Button onClick={removeFaceFromIdentity}>Remove</Button>
|
||||||
<Button onClick={markSelectedNotFace}>Not a face</Button>
|
<Button onClick={updateFasAsNotFace}>Not a face</Button>
|
||||||
<Button onClick={changeSelectedIdentity}>Change Identity</Button>
|
<Button onClick={changeSelectedIdentity}>Change Identity</Button>
|
||||||
<Button onClick={deselectAll}>Deselect All</Button>
|
<Button onClick={deselectAll}>Deselect All</Button>
|
||||||
</>}
|
</>}
|
||||||
@ -913,18 +932,17 @@ const App = () => {
|
|||||||
</Panel>
|
</Panel>
|
||||||
<PanelResizeHandle className="Resizer"/>
|
<PanelResizeHandle className="Resizer"/>
|
||||||
<Panel>
|
<Panel>
|
||||||
{image === 0 && <div style={{ margin: '1rem' }}>Select image to view</div>}
|
<div className="Viewer">
|
||||||
{image !== 0 && <Photo onFaceClick={onFaceClick} photoId={image}/> }
|
{image === 0 && <div style={{ margin: '1rem' }}>Select image to view</div>}
|
||||||
{guess !== undefined && guess.identity && <div
|
{image !== 0 && <Photo onFaceClick={onFaceClick} photoId={image}/> }
|
||||||
style={{
|
{guess !== undefined && guess.identity && <div
|
||||||
display: "flex",
|
className="Guess">
|
||||||
justifyContent: 'center',
|
<Face
|
||||||
alignItems: 'center'}}>
|
face={guess.identity.relatedFaces[0]}
|
||||||
<Face
|
onFaceClick={guessOnFaceClick}
|
||||||
face={guess.identity.relatedFaces[0]}
|
title={`${guess.identity.displayName} (${guess.distance})`}/>
|
||||||
onFaceClick={guessOnFaceClick}
|
</div> }
|
||||||
title={`${guess.identity.displayName} (${guess.distance})`}/>
|
</div>
|
||||||
</div> }
|
|
||||||
</Panel>
|
</Panel>
|
||||||
<PanelResizeHandle className="Resizer" />
|
<PanelResizeHandle className="Resizer" />
|
||||||
<Panel defaultSize={8.5} minSize={8.5} className="IdentitiesList">
|
<Panel defaultSize={8.5} minSize={8.5} className="IdentitiesList">
|
||||||
@ -932,7 +950,7 @@ const App = () => {
|
|||||||
Loading...
|
Loading...
|
||||||
</div> }
|
</div> }
|
||||||
{ loaded && <Identities
|
{ loaded && <Identities
|
||||||
{... { onFaceClick: identitiesOnFaceClick, identities }}/>
|
{...{ onFaceClick: identitiesOnFaceClick, identities }}/>
|
||||||
}
|
}
|
||||||
</Panel>
|
</Panel>
|
||||||
</PanelGroup>
|
</PanelGroup>
|
||||||
|
@ -9,7 +9,7 @@ require("../db/photos").then(function(db) {
|
|||||||
photoDB = db;
|
photoDB = db;
|
||||||
});
|
});
|
||||||
|
|
||||||
const MIN_DISTANCE_COMMIT = 0.0000001
|
const MIN_DISTANCE_COMMIT = 0.0001
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -258,15 +258,15 @@ router.get("/faces/guess/:faceId", async (req, res) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
router.put("/faces/remove/:id", async (req, res) => {
|
router.put("/faces/remove/:identityId", async (req, res) => {
|
||||||
console.log(`PUT ${req.url}`)
|
console.log(`PUT ${req.url}`)
|
||||||
if (!req.user.maintainer) {
|
if (!req.user.maintainer) {
|
||||||
console.warn(`${req.user.name} attempted to modify photos.`);
|
console.warn(`${req.user.name} attempted to modify photos.`);
|
||||||
return res.status(401).send({ message: "Unauthorized to modify photos." });
|
return res.status(401).send({ message: "Unauthorized to modify photos." });
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = parseInt(req.params.id);
|
const identityId = parseInt(req.params.identityId);
|
||||||
if (id != req.params.id) {
|
if (identityId != req.params.identityId) {
|
||||||
return res.status(400).send({ message: "Invalid identity id." });
|
return res.status(400).send({ message: "Invalid identity id." });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,30 +274,35 @@ router.put("/faces/remove/:id", async (req, res) => {
|
|||||||
return res.status(400).send({ message: "No faces supplied." });
|
return res.status(400).send({ message: "No faces supplied." });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert faces array to numbers and filter any non-numbers */
|
||||||
|
let faceIds = req.body.faces
|
||||||
|
.map(faceId => +faceId)
|
||||||
|
.filter(faceId => !isNaN(faceId));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await photoDB.sequelize.query(
|
await photoDB.sequelize.query(
|
||||||
"UPDATE faces SET identityId=null " +
|
"UPDATE faces SET identityId=null " +
|
||||||
"WHERE id IN (:faceIds)", {
|
"WHERE id IN (:faceIds)", {
|
||||||
replacements: {
|
replacements: {
|
||||||
identityId: id,
|
identityId,
|
||||||
faceIds: req.body.faces
|
faceIds
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const identity = {
|
const identity = {
|
||||||
identityId: id,
|
identityId,
|
||||||
faces: req.body.faces
|
removed: faceIds
|
||||||
};
|
};
|
||||||
identity.removed = identity.faces.map(id => +id);
|
|
||||||
/* If the primary faceId was removed, update the identity's faceId
|
/* If the primary faceId was removed, update the identity's faceId
|
||||||
* to a new faceId */
|
* to a new faceId */
|
||||||
const faceIds = await photoDB.sequelize.query(`
|
const identityFaceIds = await photoDB.sequelize.query(`
|
||||||
SELECT faceId FROM identities WHERE id=:identityId`, {
|
SELECT faceId AS identityFaceId FROM identities WHERE id=:identityId`, {
|
||||||
replacements: identity,
|
replacements: identity,
|
||||||
type: photoDB.Sequelize.QueryTypes.SELECT,
|
type: photoDB.Sequelize.QueryTypes.SELECT,
|
||||||
raw: true
|
raw: true
|
||||||
});
|
});
|
||||||
|
|
||||||
if (identity.removed.indexOf(faceIds[0]) !== -1) {
|
if (identity.removed.indexOf(identityFaceIds[0]) !== -1) {
|
||||||
const newFaceId = await photoDB.sequelize.query(`
|
const newFaceId = await photoDB.sequelize.query(`
|
||||||
SELECT faceId FROM faces WHERE identityId=:identityId
|
SELECT faceId FROM faces WHERE identityId=:identityId
|
||||||
ORDER BY distance ASC
|
ORDER BY distance ASC
|
||||||
@ -343,7 +348,7 @@ router.put("/faces/add/:id", async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!Array.isArray(req.body.faces) || req.body.faces.length == 0) {
|
if (!Array.isArray(req.body.faces) || req.body.faces.length == 0) {
|
||||||
return res.status(400).send("No faces supplied.");
|
return res.status(400).send({ message: "No faces supplied." });
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert faces array to numbers and filter any non-numbers */
|
/* Convert faces array to numbers and filter any non-numbers */
|
||||||
@ -442,8 +447,13 @@ router.put("/faces/add/:id", async (req, res) => {
|
|||||||
|
|
||||||
/* Do not block on this call finishing -- update can occur
|
/* Do not block on this call finishing -- update can occur
|
||||||
* in the background */
|
* in the background */
|
||||||
Promise.map([identity, ...tuples], identity => {
|
Promise.map([identity, ...tuples], (x, i) => {
|
||||||
updateIdentityFaces(identity);
|
try {
|
||||||
|
updateIdentityFaces(x);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(i, x);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}, {
|
}, {
|
||||||
concurrency: 1
|
concurrency: 1
|
||||||
});
|
});
|
||||||
@ -649,32 +659,37 @@ const updateIdentityFaces = async (identity) => {
|
|||||||
const t = await photoDB.sequelize.transaction();
|
const t = await photoDB.sequelize.transaction();
|
||||||
try {
|
try {
|
||||||
/* If the average position has not changed, then face distances should
|
/* If the average position has not changed, then face distances should
|
||||||
* not change either! */
|
* not change either!
|
||||||
await Promise.map(faces, async (face) => {
|
*
|
||||||
/* All the buffer are already arrays, so use the short-cut version */
|
* Do not update all the faces unless the centroid has moved a fair
|
||||||
const distance = Number
|
* amount */
|
||||||
.parseFloat(face.updatedDistance)
|
if (Math.abs(moved) > MIN_DISTANCE_COMMIT) {
|
||||||
.toFixed(4);
|
await Promise.map(faces, async (face) => {
|
||||||
|
/* All the buffer are already arrays, so use the short-cut version */
|
||||||
if (Math.abs(face.updatedDistance - face.distance)
|
const distance = Number
|
||||||
> MIN_DISTANCE_COMMIT) {
|
.parseFloat(face.updatedDistance)
|
||||||
console.log(
|
.toFixed(4);
|
||||||
`Updating face ${face.id} to ${round(distance, 2)} ` +
|
|
||||||
`(${distance - face.distance}) ` +
|
if (Math.abs(face.updatedDistance - face.distance)
|
||||||
`from identity ${identity.identityId} (${identity.displayName})`);
|
> MIN_DISTANCE_COMMIT) {
|
||||||
face.distance = face.updatedDistance;
|
console.log(
|
||||||
delete face.updatedDistance;
|
`Updating face ${face.id} to ${round(distance, 2)} ` +
|
||||||
await photoDB.sequelize.query(
|
`(${distance - face.distance}) ` +
|
||||||
'UPDATE faces SET distance=:distance WHERE id=:id', {
|
`from identity ${identity.identityId} (${identity.displayName})`);
|
||||||
replacements: face,
|
face.distance = face.updatedDistance;
|
||||||
transaction: t
|
delete face.updatedDistance;
|
||||||
}
|
await photoDB.sequelize.query(
|
||||||
);
|
'UPDATE faces SET distance=:distance WHERE id=:id', {
|
||||||
}
|
replacements: face,
|
||||||
}, {
|
transaction: t
|
||||||
concurrency: 5
|
}
|
||||||
});
|
);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
concurrency: 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let sql = '';
|
let sql = '';
|
||||||
/* If there is a new closestId, then set the faceId field */
|
/* If there is a new closestId, then set the faceId field */
|
||||||
if (closestId !== -1 && closestId !== identity.faceId) {
|
if (closestId !== -1 && closestId !== identity.faceId) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user