Coverage for src/bob/bio/face/script/display_face_annotations.py: 84%

79 statements  

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

1#!../bin/python 

2 

3"""This script displays the images with annotations provided by any face database. 

4 

5By default, all images and their corresponding annotations are displayed, and you have to press ``Enter`` after each image. 

6If the database does not include annotations, or you want to display a different set of annotations, you can specify the ``--annotation-directory`` (and if required modify the ``--annotation-file-extension`` and ``--annotation-file-type``. 

7The list of images can be narrowed down by the ``--file-ids`` parameter, where the file ids are specific to the database. 

8 

9Note that this script can only be used with face image databases, not with video or other biometric databases. 

10""" 

11 

12from __future__ import print_function 

13 

14import logging 

15import os 

16 

17import click 

18 

19from clapper.click import ConfigCommand, ResourceOption, verbosity_option 

20 

21from bob.bio.base.utils.annotations import read_annotation_file 

22from bob.bio.face.color import gray_to_rgb 

23 

24logger = logging.getLogger(__name__) 

25 

26 

27@click.command( 

28 entry_point_group="bob.bio.config", 

29 cls=ConfigCommand, 

30 epilog="""\b 

31Examples: 

32 

33 $ bob bio display-face-annotations -vvv -d <database> -a <annot_dir> 

34""", 

35) 

36@click.option( 

37 "-d", 

38 "--database", 

39 required=True, 

40 cls=ResourceOption, 

41 entry_point_group="bob.bio.database", 

42 help="Select the database for which the images plus annotations should be shown.", 

43) 

44@click.option( 

45 "-V", 

46 "--video", 

47 "is_video", 

48 is_flag=True, 

49 help="Provide this flag if your database is a video database. " 

50 "For video databases, the annotations for the first frame is shown.", 

51) 

52@click.option( 

53 "-a", 

54 "--annotations-dir", 

55 help="Use the annotations stored in this directory " 

56 "(when annotated with `$ bob bio annnotate` for example). " 

57 "If not given, will try to load the annotations from the database.", 

58) 

59@click.option( 

60 "-x", 

61 "--annotations-extension", 

62 default=".json", 

63 show_default=True, 

64 help="Annotations files have the given filename extension.", 

65) 

66@click.option( 

67 "-t", 

68 "--annotations-type", 

69 default="json", 

70 show_default=True, 

71 help="Annotations type given to bob.bio.base.read_annotations.", 

72) 

73@click.option( 

74 "-n", 

75 "--display-names", 

76 is_flag=True, 

77 help="Plot the names of the annotations, too.", 

78) 

79@click.option( 

80 "-m", 

81 "--marker-style", 

82 default="rx", 

83 show_default=True, 

84 help="Select the marker style", 

85) 

86@click.option( 

87 "-M", 

88 "--marker-size", 

89 type=float, 

90 default=10.0, 

91 show_default=True, 

92 help="Select the marker size", 

93) 

94@click.option( 

95 "-C", 

96 "--font-color", 

97 default="b", 

98 show_default=True, 

99 help="Select the color for the annotations names", 

100) 

101@click.option( 

102 "-F", 

103 "--font-size", 

104 type=int, 

105 default=16, 

106 show_default=True, 

107 help="Select the font size for the annotations names", 

108) 

109@click.option( 

110 "-o", 

111 "--output-dir", 

112 help="If given, it will save the plots in this output file instead of showing them. This option is useful when you don't have a display server (ssh).", 

113) 

114@click.option( 

115 "-k", 

116 "--keep-all", 

117 is_flag=True, 

118 help="When -o is given: keeps every annotated samples instead of just one.", 

119) 

120@click.option( 

121 "--self-test", 

122 is_flag=True, 

123 help="Prevents outputing to the screen and waiting for user input.", 

124) 

125@click.option( 

126 "--groups", 

127 "-g", 

128 multiple=True, 

129 default=["dev", "eval"], 

130 show_default=True, 

131 help="Biometric Database group that will be displayed.", 

132) 

133@verbosity_option(logger=logger, expose_value=False) 

134def display_face_annotations( 

135 database, 

136 is_video, 

137 annotations_dir, 

138 annotations_extension, 

139 annotations_type, 

140 marker_style, 

141 marker_size, 

142 display_names, 

143 font_color, 

144 font_size, 

145 output_dir, 

146 keep_all, 

147 self_test, 

148 groups, 

149 **kwargs, 

150): 

151 """ 

152 Plots annotations on the corresponding face picture. 

153 """ 

154 logger.debug("Retrieving samples from database.") 

155 samples = database.all_samples(groups) 

156 

157 logger.debug(f"{len(samples)} samples loaded from database.") 

158 

159 # open figure 

160 from matplotlib import pyplot 

161 

162 if not self_test and not output_dir: 

163 pyplot.ion() 

164 pyplot.show() 

165 else: 

166 pyplot.ioff() 

167 pyplot.figure() 

168 

169 for sample in samples: 

170 # load image 

171 logger.info("loading image for sample %s", sample.key) 

172 image = sample.data 

173 if is_video: 

174 frame_id, image, _ = image[0] 

175 # convert to color if it is not 

176 if image.ndim == 2: 

177 image = gray_to_rgb(image) 

178 

179 # get annotations 

180 annotations = {} 

181 if annotations_dir is not None: 

182 # Loads the corresponding annotations file 

183 annotations_file = os.path.join( 

184 annotations_dir, sample.key + annotations_extension 

185 ) 

186 if os.path.exists(annotations_file): 

187 logger.info( 

188 "Loading annotations from file %s", annotations_file 

189 ) 

190 annotations = read_annotation_file( 

191 annotations_file, annotations_type 

192 ) 

193 else: 

194 logger.warn( 

195 "Could not find annotation file %s", annotations_file 

196 ) 

197 else: 

198 # get annotations from database 

199 annotations = database.annotations(sample) 

200 

201 if not annotations: 

202 logger.warn("Could not find annotations for file %s", sample.key) 

203 continue 

204 

205 if is_video: 

206 assert frame_id in annotations, annotations 

207 annotations = annotations[frame_id] 

208 

209 pyplot.clf() 

210 pyplot.imshow(image.transpose(1, 2, 0)) 

211 

212 global_annotation = [] 

213 for n, a in annotations.items(): 

214 if isinstance(a, (list, tuple)) and len(a) == 2: 

215 pyplot.plot( 

216 a[1], 

217 a[0], 

218 marker_style, 

219 ms=marker_size, 

220 mew=marker_size / 5.0, 

221 ) 

222 if display_names: 

223 pyplot.annotate( 

224 n, (a[1], a[0]), color=font_color, fontsize=font_size 

225 ) 

226 else: 

227 global_annotation.append("%s=%s" % (n, a)) 

228 

229 # plot all global annotations, at the top center of the image 

230 pyplot.annotate( 

231 ";".join(global_annotation), 

232 (image.shape[-1] / 2, 0), 

233 color=font_color, 

234 fontsize=font_size, 

235 ha="center", 

236 va="baseline", 

237 ) 

238 

239 pyplot.gca().set_aspect("equal") 

240 pyplot.gca().autoscale(tight=True) 

241 

242 if output_dir is None: 

243 if self_test: 

244 raise RuntimeError("Do not run self_test without --output_dir.") 

245 pyplot.pause(0.001) 

246 else: 

247 if keep_all: 

248 output_path = os.path.join(output_dir, sample.key + ".png") 

249 else: 

250 output_path = os.path.join(output_dir, "annotated.png") 

251 os.makedirs(os.path.dirname(output_path), exist_ok=True) 

252 pyplot.savefig(output_path) 

253 

254 if not self_test: 

255 input_text = ( 

256 "Press Enter to continue to the next image (or Ctrl-C to exit)" 

257 ) 

258 input(input_text)