apply_threshold.py 3.57 KB
Newer Older
André Anjos's avatar
André Anjos committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# Andre Anjos <andre.anjos@idiap.ch>
# Wed May 25 13:27:46 2011 +0200
#
# Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland

"""This script applies a threshold to score file and reports error rates
"""

__epilog__ = """
Examples:

  1. Standard usage

     $ %(prog)s --scores=my-scores.txt --threshold=0.5
"""

19
20
21
import os
import sys
from .. import farfrr, load
André Anjos's avatar
André Anjos committed
22
23
24
25

def apthres(neg, pos, thres):
  """Prints a single output line that contains all info for the threshold"""

26
  far, frr = farfrr(neg, pos, thres)
André Anjos's avatar
André Anjos committed
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  hter = (far + frr)/2.0

  ni = neg.shape[0] #number of impostors
  fa = int(round(far*ni)) #number of false accepts
  nc = pos.shape[0] #number of clients
  fr = int(round(frr*nc)) #number of false rejects

  print("FAR : %.3f%% (%d/%d)" % (100*far, fa, ni))
  print("FRR : %.3f%% (%d/%d)" % (100*frr, fr, nc))
  print("HTER: %.3f%%" % (100*hter,))

def get_options(user_input):
  """Parse the program options"""

  usage = 'usage: %s [arguments]' % os.path.basename(sys.argv[0])

  import argparse
  parser = argparse.ArgumentParser(usage=usage,
      description=(__doc__ % {'prog': os.path.basename(sys.argv[0])}),
      epilog=(__epilog__ % {'prog': os.path.basename(sys.argv[0])}),
      formatter_class=argparse.RawDescriptionHelpFormatter)

  parser.add_argument('-s', '--scores', dest="ifile", default=None,
      help="Name of the file containing the scores (defaults to %(default)s)",
      metavar="FILE")
  parser.add_argument('-t', '--threshold', dest='thres', default=None,
      type=float, help="The threshold value to apply", metavar="FLOAT")
  parser.add_argument('-p', '--parser', dest="parser", default="4column",
André Anjos's avatar
André Anjos committed
55
      help="Name of a known parser or of a python-importable function that can parse your input files and return a tuple (negatives, positives) as blitz 1-D arrays of 64-bit floats. Consult the API of bob.measure.load.split_four_column() for details", metavar="NAME.FUNCTION")
André Anjos's avatar
André Anjos committed
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  
  # This option is not normally shown to the user...
  parser.add_argument("--self-test",
      action="store_true", dest="test", default=False, help=argparse.SUPPRESS)
      #help="if set, runs an internal verification test and erases any output")

  args = parser.parse_args(args=user_input)

  if args.test:
    # then we go into test mode, all input is preset
    args.thres = 0.0

  if args.ifile is None:
    parser.error("you should give an input score set with --scores")

  if args.thres is None:
    parser.error("you should give a threshold value with --threshold")

  #parse the score-parser
  if args.parser.lower() in ('4column', '4col'):
76
    args.parser = load.split_four_column
André Anjos's avatar
André Anjos committed
77
  elif args.parser.lower() in ('5column', '5col'):
78
    args.parser = load.split_five_column
André Anjos's avatar
André Anjos committed
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  else: #try an import
    if args.parser.find('.') == -1:
      parser.error("parser module should be either '4column', '5column' or a valid python function identifier in the format 'module.function': '%s' is invalid" % args.parser)

    mod, fct = args.parser.rsplit('.', 2)
    import imp
    try:
      fp, pathname, description = imp.find_module(mod, ['.'] + sys.path)
    except Exception as e:
      parser.error("import error for '%s': %s" % (args.parser, e))

    try:
      pmod = imp.load_module(mod, fp, pathname, description)
      args.parser = getattr(pmod, fct)
    except Exception as e:
      parser.error("loading error for '%s': %s" % (args.parser, e))
    finally:
      fp.close()

  return args

def main(user_input=None):

  options = get_options(user_input)

  neg, pos = options.parser(options.ifile)
  apthres(neg, pos, options.thres)

  return 0