1-to-N Face search¶
- One-to-many (1-to-N) Face search is the process in which a probe template is searched against the reference database of users. This raises 2 new challenges compared to 1-to-1 face recognition:
Performance optimization to not compare to the full database
Score normalization, in order to keep the same security thresholds (See Face recognition )
We strongly recommend to use the FaceIndexer module for your 1-to-N applications, and not manually implement search loops.
Note
For small databases (up to a few thousand templates), you can use the FaceMatcher search function, which uses a simpler match loop, and handles the score normalization.
The face indexer consists of large index file, serializable on disk, containing all users IDs and templates. It is optimized for fast-search with a logarithmic complexity to the number of user. We provide methods to create an index, add users, and search users in it.
Note
The Face Indexer module supports only FaceEncoders A and B versions, not the C versions. We strongly recommend to use FaceEncoder 10A.
Constructing a face index¶
Indexers shall be initialized with a maximum user number in order to preallocate the memory layout. The indexer can later be resized if necessary, but this is a quite costly operation that we recommend not to perform at each add.
N_MAX_USERS = 10000
indexer = id3.FaceIndexer.create(N_MAX_USERS, id3.FaceTemplateFormat.V10A)
Add a user to the index¶
Users are identified by a UUID v4, given as a 16-bytes unsigned char array.
tpl: id3.FaceTemplate = id3.FaceTemplate.from_file("data/ref_template_placeholder.bin")
user_id = uuid.uuid4()
indexer.add(tpl, user_id.bytes)
indexer.to_file("data/face_index.db")
Searching in the index¶
Indexer search returns the k-closest match in the database. You can set this parameter with the max_candidate parameter. Output scores can be inte
indexer = id3.FaceIndexer.from_file("data/face_index.db")
probe: id3.FaceTemplate = id3.FaceTemplate.from_file("data/probe_template_placeholder.bin")
candidates = indexer.search(probe, 1)
id_bytes = candidates[0].uuid
matched_id = uuid.UUID(bytes=bytes(id_bytes)) # To High-level UUID object
score = candidates[0].score
if score > id3.FaceMatcherThreshold.FMR10000:
print(f"Match : {matched_id} with score {score}")
else:
print("No match")