Coverage for src/bob/bio/face/reports/multipie.py: 0%

109 statements  

« prev     ^ index     » next       coverage.py v7.6.0, created at 2024-07-13 00:04 +0200

1import itertools 

2 

3import matplotlib.pyplot as plt 

4import numpy as np 

5 

6from matplotlib.backends.backend_pdf import PdfPages 

7 

8import bob.measure 

9 

10from bob.bio.base.score.load import get_split_dataframe 

11 

12 

13def _get_colors_markers(): 

14 l_styles = ["-", "--", "-.", ":", "-.-"] 

15 m_styles = [".", "o", "^", "*", "o"] 

16 

17 return itertools.product(l_styles, m_styles) 

18 

19 

20def multipie_pose_report( 

21 scores_dev, 

22 scores_eval, 

23 output_filename, 

24 titles, 

25 figsize=(16, 8), 

26 fmr_threshold=1e-3, 

27 colors=plt.cm.tab10.colors, 

28 optimal_threshold=False, 

29 threshold_eval=False, 

30): 

31 """ 

32 Compute the multipie pose report, ploting the FNMR for each view point 

33 

34 Parameters 

35 ---------- 

36 

37 scores_dev: 

38 

39 scores_eval: 

40 

41 output_filename: 

42 

43 titles: 

44 

45 figsize=(16, 8): 

46 

47 fmr_threshold: 

48 

49 colors: 

50 Color palete 

51 

52 optimal_threshold: bool 

53 If set it to `True`, it will compute one decision threshold for each 

54 subprotocol (for each pose). Default to false. 

55 

56 threshold_eval: bool 

57 If set it to `True` it will compute the threshold using the evaluation set. 

58 Default obviouslly to `False`. 

59 

60 """ 

61 

62 cameras = [ 

63 "11_0", 

64 "12_0", 

65 "09_0", 

66 "08_0", 

67 "13_0", 

68 "14_0", 

69 "05_1", 

70 "05_0", 

71 "04_1", 

72 "19_0", 

73 "20_0", 

74 "01_0", 

75 "24_0", 

76 ] 

77 

78 angles = np.linspace(-90, 90, len(cameras)) 

79 camera_to_angle = dict(zip(cameras, angles)) 

80 

81 pdf = PdfPages(output_filename) 

82 

83 # Figure for eval plot 

84 fig = plt.figure(figsize=figsize) 

85 ax = fig.add_subplot(111) 

86 style_iterator = _get_colors_markers() 

87 

88 for d_scores, e_scores, title, (linestyle, marker), color in zip( 

89 scores_dev, scores_eval, titles, style_iterator, colors 

90 ): 

91 # Load the score files and fill in the angle associated to each camera 

92 impostors_dev, genuines_dev = get_split_dataframe(d_scores) 

93 impostors_eval, genuines_eval = get_split_dataframe(e_scores) 

94 

95 # loading the dask dataframes 

96 impostors_dev = impostors_dev.compute() 

97 genuines_dev = genuines_dev.compute() 

98 impostors_eval = impostors_eval.compute() 

99 genuines_eval = genuines_eval.compute() 

100 

101 # Appending the angle 

102 impostors_dev["angle"] = impostors_dev["probe_camera"].map( 

103 camera_to_angle 

104 ) 

105 genuines_dev["angle"] = genuines_dev["probe_camera"].map( 

106 camera_to_angle 

107 ) 

108 impostors_eval["angle"] = impostors_eval["probe_camera"].map( 

109 camera_to_angle 

110 ) 

111 genuines_eval["angle"] = genuines_eval["probe_camera"].map( 

112 camera_to_angle 

113 ) 

114 

115 angles = [] 

116 eval_fmr_fnmr = [] 

117 

118 # Compute the min. HTER threshold on the Dev set 

119 threshold = None 

120 if not optimal_threshold: 

121 if threshold_eval: 

122 threshold = bob.measure.far_threshold( 

123 impostors_eval["score"].to_numpy(), 

124 genuines_eval["score"].to_numpy(), 

125 fmr_threshold, 

126 ) 

127 else: 

128 threshold = bob.measure.far_threshold( 

129 impostors_dev["score"].to_numpy(), 

130 genuines_dev["score"].to_numpy(), 

131 fmr_threshold, 

132 ) 

133 

134 # Run the analysis per view angle 

135 for ( 

136 (angle, i_dev), 

137 (_, g_dev), 

138 (_, i_eval), 

139 (_, g_eval), 

140 ) in zip( 

141 impostors_dev.groupby("angle"), 

142 genuines_dev.groupby("angle"), 

143 impostors_eval.groupby("angle"), 

144 genuines_eval.groupby("angle"), 

145 ): 

146 if optimal_threshold: 

147 if threshold_eval: 

148 threshold = bob.measure.far_threshold( 

149 i_eval["score"].to_numpy(), 

150 g_eval["score"].to_numpy(), 

151 fmr_threshold, 

152 ) 

153 else: 

154 threshold = bob.measure.far_threshold( 

155 i_dev["score"].to_numpy(), 

156 g_dev["score"].to_numpy(), 

157 fmr_threshold, 

158 ) 

159 

160 eval_fmr, eval_fnmr = bob.measure.farfrr( 

161 i_eval["score"].to_numpy(), 

162 g_eval["score"].to_numpy(), 

163 threshold, 

164 ) 

165 # eval_fnmr = (eval_fnmr + eval_fmr) / 2 

166 

167 angles.append(angle) 

168 eval_fmr_fnmr.append([eval_fmr, eval_fnmr]) 

169 

170 # eval_hter = (1 / 2 * (eval_far + eval_frr)) * 100 

171 # eval_hter = eval_frr * 100 

172 # eval_hters.append(eval_hter) 

173 

174 # Update plots 

175 

176 fnrms = [fnmr * 100 for fmr, fnmr in eval_fmr_fnmr] 

177 # fmrs = [-fmr * 100 for fmr, fnmr in eval_fmr_fnmr] 

178 plt.plot( 

179 angles, 

180 fnrms, 

181 label=title, 

182 linestyle=linestyle, 

183 marker=marker, 

184 linewidth=2, 

185 color=color, 

186 ) 

187 

188 # plt.plot( 

189 # angles, fnrms, label=title, linestyle=linestyle, marker=marker, linewidth=2, 

190 # ) 

191 if threshold_eval: 

192 plt.title(f"FNMR. at Eval. FMR@{fmr_threshold*100}%", fontsize=16) 

193 else: 

194 plt.title(f"FNMR. at Dev. FMR@{fmr_threshold*100}%", fontsize=16) 

195 plt.xlabel("Angle", fontsize=12) 

196 plt.ylabel("FNMR(%)", fontsize=14) 

197 plt.legend() 

198 plt.grid() 

199 

200 # Plot finalization 

201 

202 xticks = [-90, -75, -60, -45, -30, -15, 0, 15, 30, 45, 60, 75, 90] 

203 plt.xticks(xticks) 

204 ax.set_xticklabels(xticks, fontsize=10) 

205 

206 yticks = np.array([0, 20, 40, 60, 80, 100]) 

207 ax.set_yticks(yticks) 

208 ax.set_yticklabels(yticks, fontsize=12) 

209 

210 pdf.savefig(fig) 

211 pdf.close() 

212 

213 

214def multipie_expression_report( 

215 scores_dev, 

216 scores_eval, 

217 output_filename, 

218 titles, 

219 fmr_threshold=1e-3, 

220 figsize=(16, 8), 

221 y_abs_max=60, # Max absolute value for y axis 

222 colors=plt.cm.tab10.colors, 

223): 

224 # "all", 

225 expressions = [ 

226 "neutral", 

227 "smile", 

228 "surprise", 

229 "squint", 

230 "disgust", 

231 "scream", 

232 ] 

233 

234 # style_iterator = _get_colors_markers() 

235 # colors = plt.cm.tab20.colors 

236 

237 eval_fmr_fnmr_expressions = dict() 

238 

239 for ( 

240 d_scores, 

241 e_scores, 

242 title, 

243 ) in zip(scores_dev, scores_eval, titles): 

244 eval_fmr_fnmr_expressions[title] = [] 

245 

246 # Load the score files and fill in the angle associated to each camera 

247 impostors_dev, genuines_dev = get_split_dataframe(d_scores) 

248 impostors_eval, genuines_eval = get_split_dataframe(e_scores) 

249 

250 # loading the dask dataframes 

251 impostors_dev = impostors_dev.compute() 

252 genuines_dev = genuines_dev.compute() 

253 impostors_eval = impostors_eval.compute() 

254 genuines_eval = genuines_eval.compute() 

255 

256 # Computing the threshold combining all distances 

257 threshold = bob.measure.far_threshold( 

258 impostors_dev["score"].to_numpy(), 

259 genuines_dev["score"].to_numpy(), 

260 fmr_threshold, 

261 ) 

262 

263 def compute_fmr_fnmr(impostor_scores, genuine_scores): 

264 eval_fmr, eval_fnmr = bob.measure.farfrr( 

265 impostor_scores["score"].to_numpy(), 

266 genuine_scores["score"].to_numpy(), 

267 threshold, 

268 ) 

269 return eval_fmr, eval_fnmr 

270 

271 # All expressions 

272 # i_eval = impostors_eval 

273 # g_eval = genuines_eval 

274 # eval_fmr_fnmr_expressions[title].append(compute_fmr_fnmr(i_eval, g_eval)) 

275 

276 # EVALUATING DIFFERENT TYPES OF EXPRESSION 

277 for expression in expressions: 

278 i_eval = impostors_eval.loc[ 

279 impostors_eval.probe_expression == expression 

280 ] 

281 g_eval = genuines_eval.loc[ 

282 genuines_eval.probe_expression == expression 

283 ] 

284 

285 eval_fmr_fnmr_expressions[title].append( 

286 compute_fmr_fnmr(i_eval, g_eval) 

287 ) 

288 

289 pass 

290 

291 # Plotting 

292 pdf = PdfPages(output_filename) 

293 

294 # Figure for eval plot 

295 fig = plt.figure(figsize=figsize) 

296 ax = fig.add_subplot(111) 

297 

298 width = 0.8 / len(titles) 

299 

300 X = np.arange(len(expressions)) 

301 

302 for i, (title, color) in enumerate(zip(titles, colors)): 

303 fmrs = [-1 * fmr * 100 for fmr, _ in eval_fmr_fnmr_expressions[title]] 

304 fnmrs = [fnmr * 100 for _, fnmr in eval_fmr_fnmr_expressions[title]] 

305 

306 x_axis = X + (i + 1) * width - width / 2 

307 ax.bar( 

308 x_axis, 

309 fmrs, 

310 width, 

311 label=title, 

312 color=color, 

313 alpha=1, 

314 hatch="\\", 

315 ) 

316 ax.bar( 

317 x_axis, 

318 fnmrs, 

319 width, 

320 color=color, 

321 alpha=0.5, 

322 hatch="/", 

323 ) 

324 # str(int(fnmr)) if fnmr == 0 else str(round(fnmr, 1)) 

325 # Writting the texts on top of the bar plots 

326 for i, fnmr, fmr in zip(x_axis, fnmrs, fmrs): 

327 plt.text( 

328 i - width / 2, 

329 fnmr + 0.8, 

330 str(int(fnmr)), 

331 fontsize=10, 

332 ) 

333 plt.text( 

334 i - width / 2, 

335 fmr - 2.8, 

336 str(int(abs(fmr))), 

337 fontsize=10, 

338 ) 

339 

340 # Plot finalization 

341 plt.title(f"FMR vs FNMR. at Dev. FMR@{fmr_threshold*100}%", fontsize=16) 

342 ax.set_xlabel("Expressions", fontsize=12) 

343 ax.set_ylabel("FMR(%) vs FNMR(%) ", fontsize=14) 

344 

345 ax.set_xticks(X + 0.5) 

346 ax.set_xticklabels(expressions) 

347 

348 yticks = np.array( 

349 [ 

350 -y_abs_max / 8, 

351 0, 

352 y_abs_max / 4, 

353 y_abs_max / 2, 

354 y_abs_max, 

355 ] 

356 ) 

357 

358 ax.set_yticks(yticks) 

359 ax.set_yticklabels([int(abs(y)) for y in yticks], fontsize=16) 

360 

361 plt.axhline(0, linestyle="-", color="k") 

362 plt.ylim([-y_abs_max / 8, y_abs_max + 1]) 

363 

364 plt.legend() 

365 plt.grid() 

366 

367 pdf.savefig(fig) 

368 

369 pdf.close()