Coverage for src/bob/bio/base/script/commands.py: 92%

100 statements  

« prev     ^ index     » next       coverage.py v7.6.5, created at 2024-11-14 21:41 +0100

1""" Click commands for ``bob.bio.base`` """ 

2import functools 

3import logging 

4 

5import click 

6 

7from clapper.click import verbosity_option 

8 

9import bob.measure.script.figure as measure_figure 

10 

11from bob.measure.script import common_options 

12 

13from ..score import load 

14from . import figure as bio_figure 

15 

16logger = logging.getLogger(__name__) 

17 

18SCORE_FORMAT = ( 

19 "Files must be 4- or 5- columns format, see " 

20 ":py:func:`bob.bio.base.score.load.four_column` and " 

21 ":py:func:`bob.bio.base.score.load.five_column` for details." 

22) 

23CRITERIA = ("eer", "min-hter", "far", "mindcf", "cllr", "rr") 

24 

25 

26def rank_option(**kwargs): 

27 """Get option for rank parameter""" 

28 

29 def custom_rank_option(func): 

30 def callback(ctx, param, value): 

31 value = 1 if value < 0 else value 

32 ctx.meta["rank"] = value 

33 return value 

34 

35 return click.option( 

36 "-rk", 

37 "--rank", 

38 type=click.INT, 

39 default=1, 

40 help="Provide rank for the command", 

41 callback=callback, 

42 show_default=True, 

43 **kwargs, 

44 )(func) 

45 

46 return custom_rank_option 

47 

48 

49@common_options.metrics_command( 

50 common_options.METRICS_HELP.format( 

51 names="FtA, FAR, FRR, FMR, FNMR, HTER", 

52 criteria=CRITERIA, 

53 score_format=SCORE_FORMAT, 

54 hter_note="Note that FAR = FMR * (1 - FtA), FRR = FtA + FNMR * (1 - FtA) " 

55 "and HTER = (FMR + FNMR) / 2", 

56 command="bob bio metrics", 

57 ), 

58 criteria=CRITERIA, 

59) 

60@common_options.cost_option() 

61@click.option( 

62 "--score-column", 

63 default="score", 

64 show_default=True, 

65 help=( 

66 "Selects the CSV column to consider as scores. This is ignored for " 

67 "non-CSV files. The column must contain numerical values." 

68 ), 

69) 

70def metrics(ctx, scores, evaluation, score_column, **kwargs): 

71 if "criterion" in ctx.meta and ctx.meta["criterion"] == "rr": 

72 process = bio_figure.Metrics( 

73 ctx, 

74 scores, 

75 evaluation, 

76 functools.partial(load.cmc, csv_score_column=score_column), 

77 ) 

78 else: 

79 process = bio_figure.Metrics( 

80 ctx, 

81 scores, 

82 evaluation, 

83 functools.partial(load.split, csv_score_column=score_column), 

84 ) 

85 process.run() 

86 

87 

88@common_options.roc_command( 

89 common_options.ROC_HELP.format( 

90 score_format=SCORE_FORMAT, command="bob bio roc" 

91 ) 

92) 

93@click.option( 

94 "--score-column", 

95 default="score", 

96 show_default=True, 

97 help=( 

98 "Selects the CSV column to consider as scores. This is ignored for " 

99 "non-CSV files. The column must contain numerical values." 

100 ), 

101) 

102def roc(ctx, scores, evaluation, score_column, **kwargs): 

103 process = bio_figure.Roc( 

104 ctx, 

105 scores, 

106 evaluation, 

107 functools.partial(load.split, csv_score_column=score_column), 

108 ) 

109 process.run() 

110 

111 

112@common_options.det_command( 

113 common_options.DET_HELP.format( 

114 score_format=SCORE_FORMAT, command="bob bio det" 

115 ) 

116) 

117@click.option( 

118 "--score-column", 

119 default="score", 

120 show_default=True, 

121 help=( 

122 "Selects the CSV column to consider as scores. This is ignored for " 

123 "non-CSV files. The column must contain numerical values." 

124 ), 

125) 

126def det(ctx, scores, evaluation, score_column, **kwargs): 

127 process = bio_figure.Det( 

128 ctx, 

129 scores, 

130 evaluation, 

131 functools.partial(load.split, csv_score_column=score_column), 

132 ) 

133 process.run() 

134 

135 

136@common_options.epc_command( 

137 common_options.EPC_HELP.format( 

138 score_format=SCORE_FORMAT, command="bob bio epc" 

139 ) 

140) 

141@click.option( 

142 "--score-column", 

143 default="score", 

144 show_default=True, 

145 help=( 

146 "Selects the CSV column to consider as scores. This is ignored for " 

147 "non-CSV files. The column must contain numerical values." 

148 ), 

149) 

150def epc(ctx, scores, score_column, **kwargs): 

151 process = measure_figure.Epc( 

152 ctx, 

153 scores, 

154 True, 

155 functools.partial(load.split, csv_score_column=score_column), 

156 ) 

157 process.run() 

158 

159 

160@common_options.hist_command( 

161 common_options.HIST_HELP.format( 

162 score_format=SCORE_FORMAT, command="bob bio hist" 

163 ) 

164) 

165@click.option( 

166 "--score-column", 

167 default="score", 

168 show_default=True, 

169 help=( 

170 "Selects the CSV column to consider as scores. This is ignored for " 

171 "non-CSV files. The column must contain numerical values." 

172 ), 

173) 

174def hist(ctx, scores, evaluation, score_column, **kwargs): 

175 process = bio_figure.Hist( 

176 ctx, 

177 scores, 

178 evaluation, 

179 functools.partial(load.split, csv_score_column=score_column), 

180 ) 

181 process.run() 

182 

183 

184@common_options.evaluate_command( 

185 common_options.EVALUATE_HELP.format( 

186 score_format=SCORE_FORMAT, command="bob bio evaluate" 

187 ), 

188 criteria=CRITERIA, 

189) 

190@click.option( 

191 "--score-column", 

192 default="score", 

193 show_default=True, 

194 help=( 

195 "NOT YET IMPLEMENTED. " 

196 "Selects the CSV column to consider as scores. This is ignored for " 

197 "non-CSV files. The column must contain numerical values." 

198 ), 

199) 

200@common_options.cost_option() 

201def evaluate(ctx, scores, evaluation, score_column, **kwargs): 

202 if score_column != "score": 

203 raise NotImplementedError( 

204 "'evaluate' does not yet support files with scores in columns " 

205 "other than 'score'." 

206 ) 

207 common_options.evaluate_flow( 

208 ctx, scores, evaluation, metrics, roc, det, epc, hist, **kwargs 

209 ) 

210 

211 

212@common_options.multi_metrics_command( 

213 common_options.MULTI_METRICS_HELP.format( 

214 names="FtA, FAR, FRR, FMR, FNMR, HTER", 

215 criteria=CRITERIA, 

216 score_format=SCORE_FORMAT, 

217 command="bob bio multi-metrics", 

218 ), 

219 criteria=CRITERIA, 

220) 

221@click.option( 

222 "--score-column", 

223 default="score", 

224 show_default=True, 

225 help=( 

226 "Selects the CSV column to consider as scores. This is ignored for " 

227 "non-CSV files. The column must contain numerical values." 

228 ), 

229) 

230def multi_metrics( 

231 ctx, scores, evaluation, protocols_number, score_column, **kwargs 

232): 

233 ctx.meta["min_arg"] = protocols_number * (2 if evaluation else 1) 

234 process = bio_figure.MultiMetrics( 

235 ctx, 

236 scores, 

237 evaluation, 

238 functools.partial(load.split, csv_score_column=score_column), 

239 ) 

240 process.run() 

241 

242 

243@click.command() 

244@common_options.scores_argument(nargs=-1) 

245@common_options.titles_option() 

246@common_options.legends_option() 

247@common_options.sep_dev_eval_option() 

248@common_options.output_plot_file_option(default_out="cmc.pdf") 

249@common_options.eval_option() 

250@common_options.semilogx_option(True) 

251@common_options.axes_val_option(dflt=None) 

252@common_options.x_rotation_option() 

253@common_options.const_layout_option() 

254@common_options.style_option() 

255@common_options.linestyles_option() 

256@common_options.figsize_option() 

257@verbosity_option(logger=logger) 

258@click.pass_context 

259def cmc(ctx, scores, evaluation, **kwargs): 

260 """Plot CMC (cumulative match characteristic curve). 

261 graphical presentation of results of an identification task eval, plotting 

262 rank values on the x-axis and the probability of correct identification at 

263 or below that rank on the y-axis. The values for the axis will be computed 

264 using :py:func:`bob.measure.cmc`. 

265 

266 You need to provide one or more development score file(s) for each 

267 experiment. You can also provide eval files along with dev files. If 

268 eval-scores are used, the flag `--eval` must be used. is required 

269 in that case. Files must be 4- or 5- columns format, see 

270 :py:func:`bob.bio.base.score.load.four_column` and 

271 :py:func:`bob.bio.base.score.load.five_column` for details. 

272 

273 

274 Examples: 

275 $ bob bio cmc -v dev-scores 

276 

277 $ bob bio cmc -v dev-scores1 eval-scores1 dev-scores2 

278 eval-scores2 

279 

280 $ bob bio cmc -v -o my_roc.pdf dev-scores1 eval-scores1 

281 """ 

282 process = bio_figure.Cmc(ctx, scores, evaluation, load.cmc) 

283 process.run() 

284 

285 

286@click.command() 

287@common_options.scores_argument(nargs=-1) 

288@common_options.titles_option() 

289@common_options.legends_option() 

290@common_options.sep_dev_eval_option() 

291@common_options.output_plot_file_option(default_out="dir.pdf") 

292@common_options.eval_option() 

293@common_options.semilogx_option(True) 

294@common_options.axes_val_option(dflt=None) 

295@common_options.x_rotation_option() 

296@rank_option() 

297@common_options.const_layout_option() 

298@common_options.style_option() 

299@common_options.linestyles_option() 

300@common_options.figsize_option() 

301@common_options.min_far_option() 

302@verbosity_option(logger=logger) 

303@click.pass_context 

304def dir(ctx, scores, evaluation, **kwargs): 

305 """Plots the Detection & Identification Rate curve over the FAR. 

306 

307 This curve is designed to be used in an open set identification protocol, 

308 and defined in Chapter 14.1 of [LiJain2005]_. It requires to have at least 

309 one open set probe item, i.e., with no corresponding gallery, such that the 

310 positives for that pair are ``None``. 

311 

312 The detection and identification curve first computes FAR thresholds based 

313 on the out-of-set probe scores (negative scores). For each probe item, the 

314 **maximum** negative score is used. Then, it plots the detection and 

315 identification rates for those thresholds, which are based on the in-set 

316 probe scores only. See [LiJain2005]_ for more details. 

317 

318 .. [LiJain2005] **Stan Li and Anil K. Jain**, *Handbook of Face Recognition*, Springer, 2005 

319 

320 You need to provide one or more development score file(s) for each 

321 experiment. You can also provide eval files along with dev files. If 

322 eval-scores are used, the flag `--eval` must be used. is required 

323 in that case. Files must be 4- or 5- columns format, see 

324 :py:func:`bob.bio.base.score.load.four_column` and 

325 :py:func:`bob.bio.base.score.load.five_column` for details. 

326 

327 Examples: 

328 $ bob bio dir -e -v dev-scores 

329 

330 $ bob bio dir -v dev-scores1 eval-scores1 dev-scores2 

331 eval-scores2 

332 

333 $ bob bio dir -v -o my_roc.pdf dev-scores1 eval-scores1 

334 """ 

335 process = bio_figure.Dir(ctx, scores, evaluation, load.cmc) 

336 process.run()