This tutorial continues from the previous one which is on Using NIST Fingerprint software to generate a pairwise comparison score matrix. So, do read this before doing this one.
In this tutorial, you will learn how to optimize the fingerprint minutiae quality threshold. The Detection Error Trade-off (DET) curve before and after using a better threshold is shown below.
As can be observed, there is a marked improvement by simplying using only minutiae of sufficiently high quality.
features
directory.# In bash
mv features features_original
mkdir features
features
directory which contains fingerprint templates with only sufficiently high quality minutiae.Let’s take a look at an xyt
file using head features_original/100_1.xyt
in bash, which gives the following output:
167 246 34 13
172 191 214 12
177 219 236 6
178 228 45 13
178 209 225 6
184 206 45 29
187 273 304 14
195 290 191 14
196 318 214 32
198 264 34 32
The first column shows the row and column of minutiae and the third column shows the orientation. The last column is what we are interested in; it shows the quality of the minuatiae. The code below will filter out the minutiae with low quality by using a threshold of 20
and then writing the feature files back to the features
directory.
quality_thrd = 20;
for i=1:numel(fname)
original_fname = strrep(fname{i}, 'features', 'features_original');
tmplt = dlmread(original_fname);
selected_row = tmplt(:,4) > quality_thrd;
dlmwrite(fname{i}, tmplt(selected_row,:), ' ');
end
scores = zeros(1000,1000);
for i=1:numel(fname)
cmd = sprintf("bozorth3 -o out.scores -p %s -G filelist_xyt.txt", fname{i});
tic;
msg = unix(cmd);
scores_ = dlmread('out.scores');
scores(:,i) = scores_;
time_ = toc;
fprintf(1, '%d of %d (%1.2f)\n', i, numel(fname), time_); fflush(stdout);
end
save scores_20.mat scores
First, we load the scores produced in the previous tutorial; and call it scores
.
out = load('scores.mat');
scores = out.scores;
out = load('scores_20.mat');
scores20 = out.scores; %scores produced in this tutorial
Next, we get the genuine and impostor scores, reusing the variable user
created in the previous tutorial.
idlist = user;
% get the scores
sym_scores = get_symmetric_scores(scores20, idlist);
[imp_scores, gen_scores] = get_scores(sym_scores, idlist);
imp_logit = - get_gen_logit(imp_scores, 400);
gen_logit = - get_gen_logit(gen_scores, 400);
eer2 = wer(imp_logit, gen_logit,[],2)
sym_scores = get_symmetric_scores(scores, idlist);
[imp_scores, gen_scores] = get_scores(sym_scores, idlist);
imp_logit = - get_gen_logit(imp_scores, 400);
gen_logit = - get_gen_logit(gen_scores, 400);
eer = wer(imp_logit, gen_logit,[],2,[],2)
legend('Original', 'Quality>20','Location', 'northeast');
print('-dpng', 'Pictures/wer_quality_optimised.png');
@misc{ poh_2017_12_29_optimize-fprint-minutiae-quality,
author = {Norman Poh},
title = { Tutorial: Optimize fingerprint minutiae quality },
howpublished = {\url{ http://normanpoh.github.com/blog/2017/12/29/optimize-fprint-minutiae-quality.html},
note = "Accessed: ___TODAY___"
}