One-To-Many (1:N) Search¶
One-to-many (or 1-to-N) search is the process in which a probe template is searched against a large database of reference templates. It should return a candidate list of the closest matches in the database.
Note
For small databases (up to 100 templates), The FingerMatcher module provides a search method that performs exhaustive matches against the reference list.
For large databases (over 100 templates), the FingerIndexer module offers a more efficient way of performing a one-to-many search.
The 1:N search using FingerIndexer is separated in 2 steps :
A coarse search using the FingerIndexer, which returns a list of potential candidates, but with no interpretable scores.
A fine search on this list using the normal FingerMatcher, to reorder and compute usable match scores.
Storage¶
The user must handle the storage of 2 different objects :
The binary file of the FingerIndexer, which must be loaded in the SDK Runtime.
A database of the ISO templates of each user. For scalability reasons, these are not loaded entirely in RAM: it is up to the user to retrieve only the necessary ones after the first coarse search step.
Constructing a finger index¶

The example below demonstrates how to construct a Finger Indexer:
# Load models
id3.FingerLibrary.load_model(MODELS_PATH, id3.FingerModel.FINGER_ALIGNER_1A, id3.ProcessingUnit.CPU)
id3.FingerLibrary.load_model(MODELS_PATH, id3.FingerModel.FINGER_ENCODER_1A, id3.ProcessingUnit.CPU)
id3.FingerLibrary.load_model(MODELS_PATH, id3.FingerModel.FINGER_MINUTIA_DETECTOR_3B, id3.ProcessingUnit.CPU)
# --------------- Indexer creation ----------------
# Create FingerIndexer
finger_indexer = id3.FingerIndexer.create(1000, id3.FingerDataFormat.FINGER_EMBEDDING_V1_A)
# Loop on users
for user in tqdm(range(100)):
file_path = f"finger_image_records/{user}_1.fir"
image_record = id3.FingerImageRecord.from_file(id3.FingerImageRecordFormat.ISO19794_4_2005, file_path)
finger_indexer.add(image_record, user)
print("Successfully enrolled {} users".format(finger_indexer.user_count))
# Save FingerIndexer
finger_indexer.to_file("id3_finger_indexer.bin")
Searching in the index¶

The example below demonstrates how to search for a fingerprint using the index:
# Load FingerIndexer
finger_indexer = id3.FingerIndexer.from_file("id3_finger_indexer.bin")
extractor = id3.FingerExtractor()
matcher = id3.FingerMatcher()
# Parameters
K_CANDIDATES = 10
TRUST_POSITIONS = False
# Coarse search : genuine user 35
probe_path = f"finger_image_records/35_1.fir"
probe_image_record = id3.FingerImageRecord.from_file(id3.FingerImageRecordFormat.ISO19794_4_2005, probe_path)
candidate_list = finger_indexer.search(probe_image_record, K_CANDIDATES, TRUST_POSITIONS)
# Loop on candidates
for index, candidate in enumerate(candidate_list):
# Retrieve candidate image record
candidate_path = f"finger_image_records/{candidate.id}_1.fir"
candidate_image_record = id3.FingerImageRecord.from_file(id3.FingerImageRecordFormat.ISO19794_4_2005, candidate_path)
# Extract (or retrieve in database) the ISO template record
candidate_template_record = extractor.create_template_record(candidate_image_record)
# Fill it in the candidate list
candidate_list.set_template_record(index, candidate_template_record)
# Extract (or retrieve in database) the ISO template record of the probe
probe_template_record = extractor.create_template_record(probe_image_record)
# Fine grain search to reorder candidate list and compute interpretable scores
final_candidates = matcher.search(probe_template_record, candidate_list, TRUST_POSITIONS)
# Use the result
for candidate in final_candidates:
status = "[Match] " if candidate.score > id3.FingerMatcherThreshold.FMR10000 \
else "[Non-match]"
print("{} : Found user {} with score {}".format(status, candidate.id, candidate.score))