Continuing development...
Signed-off-by: James P. Ketrenos <james.p.ketrenos@intel.com>
This commit is contained in:
parent
99db385686
commit
40b3a0d819
@ -85,6 +85,13 @@ div {
|
|||||||
background-position: 50% 50% !important;
|
background-position: 50% 50% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.UnknownFace {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 4rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
.IdentityForm {
|
.IdentityForm {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
@ -116,6 +123,8 @@ div {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
width: 8rem;
|
width: 8rem;
|
||||||
height: 8rem;
|
height: 8rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Cluster {
|
.Cluster {
|
||||||
|
@ -123,14 +123,12 @@ const onFaceMouseEnter = (e: any, face: FaceData) => {
|
|||||||
const faceId = face.faceId;
|
const faceId = face.faceId;
|
||||||
const els = [...document.querySelectorAll(`[data-face-id="${faceId}"]`)];
|
const els = [...document.querySelectorAll(`[data-face-id="${faceId}"]`)];
|
||||||
|
|
||||||
if (face.identity) {
|
const identityId = face.identityId;
|
||||||
const identityId = face.identity.identityId;
|
els.splice(0, 0,
|
||||||
els.splice(0, 0,
|
...document.querySelectorAll(
|
||||||
...document.querySelectorAll(
|
`.Identities [data-identity-id="${identityId}"]`),
|
||||||
`.Identities [data-identity-id="${identityId}"]`),
|
...document.querySelectorAll(
|
||||||
...document.querySelectorAll(
|
`.Photo [data-identity-id="${identityId}"]`));
|
||||||
`.Photo [data-identity-id="${identityId}"]`));
|
|
||||||
}
|
|
||||||
|
|
||||||
els.forEach(el => {
|
els.forEach(el => {
|
||||||
el.classList.add('Active');
|
el.classList.add('Active');
|
||||||
@ -141,11 +139,9 @@ const onFaceMouseLeave = (e: any, face: FaceData) => {
|
|||||||
const faceId = face.faceId;
|
const faceId = face.faceId;
|
||||||
const els = [...document.querySelectorAll(`[data-face-id="${faceId}"]`)];
|
const els = [...document.querySelectorAll(`[data-face-id="${faceId}"]`)];
|
||||||
|
|
||||||
if (face.identity) {
|
const identityId = face.identityId;
|
||||||
const identityId = face.identity.identityId;
|
els.splice(0, 0,
|
||||||
els.splice(0, 0,
|
...document.querySelectorAll(`[data-identity-id="${identityId}"]`));
|
||||||
...document.querySelectorAll(`[data-identity-id="${identityId}"]`));
|
|
||||||
}
|
|
||||||
|
|
||||||
els.forEach(el => {
|
els.forEach(el => {
|
||||||
el.classList.remove('Active');
|
el.classList.remove('Active');
|
||||||
@ -155,6 +151,14 @@ const onFaceMouseLeave = (e: any, face: FaceData) => {
|
|||||||
const Face = ({ face, onFaceClick, title, ...rest }: any) => {
|
const Face = ({ face, onFaceClick, title, ...rest }: any) => {
|
||||||
const faceId = face.faceId;
|
const faceId = face.faceId;
|
||||||
const idPath = String(faceId % 100).padStart(2, '0');
|
const idPath = String(faceId % 100).padStart(2, '0');
|
||||||
|
const img = faceId === -1
|
||||||
|
? <div className='UnknownFace'>?</div>
|
||||||
|
: <img src={`${base}/../faces/${idPath}/${faceId}.jpg`}
|
||||||
|
style={{
|
||||||
|
objectFit: 'contain',
|
||||||
|
width: '100%',
|
||||||
|
height: '100%'
|
||||||
|
}} />;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-face-id={face.faceId}
|
data-face-id={face.faceId}
|
||||||
@ -165,12 +169,7 @@ const Face = ({ face, onFaceClick, title, ...rest }: any) => {
|
|||||||
onMouseLeave={(e) => { onFaceMouseLeave(e, face) }}
|
onMouseLeave={(e) => { onFaceMouseLeave(e, face) }}
|
||||||
className='Face'>
|
className='Face'>
|
||||||
<div className='Image'>
|
<div className='Image'>
|
||||||
<img src={`${base}/../faces/${idPath}/${faceId}.jpg`}
|
{ img }
|
||||||
style={{
|
|
||||||
objectFit: 'contain',
|
|
||||||
width: '100%',
|
|
||||||
height: '100%'
|
|
||||||
}}/>
|
|
||||||
<div className='Title'>{title}</div>
|
<div className='Title'>{title}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -185,8 +184,6 @@ type ClusterProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Cluster = ({ identity, setIdentity, setImage, setSelected }: ClusterProps) => {
|
const Cluster = ({ identity, setIdentity, setImage, setSelected }: ClusterProps) => {
|
||||||
console.log(identity);
|
|
||||||
|
|
||||||
const relatedFacesJSX = useMemo(() => {
|
const relatedFacesJSX = useMemo(() => {
|
||||||
const faceClicked = async (e: any, face: FaceData) => {
|
const faceClicked = async (e: any, face: FaceData) => {
|
||||||
if (!identity) {
|
if (!identity) {
|
||||||
@ -267,13 +264,37 @@ const Cluster = ({ identity, setIdentity, setImage, setSelected }: ClusterProps)
|
|||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify(filtered)
|
body: JSON.stringify(filtered)
|
||||||
});
|
});
|
||||||
const data = await res.json();
|
const updated = await res.json();
|
||||||
setIdentity({ ...identity });
|
setIdentity({ ...identity });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const createIdentity = async () => {
|
||||||
|
try {
|
||||||
|
const validFields = [
|
||||||
|
'id', 'displayName', 'firstName', 'lastName', 'middleName'];
|
||||||
|
const filtered: any = Object.assign({}, identity);
|
||||||
|
for (let key in filtered) {
|
||||||
|
if (validFields.indexOf(key) == -1) {
|
||||||
|
delete filtered[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const res = await window.fetch(
|
||||||
|
`${base}/api/v1/identities/`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(filtered)
|
||||||
|
});
|
||||||
|
const created = await res.json();
|
||||||
|
setIdentity(created);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
if (identity === undefined) {
|
if (identity === undefined) {
|
||||||
return (<div className='Cluster'>
|
return (<div className='Cluster'>
|
||||||
Select identity to load.
|
Select identity to load.
|
||||||
@ -300,6 +321,7 @@ const Cluster = ({ identity, setIdentity, setImage, setSelected }: ClusterProps)
|
|||||||
value={identity.displayName}
|
value={identity.displayName}
|
||||||
onChange={displayNameChanged} />
|
onChange={displayNameChanged} />
|
||||||
</form>
|
</form>
|
||||||
|
<Button onClick={createIdentity}>Create</Button>
|
||||||
<Button onClick={updateIdentity}>Update</Button>
|
<Button onClick={updateIdentity}>Update</Button>
|
||||||
</div>
|
</div>
|
||||||
<div>Faces: {identity.relatedFaces.length}</div>
|
<div>Faces: {identity.relatedFaces.length}</div>
|
||||||
@ -313,10 +335,10 @@ const Cluster = ({ identity, setIdentity, setImage, setSelected }: ClusterProps)
|
|||||||
type FaceData = {
|
type FaceData = {
|
||||||
faceId: number,
|
faceId: number,
|
||||||
photoId: number,
|
photoId: number,
|
||||||
lastName: string,
|
/* lastName: string,
|
||||||
firstName: string,
|
firstName: string,
|
||||||
middleName: string,
|
middleName: string,
|
||||||
displayName: string,
|
displayName: string,*/
|
||||||
identity: IdentityData,
|
identity: IdentityData,
|
||||||
identityId: number,
|
identityId: number,
|
||||||
distance: number,
|
distance: number,
|
||||||
@ -500,11 +522,7 @@ const App = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFaceClick = (e: any, face: FaceData) => {
|
const onFaceClick = (e: any, face: FaceData) => {
|
||||||
if (!face.identity) {
|
const identityId = face.identityId;
|
||||||
console.log(`Face ${face.faceId} does not have an Identity`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const identityId = face.identity.identityId;
|
|
||||||
const faceId = face.faceId;
|
const faceId = face.faceId;
|
||||||
console.log(`onFaceClick`, { faceId, identityId});
|
console.log(`onFaceClick`, { faceId, identityId});
|
||||||
const faces = [
|
const faces = [
|
||||||
@ -516,7 +534,7 @@ const App = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const identitiesOnFaceClick = (e: any, face: FaceData) => {
|
const identitiesOnFaceClick = (e: any, face: FaceData) => {
|
||||||
const identityId = face.identity.identityId;
|
const identityId = face.identityId;
|
||||||
loadIdentity(identityId);
|
loadIdentity(identityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
# DEVELOPMENT -- use npm development server on port 3000 (entrypoint.sh)
|
# DEVELOPMENT -- use npm development server on port 3000 (entrypoint.sh)
|
||||||
location /identities/api/v1/ {
|
location /identities/api/v1/ {
|
||||||
rewrite ^/identities/api/v1/(.*)$ https://${host}/api/v1/$1 permanent;
|
rewrite ^/identities/api/v1/(.*)$ /api/v1/$1 break;
|
||||||
|
proxy_pass https://localhost/;
|
||||||
|
proxy_redirect off;
|
||||||
|
proxy_set_header Host $host;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /identities {
|
location /identities {
|
||||||
|
@ -11,6 +11,109 @@ require("../db/photos").then(function(db) {
|
|||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
|
const addOrUpdateIdentity = async(id, {
|
||||||
|
displayName,
|
||||||
|
firstName,
|
||||||
|
lastName,
|
||||||
|
middleName
|
||||||
|
}, res) => {
|
||||||
|
|
||||||
|
if (displayName === undefined
|
||||||
|
|| firstName === undefined
|
||||||
|
|| lastName === undefined
|
||||||
|
|| middleName === undefined) {
|
||||||
|
res.status(400).send({ message: `Missing fields` });
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const identity = {
|
||||||
|
displayName,
|
||||||
|
firstName,
|
||||||
|
lastName,
|
||||||
|
middleName,
|
||||||
|
id
|
||||||
|
};
|
||||||
|
|
||||||
|
if (id === -1 || !id) {
|
||||||
|
const [results, { lastId }] = await photoDB.sequelize.query(
|
||||||
|
`INSERT INTO identities ` +
|
||||||
|
'(displayName,firstName,lastName,middleName)' +
|
||||||
|
'VALUES(:displayName,:firstName,:lastName,:middleName)', {
|
||||||
|
replacements: identity
|
||||||
|
});
|
||||||
|
identity.id = lastId;
|
||||||
|
} else {
|
||||||
|
await photoDB.sequelize.query(
|
||||||
|
`UPDATE identities ` +
|
||||||
|
'SET ' +
|
||||||
|
'displayName=:displayName, ' +
|
||||||
|
'firstName=:firstName, ' +
|
||||||
|
'lastName=:lastName, ' +
|
||||||
|
'middleName=:middleName ' +
|
||||||
|
'WHERE id=:id', {
|
||||||
|
replacements: identity
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return identity;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const populateRelatedFaces = async (identity, count) => {
|
||||||
|
let limit = '';
|
||||||
|
if (count) {
|
||||||
|
limit = ` LIMIT ${count} `;
|
||||||
|
}
|
||||||
|
/* If this is a new identity, no faces are being requested --
|
||||||
|
* just return the empty 'unknown face'.
|
||||||
|
*
|
||||||
|
* Otherwise, query the DB for 'count' faces */
|
||||||
|
if (count === undefined) {
|
||||||
|
identity.relatedFaces = await photoDB.sequelize.query(
|
||||||
|
"SELECT id AS faceId,photoId,faceConfidence " +
|
||||||
|
"FROM faces " +
|
||||||
|
"WHERE identityId=:identityId " +
|
||||||
|
limit, {
|
||||||
|
replacements: { identityId: identity.id },
|
||||||
|
type: photoDB.Sequelize.QueryTypes.SELECT,
|
||||||
|
raw: true
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
identity.relatedFaces = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there are no faces, return the 'unknown face' */
|
||||||
|
if (identity.relatedFaces.length === 0) {
|
||||||
|
identity.relatedFaces.push({
|
||||||
|
faceId: -1,
|
||||||
|
photoId: -1,
|
||||||
|
faceConfidence: 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
identity.relatedFaces.forEach(face => {
|
||||||
|
face.identityId = identity.id;
|
||||||
|
face.distance = face.faceConfidence;
|
||||||
|
face.descriptors = [];
|
||||||
|
delete face.faceConfidence;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
router.post('/', async (req, res) => {
|
||||||
|
console.log(`POST ${req.url}`)
|
||||||
|
if (!req.user.maintainer) {
|
||||||
|
console.warn(`${req.user.name} attempted to modify photos.`);
|
||||||
|
return res.status(401).send({ message: "Unauthorized to modify photos." });
|
||||||
|
}
|
||||||
|
|
||||||
|
const identity = await addOrUpdateIdentity(-1, req.body, res);
|
||||||
|
if (!identity) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
populateRelatedFaces(identity, 1);
|
||||||
|
return res.status(200).send(identity);
|
||||||
|
});
|
||||||
|
|
||||||
router.put('/:id', async (req, res) => {
|
router.put('/:id', async (req, res) => {
|
||||||
console.log(`PUT ${req.url}`)
|
console.log(`PUT ${req.url}`)
|
||||||
if (!req.user.maintainer) {
|
if (!req.user.maintainer) {
|
||||||
@ -23,45 +126,12 @@ router.put('/:id', async (req, res) => {
|
|||||||
return res.status(400).send({ message: `Invalid identity id ${id}` });
|
return res.status(400).send({ message: `Invalid identity id ${id}` });
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const identity = await addOrUpdateIdentity(id, req.body, res);
|
||||||
displayName,
|
if (!identity) {
|
||||||
firstName,
|
return;
|
||||||
lastName,
|
|
||||||
middleName
|
|
||||||
} = req.body;
|
|
||||||
|
|
||||||
if (displayName === undefined
|
|
||||||
|| firstName === undefined
|
|
||||||
|| lastName === undefined
|
|
||||||
|| middleName === undefined) {
|
|
||||||
return res.status(400).send({ message: `Missing fields` });
|
|
||||||
}
|
}
|
||||||
|
populateRelatedFaces(identity);
|
||||||
await photoDB.sequelize.query(
|
return res.status(200).send(identity);
|
||||||
'UPDATE identities ' +
|
|
||||||
'SET ' +
|
|
||||||
'displayName=:displayName, ' +
|
|
||||||
'firstName=:firstName, ' +
|
|
||||||
'lastName=:lastName, ' +
|
|
||||||
'middleName=:middleName ' +
|
|
||||||
'WHERE id=:id', {
|
|
||||||
replacements: {
|
|
||||||
displayName,
|
|
||||||
firstName,
|
|
||||||
lastName,
|
|
||||||
middleName,
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return res.status(200).json({
|
|
||||||
displayName,
|
|
||||||
firstName,
|
|
||||||
lastName,
|
|
||||||
middleName,
|
|
||||||
id
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
router.put("/faces/remove/:id", (req, res) => {
|
router.put("/faces/remove/:id", (req, res) => {
|
||||||
@ -99,7 +169,7 @@ router.put("/faces/remove/:id", (req, res) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.put("/faces/add/:id", (req, res) => {
|
router.put("/faces/add/:id", async (req, res) => {
|
||||||
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("Unauthorized to modify photos.");
|
return res.status(401).send("Unauthorized to modify photos.");
|
||||||
@ -114,23 +184,24 @@ router.put("/faces/add/:id", (req, res) => {
|
|||||||
return res.status(400).send("No faces supplied.");
|
return res.status(400).send("No faces supplied.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return photoDB.sequelize.query(
|
try {
|
||||||
"UPDATE faces SET identityId=:identityId " +
|
await photoDB.sequelize.query(
|
||||||
"WHERE id IN (:faceIds)", {
|
"UPDATE faces SET identityId=:identityId,classifiedBy='human' " +
|
||||||
replacements: {
|
"WHERE id IN (:faceIds)", {
|
||||||
identityId: id,
|
replacements: {
|
||||||
faceIds: req.body.faces
|
identityId: id,
|
||||||
}
|
faceIds: req.body.faces
|
||||||
}).then(() => {
|
}
|
||||||
|
});
|
||||||
const identity = {
|
const identity = {
|
||||||
id: id,
|
id: id,
|
||||||
faces: req.body.faces
|
faces: req.body.faces
|
||||||
};
|
};
|
||||||
return res.status(200).json([identity]);
|
return res.status(200).json([identity]);
|
||||||
}).catch((error) => {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
return res.status(500).send("Error processing request.");
|
return res.status(500).send("Error processing request.");
|
||||||
});
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post("/", (req, res) => {
|
router.post("/", (req, res) => {
|
||||||
@ -192,6 +263,42 @@ function euclideanDistance(a, b) {
|
|||||||
return Math.sqrt(sum);
|
return Math.sqrt(sum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getUnknownIdentity = async (faceCount) => {
|
||||||
|
const unknownIdentity = {
|
||||||
|
identityId: -1,
|
||||||
|
lastName: '',
|
||||||
|
firstName: '',
|
||||||
|
middleName: '',
|
||||||
|
displayName: 'Unknown',
|
||||||
|
descriptors: [],
|
||||||
|
relatedFaces: []
|
||||||
|
};
|
||||||
|
const limit = faceCount
|
||||||
|
? ` LIMIT ${faceCount} `
|
||||||
|
: ' ORDER BY faceConfidence DESC ';
|
||||||
|
unknownIdentity.relatedFaces = await photoDB.sequelize.query(
|
||||||
|
"SELECT id AS faceId,photoId,faceConfidence " +
|
||||||
|
"FROM faces WHERE identityId IS NULL AND classifiedBy != 'not-a-face' " +
|
||||||
|
limit, {
|
||||||
|
type: photoDB.Sequelize.QueryTypes.SELECT,
|
||||||
|
raw: true
|
||||||
|
});
|
||||||
|
if (unknownIdentity.relatedFaces.length === 0) {
|
||||||
|
unknownIdentity.relatedFaces.push({
|
||||||
|
faceId: -1,
|
||||||
|
photoId: -1,
|
||||||
|
faceConfidence: 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
unknownIdentity.relatedFaces.forEach(face => {
|
||||||
|
face.identityId = -1;
|
||||||
|
face.distance = face.faceConfidence;
|
||||||
|
face.descriptors = [];
|
||||||
|
delete face.faceConfidence;
|
||||||
|
});
|
||||||
|
return unknownIdentity;
|
||||||
|
}
|
||||||
|
|
||||||
router.get("/:id?", async (req, res) => {
|
router.get("/:id?", async (req, res) => {
|
||||||
console.log(`GET ${req.url}`);
|
console.log(`GET ${req.url}`);
|
||||||
|
|
||||||
@ -204,6 +311,13 @@ router.get("/:id?", async (req, res) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If identityId requested is -1, this is the "Unknown" identity
|
||||||
|
* where all unmapped faces live. */
|
||||||
|
if (id === -1) {
|
||||||
|
const unknownIdentity = await getUnknownIdentity()
|
||||||
|
return res.status(200).json([ unknownIdentity ]);
|
||||||
|
}
|
||||||
|
|
||||||
const filter = id ? "WHERE identities.id=:id " : "";
|
const filter = id ? "WHERE identities.id=:id " : "";
|
||||||
|
|
||||||
const identities = await photoDB.sequelize.query("SELECT " +
|
const identities = await photoDB.sequelize.query("SELECT " +
|
||||||
@ -212,14 +326,14 @@ router.get("/:id?", async (req, res) => {
|
|||||||
"GROUP_CONCAT(faces.descriptorId) AS relatedFaceDescriptorIds," +
|
"GROUP_CONCAT(faces.descriptorId) AS relatedFaceDescriptorIds," +
|
||||||
"GROUP_CONCAT(faces.photoId) AS relatedFacePhotoIds " +
|
"GROUP_CONCAT(faces.photoId) AS relatedFacePhotoIds " +
|
||||||
"FROM identities " +
|
"FROM identities " +
|
||||||
"INNER JOIN faces ON identities.id=faces.identityId " +
|
"LEFT JOIN faces ON identities.id=faces.identityId " +
|
||||||
filter +
|
filter +
|
||||||
"GROUP BY identities.id", {
|
"GROUP BY identities.id", {
|
||||||
replacements: { id },
|
replacements: { id },
|
||||||
type: photoDB.Sequelize.QueryTypes.SELECT,
|
type: photoDB.Sequelize.QueryTypes.SELECT,
|
||||||
raw: true
|
raw: true
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.map(identities, async (identity) => {
|
await Promise.map(identities, async (identity) => {
|
||||||
[ 'firstName', 'middleName', 'lastName' ].forEach(key => {
|
[ 'firstName', 'middleName', 'lastName' ].forEach(key => {
|
||||||
if (!identity[key]) {
|
if (!identity[key]) {
|
||||||
@ -228,35 +342,49 @@ router.get("/:id?", async (req, res) => {
|
|||||||
});
|
});
|
||||||
identity.identityId = identity.id;
|
identity.identityId = identity.id;
|
||||||
|
|
||||||
const relatedFaces = identity.relatedFaceIds.split(","),
|
if (!identity.relatedFaceIds) {
|
||||||
relatedFacePhotos = identity.relatedFacePhotoIds.split(",");
|
identity.relatedFaces = [];
|
||||||
|
} else {
|
||||||
|
const relatedFaces = identity.relatedFaceIds.split(","),
|
||||||
|
relatedFacePhotos = identity.relatedFacePhotoIds.split(",");
|
||||||
|
|
||||||
let descriptors = await photoDB.sequelize.query(
|
let descriptors = await photoDB.sequelize.query(
|
||||||
`SELECT descriptors FROM facedescriptors WHERE id in (:ids)`, {
|
`SELECT descriptors FROM facedescriptors WHERE id in (:ids)`, {
|
||||||
replacements: {
|
replacements: {
|
||||||
ids: identity.relatedFaceDescriptorIds.split(',')
|
ids: identity.relatedFaceDescriptorIds.split(',')
|
||||||
},
|
},
|
||||||
type: photoDB.Sequelize.QueryTypes.SELECT,
|
type: photoDB.Sequelize.QueryTypes.SELECT,
|
||||||
raw: true
|
raw: true
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
||||||
descriptors = descriptors.map(entry => entry.descriptors);
|
|
||||||
|
|
||||||
identity.relatedFaces = relatedFaces.map((faceId, index) => {
|
|
||||||
const distance = euclideanDistance(
|
|
||||||
descriptors[index],
|
|
||||||
identity.descriptors
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
descriptors = descriptors.map(entry => entry.descriptors);
|
||||||
|
|
||||||
return {
|
identity.relatedFaces = relatedFaces.map((faceId, index) => {
|
||||||
|
const distance = euclideanDistance(
|
||||||
|
descriptors[index],
|
||||||
|
identity.descriptors
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
identityId: identity.id,
|
||||||
|
faceId,
|
||||||
|
photoId: relatedFacePhotos[index],
|
||||||
|
distance
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (identity.relatedFaces.length === 0) {
|
||||||
|
identity.relatedFaces.push({
|
||||||
|
faceId: -1,
|
||||||
|
photoId: -1,
|
||||||
identityId: identity.id,
|
identityId: identity.id,
|
||||||
faceId,
|
distance: 0,
|
||||||
photoId: relatedFacePhotos[index],
|
faceConfidence: 0
|
||||||
distance
|
});
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
|
||||||
identity
|
identity
|
||||||
.relatedFaces
|
.relatedFaces
|
||||||
.sort((A, B) => {
|
.sort((A, B) => {
|
||||||
@ -277,6 +405,14 @@ router.get("/:id?", async (req, res) => {
|
|||||||
delete identity.relatedIdentityDescriptors;
|
delete identity.relatedIdentityDescriptors;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* If no ID was provided (so no 'filter') then this call is returning
|
||||||
|
* a list of all identities -- we create a fake identity for all
|
||||||
|
* unlabeled faces */
|
||||||
|
if (!filter) {
|
||||||
|
const unknownIdentity = await getUnknownIdentity(1)
|
||||||
|
identities.push(unknownIdentity);
|
||||||
|
}
|
||||||
|
|
||||||
return res.status(200).json(identities);
|
return res.status(200).json(identities);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user