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
« prev ^ index » next coverage.py v7.6.0, created at 2024-07-13 00:04 +0200
1import itertools
3import matplotlib.pyplot as plt
4import numpy as np
6from matplotlib.backends.backend_pdf import PdfPages
8import bob.measure
10from bob.bio.base.score.load import get_split_dataframe
13def _get_colors_markers():
14 l_styles = ["-", "--", "-.", ":", "-.-"]
15 m_styles = [".", "o", "^", "*", "o"]
17 return itertools.product(l_styles, m_styles)
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
34 Parameters
35 ----------
37 scores_dev:
39 scores_eval:
41 output_filename:
43 titles:
45 figsize=(16, 8):
47 fmr_threshold:
49 colors:
50 Color palete
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.
56 threshold_eval: bool
57 If set it to `True` it will compute the threshold using the evaluation set.
58 Default obviouslly to `False`.
60 """
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 ]
78 angles = np.linspace(-90, 90, len(cameras))
79 camera_to_angle = dict(zip(cameras, angles))
81 pdf = PdfPages(output_filename)
83 # Figure for eval plot
84 fig = plt.figure(figsize=figsize)
85 ax = fig.add_subplot(111)
86 style_iterator = _get_colors_markers()
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)
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()
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 )
115 angles = []
116 eval_fmr_fnmr = []
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 )
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 )
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
167 angles.append(angle)
168 eval_fmr_fnmr.append([eval_fmr, eval_fnmr])
170 # eval_hter = (1 / 2 * (eval_far + eval_frr)) * 100
171 # eval_hter = eval_frr * 100
172 # eval_hters.append(eval_hter)
174 # Update plots
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 )
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()
200 # Plot finalization
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)
206 yticks = np.array([0, 20, 40, 60, 80, 100])
207 ax.set_yticks(yticks)
208 ax.set_yticklabels(yticks, fontsize=12)
210 pdf.savefig(fig)
211 pdf.close()
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 ]
234 # style_iterator = _get_colors_markers()
235 # colors = plt.cm.tab20.colors
237 eval_fmr_fnmr_expressions = dict()
239 for (
240 d_scores,
241 e_scores,
242 title,
243 ) in zip(scores_dev, scores_eval, titles):
244 eval_fmr_fnmr_expressions[title] = []
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)
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()
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 )
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
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))
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 ]
285 eval_fmr_fnmr_expressions[title].append(
286 compute_fmr_fnmr(i_eval, g_eval)
287 )
289 pass
291 # Plotting
292 pdf = PdfPages(output_filename)
294 # Figure for eval plot
295 fig = plt.figure(figsize=figsize)
296 ax = fig.add_subplot(111)
298 width = 0.8 / len(titles)
300 X = np.arange(len(expressions))
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]]
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 )
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)
345 ax.set_xticks(X + 0.5)
346 ax.set_xticklabels(expressions)
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 )
358 ax.set_yticks(yticks)
359 ax.set_yticklabels([int(abs(y)) for y in yticks], fontsize=16)
361 plt.axhline(0, linestyle="-", color="k")
362 plt.ylim([-y_abs_max / 8, y_abs_max + 1])
364 plt.legend()
365 plt.grid()
367 pdf.savefig(fig)
369 pdf.close()