ID can now be set per face
Signed-off-by: James P. Ketrenos <james.p.ketrenos@intel.com>
This commit is contained in:
parent
40b3a0d819
commit
83e006b43c
@ -403,6 +403,7 @@ const Button = ({ onClick, children }: any) => {
|
|||||||
const App = () => {
|
const App = () => {
|
||||||
const [identities, setIdentities] = useState<IdentityData[]>([]);
|
const [identities, setIdentities] = useState<IdentityData[]>([]);
|
||||||
const { identityId, faceId } = useParams();
|
const { identityId, faceId } = useParams();
|
||||||
|
const [selectedIdentities, setSelectedIdentities] = useState<number[]>([]);
|
||||||
const [identity, setIdentity] = useState<IdentityData | undefined>(undefined);
|
const [identity, setIdentity] = useState<IdentityData | undefined>(undefined);
|
||||||
const [image, setImage] = useState<number>(0);
|
const [image, setImage] = useState<number>(0);
|
||||||
const { loading, data } = useApi(
|
const { loading, data } = useApi(
|
||||||
@ -503,6 +504,27 @@ const App = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const changeSelectedIdentity = async () => {
|
||||||
|
|
||||||
|
if (selectedIdentities.length === 0) {
|
||||||
|
window.alert('You need to select an identity first (CTRL+CLICK)');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const res = await window.fetch(
|
||||||
|
`${base}/api/v1/identities/faces/add/${selectedIdentities[0]}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ faces: selected })
|
||||||
|
});
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
removeFacesFromIdentities(data.faces);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const markSelectedNotFace = async () => {
|
const markSelectedNotFace = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await window.fetch(
|
const res = await window.fetch(
|
||||||
@ -534,7 +556,36 @@ const App = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const identitiesOnFaceClick = (e: any, face: FaceData) => {
|
const identitiesOnFaceClick = (e: any, face: FaceData) => {
|
||||||
|
const identitiesEl = document.querySelector('.Identities');
|
||||||
|
if (!identitiesEl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const identityId = face.identityId;
|
const identityId = face.identityId;
|
||||||
|
|
||||||
|
const el = e.currentTarget;
|
||||||
|
|
||||||
|
/* Control -- select / deselect single item */
|
||||||
|
if (e.ctrlKey) {
|
||||||
|
[...identitiesEl.querySelectorAll('.Selected')].forEach(item => {
|
||||||
|
item.classList.remove('Selected')
|
||||||
|
});
|
||||||
|
el.classList.toggle('Selected');
|
||||||
|
|
||||||
|
const selected = [...identitiesEl.querySelectorAll('.Selected')]
|
||||||
|
.map((face: any) => face.getAttribute('data-identity-id'));
|
||||||
|
setSelectedIdentities(selected);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift -- select groups */
|
||||||
|
if (e.shiftKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default to load image */
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
loadIdentity(identityId);
|
loadIdentity(identityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -559,6 +610,7 @@ const App = () => {
|
|||||||
{ selected.length !== 0 && <>
|
{ selected.length !== 0 && <>
|
||||||
<Button onClick={markSelectedIncorrectIdentity}>Remove</Button>
|
<Button onClick={markSelectedIncorrectIdentity}>Remove</Button>
|
||||||
<Button onClick={markSelectedNotFace}>Not a face</Button>
|
<Button onClick={markSelectedNotFace}>Not a face</Button>
|
||||||
|
<Button onClick={changeSelectedIdentity}>Change Identity</Button>
|
||||||
</>}
|
</>}
|
||||||
</div>
|
</div>
|
||||||
</Panel>
|
</Panel>
|
||||||
|
@ -99,7 +99,8 @@ def load_faces(db_path ):
|
|||||||
FROM faces
|
FROM faces
|
||||||
INNER JOIN photos ON (photos.duplicate == 0 OR photos.duplicate IS NULL)
|
INNER JOIN photos ON (photos.duplicate == 0 OR photos.duplicate IS NULL)
|
||||||
JOIN facedescriptors ON (faces.descriptorId=facedescriptors.id)
|
JOIN facedescriptors ON (faces.descriptorId=facedescriptors.id)
|
||||||
WHERE faces.identityId IS null
|
WHERE faces.identityId IS null
|
||||||
|
AND faces.classifiedBy != 'not-a-face'
|
||||||
AND faces.photoId=photos.id
|
AND faces.photoId=photos.id
|
||||||
''')
|
''')
|
||||||
for row in res.fetchall():
|
for row in res.fetchall():
|
||||||
|
@ -134,7 +134,24 @@ router.put('/:id', async (req, res) => {
|
|||||||
return res.status(200).send(identity);
|
return res.status(200).send(identity);
|
||||||
});
|
});
|
||||||
|
|
||||||
router.put("/faces/remove/:id", (req, res) => {
|
|
||||||
|
const addFaceToIdentityDescriptors = (identity, face) => {
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeFaceToIdentityDescriptors = (identity, face) => {
|
||||||
|
};
|
||||||
|
|
||||||
|
const writeIdentityDescriptors = async (identity) => {
|
||||||
|
await photoDB.sequelize.query(
|
||||||
|
'UPDATE identities ' +
|
||||||
|
'SET descriptors=:descriptors' +
|
||||||
|
'WHERE id=:identityId', {
|
||||||
|
replacements: identity
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
router.put("/faces/remove/:id", 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.`);
|
||||||
@ -150,23 +167,28 @@ router.put("/faces/remove/:id", (req, res) => {
|
|||||||
return res.status(400).send({ message: "No faces supplied." });
|
return res.status(400).send({ message: "No faces supplied." });
|
||||||
}
|
}
|
||||||
|
|
||||||
return photoDB.sequelize.query(
|
try {
|
||||||
"UPDATE faces SET identityId=null " +
|
await photoDB.sequelize.query(
|
||||||
"WHERE id IN (:faceIds)", {
|
"UPDATE faces SET identityId=null " +
|
||||||
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
|
||||||
};
|
};
|
||||||
|
identity.faces = identity.faces.map(id => +id);
|
||||||
|
|
||||||
|
updateIdentityDescriptors(identity);
|
||||||
|
|
||||||
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({message: "Error processing request." });
|
return res.status(500).send({message: "Error processing request." });
|
||||||
});
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
router.put("/faces/add/:id", async (req, res) => {
|
router.put("/faces/add/:id", async (req, res) => {
|
||||||
@ -197,7 +219,11 @@ router.put("/faces/add/:id", async (req, res) => {
|
|||||||
id: id,
|
id: id,
|
||||||
faces: req.body.faces
|
faces: req.body.faces
|
||||||
};
|
};
|
||||||
return res.status(200).json([identity]);
|
identity.faces = identity.faces.map(id => +id);
|
||||||
|
|
||||||
|
updateIdentityDescriptors(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.");
|
||||||
@ -249,10 +275,16 @@ router.post("/", (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function bufferToFloat32Array(buffer) {
|
function bufferToFloat32Array(buffer) {
|
||||||
return new Float64Array(buffer.buffer, buffer.byteOffset, buffer.byteLength / Float64Array.BYTES_PER_ELEMENT);
|
return new Float64Array(buffer.buffer,
|
||||||
|
buffer.byteOffset,
|
||||||
|
buffer.byteLength / Float64Array.BYTES_PER_ELEMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
function euclideanDistance(a, b) {
|
function euclideanDistance(a, b) {
|
||||||
|
if (!a.buffer || !b.buffer) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
let A = bufferToFloat32Array(a);
|
let A = bufferToFloat32Array(a);
|
||||||
let B = bufferToFloat32Array(b);
|
let B = bufferToFloat32Array(b);
|
||||||
let sum = 0;
|
let sum = 0;
|
||||||
@ -270,7 +302,7 @@ const getUnknownIdentity = async (faceCount) => {
|
|||||||
firstName: '',
|
firstName: '',
|
||||||
middleName: '',
|
middleName: '',
|
||||||
displayName: 'Unknown',
|
displayName: 'Unknown',
|
||||||
descriptors: [],
|
descriptors: new Float32Array(0),
|
||||||
relatedFaces: []
|
relatedFaces: []
|
||||||
};
|
};
|
||||||
const limit = faceCount
|
const limit = faceCount
|
||||||
@ -293,7 +325,7 @@ const getUnknownIdentity = async (faceCount) => {
|
|||||||
unknownIdentity.relatedFaces.forEach(face => {
|
unknownIdentity.relatedFaces.forEach(face => {
|
||||||
face.identityId = -1;
|
face.identityId = -1;
|
||||||
face.distance = face.faceConfidence;
|
face.distance = face.faceConfidence;
|
||||||
face.descriptors = [];
|
face.descriptors = new Float32Array(0);
|
||||||
delete face.faceConfidence;
|
delete face.faceConfidence;
|
||||||
});
|
});
|
||||||
return unknownIdentity;
|
return unknownIdentity;
|
||||||
@ -361,10 +393,15 @@ router.get("/:id?", async (req, res) => {
|
|||||||
descriptors = descriptors.map(entry => entry.descriptors);
|
descriptors = descriptors.map(entry => entry.descriptors);
|
||||||
|
|
||||||
identity.relatedFaces = relatedFaces.map((faceId, index) => {
|
identity.relatedFaces = relatedFaces.map((faceId, index) => {
|
||||||
const distance = euclideanDistance(
|
let distance = 0;
|
||||||
descriptors[index],
|
if (descriptors[index] && identity.descriptors) {
|
||||||
identity.descriptors
|
distance = euclideanDistance(
|
||||||
);
|
descriptors[index],
|
||||||
|
identity.descriptors
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
distance = -1;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
identityId: identity.id,
|
identityId: identity.id,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user