Bob 2.0 standard metrics for biometric system evaluation. Scores use strings for template ids.

This algorithm is a legacy one. The API has changed since its implementation. New versions and forks will need to be updated.
This algorithm is an analyzer. It can only be used on analysis blocks.

Algorithms have at least one input and one output. All algorithm endpoints are organized in groups. Groups are used by the platform to indicate which inputs and outputs are synchronized together. The first group is automatically synchronized with the channel defined by the block in which the algorithm is deployed.

Group: test

Endpoint Name Data Format Nature
test_fusion_scores pkorshunov/fusion_scores/1 Input

Group: dev

Endpoint Name Data Format Nature
dev_fusion_scores pkorshunov/fusion_scores/1 Input

Analyzers may produce any number of results. Once experiments using this analyzer are done, you may display the results or filter experiments using criteria based on them.

Name Type
number_of_positives_dev_spoof int32
number_of_negatives_dev_spoof int32
number_of_positives_test_spoof int32
HTER_licit float32
FRR_test_spoof float32
roc_test plot/isoroc/1
number_of_negatives_test_licit int32
FAR_dev_spoof float32
number_of_negatives_dev_licit int32
FAR_dev_licit float32
dev_histograms plot/bar/1
number_of_positives_dev_licit int32
EER_spoof float32
test_histograms plot/bar/1
HTER_spoof float32
FAR_test_spoof float32
number_of_positives_test_licit int32
FRR_dev_licit float32
number_of_negatives_test_spoof int32
FRR_test_licit float32
threshold_licit float32
roc_dev plot/isoroc/1
threshold_spoof float32
FAR_test_licit float32
FRR_dev_spoof float32
EER_licit float32

Parameters allow users to change the configuration of an algorithm when scheduling an experiment

Name Description Type Default Range/Choices
n_bins_real Number of histogram bins for real scores uint32 20
n_bins_attack Number of histogram bins for attack scores uint32 80
n_bins_zimp Number of histogram bins for zero-impostors scores uint32 100
xxxxxxxxxx
187
 
1
import bob.measure
2
import numpy
3
4
5
class Algorithm:
6
7
    def __init__(self):
8
        self.positives_dev_licit = []
9
        self.negatives_dev_licit = []
10
        self.positives_test_licit = []
11
        self.negatives_test_licit = []
12
        self.positives_dev_spoof = []
13
        self.negatives_dev_spoof = []
14
        self.positives_test_spoof = []
15
        self.negatives_test_spoof = []
16
        self.dev_scores_real = None
17
        self.n_bins_real = 20
18
        self.n_bins_zimp = 100
19
        self.n_bins_attack = 80
20
21
    def setup(self, parameters):
22
        self.n_bins_real = float(parameters.get('n_bins_real', self.n_bins_real))
23
        self.n_bins_zimp = float(parameters.get('n_bins_zimp', self.n_bins_zimp))
24
        self.n_bins_attack = float(parameters.get('n_bins_attack', self.n_bins_attack))
25
        return True
26
27
    def process(self, inputs, output):
28
        dev_scores_zimp = []
29
        dev_scores_attack = []
30
        test_scores_real = []
31
        test_scores_zimp = []
32
        test_scores_attack = []
33
        
34
        # accumulate the dev scores
35
        if self.dev_scores_real is None:
36
            self.dev_scores_real = []
37
            while inputs['dev_fusion_scores'].hasMoreData():
38
                inputs['dev_fusion_scores'].next()
39
                dev_fusion_scores = inputs['dev_fusion_scores'].data
40
                self.dev_scores_real.extend(dev_fusion_scores.real_scores)
41
                dev_scores_zimp.extend(dev_fusion_scores.zimp_scores)
42
                dev_scores_attack.extend(dev_fusion_scores.attack_scores)
43
          
44
        test_fusion_scores = inputs['test_fusion_scores'].data
45
        test_scores_real.extend(test_fusion_scores.real_scores)
46
        test_scores_zimp.extend(test_fusion_scores.zimp_scores)
47
        test_scores_attack.extend(test_fusion_scores.attack_scores)
48
49
        # once all values are received, evaluate the scores
50
        if not(inputs.hasMoreData()):
51
            # first, compute everything for licit scenario (no attacks)
52
            self.positives_dev_licit = self.dev_scores_real
53
            self.negatives_dev_licit = dev_scores_zimp
54
            self.positives_test_licit = test_scores_real
55
            self.negatives_test_licit = test_scores_zimp
56
            
57
            eer_threshold_licit = bob.measure.eer_threshold(self.negatives_dev_licit, self.positives_dev_licit)
58
            far_dev_licit, frr_dev_licit   = bob.measure.farfrr(self.negatives_dev_licit, self.positives_dev_licit, eer_threshold_licit)
59
            far_test_licit, frr_test_licit = bob.measure.farfrr(self.negatives_test_licit, self.positives_test_licit, eer_threshold_licit)
60
            roc_points_dev_licit     = bob.measure.roc(self.negatives_dev_licit, self.positives_dev_licit, 100)
61
            roc_points_test_licit    = bob.measure.roc(self.negatives_test_licit, self.positives_test_licit, 100)
62
63
            dev_hist_pos_licit, dev_bin_pos_licit = numpy.histogram(self.positives_dev_licit, self.n_bins_real)
64
            dev_hist_neg_licit, dev_bin_neg_licit = numpy.histogram(self.negatives_dev_licit, self.n_bins_zimp)
65
            test_hist_pos_licit, test_bin_pos_licit = numpy.histogram(self.positives_test_licit, self.n_bins_real)
66
            test_hist_neg_licit, test_bin_neg_licit = numpy.histogram(self.negatives_test_licit, self.n_bins_zimp)
67
            
68
            # then, compute everything for spoof scenario (no zero-impostor)
69
            self.positives_dev_spoof = self.dev_scores_real
70
            self.negatives_dev_spoof = dev_scores_attack
71
            self.positives_test_spoof = test_scores_real
72
            self.negatives_test_spoof = test_scores_attack
73
            eer_threshold_spoof = bob.measure.eer_threshold(self.negatives_dev_spoof, self.positives_dev_spoof)
74
            far_dev_spoof, frr_dev_spoof   = bob.measure.farfrr(self.negatives_dev_spoof, self.positives_dev_spoof, eer_threshold_spoof)
75
            far_test_spoof, frr_test_spoof = bob.measure.farfrr(self.negatives_test_spoof, self.positives_test_spoof, eer_threshold_spoof)
76
            roc_points_dev_spoof     = bob.measure.roc(self.negatives_dev_spoof, self.positives_dev_spoof, 100)
77
            roc_points_test_spoof    = bob.measure.roc(self.negatives_test_spoof, self.positives_test_spoof, 100)
78
79
            dev_hist_neg_spoof, dev_bin_neg_spoof = numpy.histogram(self.negatives_dev_spoof, self.n_bins_attack)
80
            test_hist_neg_spoof, test_bin_neg_spoof = numpy.histogram(self.negatives_test_spoof, self.n_bins_attack)
81
            
82
            # writes the output back to the platform
83
            output.write({
84
                'EER_licit': numpy.float32((far_dev_licit+frr_dev_licit) / 2.),
85
                'threshold_licit': numpy.float32(eer_threshold_licit),
86
                'FAR_dev_licit': numpy.float32(far_dev_licit),
87
                'FRR_dev_licit': numpy.float32(frr_dev_licit),
88
                'HTER_licit': numpy.float32((far_test_licit+frr_test_licit) / 2.),
89
                'FAR_test_licit': numpy.float32(far_test_licit),
90
                'FRR_test_licit': numpy.float32(frr_test_licit),
91
                'number_of_positives_dev_licit': numpy.int32(len(self.positives_dev_licit)),
92
                'number_of_negatives_dev_licit': numpy.int32(len(self.negatives_dev_licit)),
93
                'number_of_positives_test_licit': numpy.int32(len(self.positives_test_licit)),
94
                'number_of_negatives_test_licit': numpy.int32(len(self.negatives_test_licit)),
95
                'EER_spoof': numpy.float32((far_dev_spoof+frr_dev_spoof) / 2.),
96
                'threshold_spoof': numpy.float32(eer_threshold_spoof),
97
                'FAR_dev_spoof': numpy.float32(far_dev_spoof),
98
                'FRR_dev_spoof': numpy.float32(frr_dev_spoof),
99
                'HTER_spoof': numpy.float32((far_test_spoof+frr_test_spoof) / 2.),
100
                'FAR_test_spoof': numpy.float32(far_test_spoof),
101
                'FRR_test_spoof': numpy.float32(frr_test_spoof),
102
                'number_of_positives_dev_spoof': numpy.int32(len(self.positives_dev_spoof)),
103
                'number_of_negatives_dev_spoof': numpy.int32(len(self.negatives_dev_spoof)),
104
                'number_of_positives_test_spoof': numpy.int32(len(self.positives_test_spoof)),
105
                'number_of_negatives_test_spoof': numpy.int32(len(self.negatives_test_spoof)),
106
                'roc_dev': {
107
                    "data":
108
                        [
109
                            {
110
                                "label": "licit-protocol",
111
                                "false_positives": roc_points_dev_licit[0],
112
                                "false_negatives": roc_points_dev_licit[1],
113
                                "number_of_positives": numpy.uint64(len(self.positives_dev_licit)),
114
                                "number_of_negatives": numpy.uint64(len(self.negatives_dev_licit)),
115
                            },
116
                            {
117
                                "label": "spoof-protocol",
118
                                "false_positives": roc_points_dev_spoof[0],
119
                                "false_negatives": roc_points_dev_spoof[1],
120
                                "number_of_positives": numpy.uint64(len(self.positives_dev_spoof)),
121
                                "number_of_negatives": numpy.uint64(len(self.negatives_dev_spoof)),
122
                            }
123
                        ]
124
                    },
125
                'roc_test': {
126
                    "data":
127
                        [
128
                            {
129
                                "label": "licit-protocol",
130
                                "false_positives": roc_points_test_licit[0],
131
                                "false_negatives": roc_points_test_licit[1],
132
                                "number_of_positives": numpy.uint64(len(self.positives_test_licit)),
133
                                "number_of_negatives": numpy.uint64(len(self.negatives_test_licit)),
134
                            },
135
                            {
136
                                "label": "spoof-protocol",
137
                                "false_positives": roc_points_test_spoof[0],
138
                                "false_negatives": roc_points_test_spoof[1],
139
                                "number_of_positives": numpy.uint64(len(self.positives_test_spoof)),
140
                                "number_of_negatives": numpy.uint64(len(self.negatives_test_spoof)),
141
                            }
142
                        ]
143
                    },
144
                'dev_histograms': {
145
                    "data":
146
                        [
147
                            {
148
                                "label": "Attacks",
149
                                "x": dev_bin_neg_spoof[:-1],
150
                                "y": dev_hist_neg_spoof,
151
                            },
152
                            {
153
                                "label": "Zero-impostors",
154
                                "x": dev_bin_neg_licit[:-1],
155
                                "y": dev_hist_neg_licit,
156
                            },
157
                            {
158
                                "label": "Genuine",
159
                                "x": dev_bin_pos_licit[:-1],
160
                                "y": dev_hist_pos_licit,
161
                            }
162
                        ]
163
                    },
164
                'test_histograms': {
165
                    "data":
166
                        [
167
                            {
168
                                "label": "Attacks",
169
                                "x": test_bin_neg_spoof[:-1],
170
                                "y": test_hist_neg_spoof,
171
                            },
172
                            {
173
                                "label": "Zero-impostors",
174
                                "x": test_bin_neg_licit[:-1],
175
                                "y": test_hist_neg_licit,
176
                            },
177
                            {
178
                                "label": "Genuine",
179
                                "x": test_bin_pos_licit[:-1],
180
                                "y": test_hist_pos_licit,
181
                            }
182
                        ]
183
                    }
184
            })
185
186
        return True
187

The code for this algorithm in Python
The ruler at 80 columns indicate suggested POSIX line breaks (for readability).
The editor will automatically enlarge to accomodate the entirety of your input
Use keyboard shortcuts for search/replace and faster editing. For example, use Ctrl-F (PC) or Cmd-F (Mac) to search through this box

An algorithm that implements standard metrics for biometric system evaluation.

Specifically, it returns:

  • eer: the equal error rate (EER) on the development set.
  • hter: the half total error rate (HTER) on the test set
  • far_dev: the false acceptance rate (FAR) on the development set
  • frr_dev: the false rejection rate (FRR) on the development set
  • far_dev: the false acceptance rate (FAR) on the test set
  • frr_test: the false rejection rate (FRR) on the test set
  • number_of_positives_dev: the number of positive (genuine) trials on the development set
  • number_of_negatives_dev: the number of negative (impostor) trials on the development set
  • number_of_positives_test: the number of positive (genuine) trials on the test set
  • number_of_negatives_test: the number of negative (impostor) trials on the test set
  • threshold: the threshold at the equal error rate on the development set
  • roc_dev: the receiver operating characteristic (ROC) curve on the development set according to the biometrics standard ISO/IEC 19795-1:2006(E)
  • roc_test: the receiver operating characteristic (ROC) curve on the test set according to the biometrics standard ISO/IEC 19795-1:2006(E)

This implementation relies on the 'measure' package from the `Bob <http://www.idiap.ch/software/bob>`_ library.

Docutils System Messages

System Message: ERROR/3 (<string>, line 31); backlink

Unknown target name: "bob &amp;amp;lt;http://www.idiap.ch/software/bob&amp;amp;gt;".

Experiments

Updated Name Databases/Protocols Analyzers
pkorshunov/pkorshunov/isv-asv-pad-fusion-complete/1/asv_isv-pad_lbp_hist_ratios_lr-fusion_lr-pa_aligned avspoof/2@physicalaccess_verification,avspoof/2@physicalaccess_verify_train,avspoof/2@physicalaccess_verify_train_spoof,avspoof/2@physicalaccess_antispoofing,avspoof/2@physicalaccess_verification_spoof pkorshunov/spoof-score-fusion-roc_hist/1
pkorshunov/pkorshunov/isv-asv-pad-fusion-complete/1/asv_isv-pad_gmm-fusion_lr-pa avspoof/2@physicalaccess_verification,avspoof/2@physicalaccess_verify_train,avspoof/2@physicalaccess_verify_train_spoof,avspoof/2@physicalaccess_antispoofing,avspoof/2@physicalaccess_verification_spoof pkorshunov/spoof-score-fusion-roc_hist/1
Created with Raphaël 2.1.2[compare]pkorshunov/spoof-score-fusion-roc_hist/12016Apr7

This table shows the number of times this algorithm has been successfully run using the given environment. Note this does not provide sufficient information to evaluate if the algorithm will run when submitted to different conditions.

Terms of Service | Contact Information | BEAT platform version 2.2.1b0 | © Idiap Research Institute - 2013-2025