Coverage for src/bob/bio/face/database/vgg2.py: 91%

35 statements  

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

1#!/usr/bin/env python 

2# vim: set fileencoding=utf-8 : 

3# Tiago de Freitas Pereira <tiago.pereira@idiap.ch> 

4 

5import logging 

6 

7logger = logging.getLogger(__name__) 

8 

9 

10""" 

11 VGG2 database implementation 

12""" 

13 

14from clapper.rc import UserDefaults 

15from sklearn.base import BaseEstimator, TransformerMixin 

16from sklearn.pipeline import make_pipeline 

17 

18import bob.io.base 

19 

20from bob.bio.base.database import CSVDatabase, FileSampleLoader 

21from bob.pipelines import DelayedSample 

22 

23rc = UserDefaults("bobrc.toml") 

24 

25 

26class VGG2Annotations(TransformerMixin, BaseEstimator): 

27 """ 

28 Decode VGG2 Annotations. 

29 

30 VGG2 has 5 landmarks annotated and the are the following: two for eyes, one for the nose and two for the mouth 

31 

32 """ 

33 

34 def fit(self, X, y=None): 

35 return self 

36 

37 def _more_tags(self): 

38 return { 

39 "requires_fit": False, 

40 } 

41 

42 def transform(self, X): 

43 """ 

44 Convert leye_x, leye_y, reye_x, reye_y attributes to `annotations = (leye, reye)` 

45 """ 

46 

47 annotated_samples = [] 

48 

49 for x in X: 

50 annotations = { 

51 "leye": ( 

52 float(x.leye_y), 

53 float(x.leye_x), 

54 ), 

55 "reye": ( 

56 float(x.reye_y), 

57 float(x.reye_x), 

58 ), 

59 "nose": ( 

60 float(x.nose_y), 

61 float(x.nose_x), 

62 ), 

63 "lmouth": ( 

64 float(x.lmouth_y), 

65 float(x.lmouth_x), 

66 ), 

67 "rmouth": ( 

68 float(x.rmouth_y), 

69 float(x.rmouth_x), 

70 ), 

71 "topleft": ( 

72 float(x.face_y), 

73 float(x.face_x), 

74 ), 

75 "size": ( 

76 float(x.face_h), 

77 float(x.face_w), 

78 ), 

79 } 

80 

81 sample = DelayedSample.from_sample(x, annotations=annotations) 

82 # Cleaning up 

83 [ 

84 delattr(sample, a) 

85 for a in [ 

86 "leye_x", 

87 "leye_y", 

88 "reye_x", 

89 "reye_y", 

90 "nose_y", 

91 "nose_x", 

92 "face_y", 

93 "face_x", 

94 "face_h", 

95 "face_w", 

96 "lmouth_y", 

97 "lmouth_x", 

98 "rmouth_y", 

99 "rmouth_x", 

100 ] 

101 ] 

102 annotated_samples.append(sample) 

103 

104 return annotated_samples 

105 

106 

107class VGG2Database(CSVDatabase): 

108 """ 

109 The VGG2 Dataset is composed of 9131 people split into two sets. 

110 The training set contains 8631 identities, while the test set contains 500 identities. 

111 

112 As metadata, this dataset contains the gender labels "m" and "f" for, respectively, male and female. 

113 It also contains the following race labels: 

114 

115 - A: Asian in general (Chinese, Japanese, Filipino, Korean, Polynesian, Indonesian, Samoan, or any other Pacific Islander 

116 - B: A person having origins in any of the black racial groups of Africa 

117 - I: American Indian, Asian Indian, Eskimo, or Alaskan native 

118 - U: Of indeterminable race 

119 - W: Caucasian, Mexican, Puerto Rican, Cuban, Central or South American, or other Spanish culture or origin, Regardless of race 

120 - N: None of the above 

121 

122 Race labels are taken from: MasterEBTSv10.0.809302017_Final.pdf. 

123 

124 This dataset also contains sets for `T-Norm` and `Z-Norm`, normalization. 

125 

126 

127 We provide four protocols; `vgg2-short`, `vgg2-full`,`vgg2-short-with-eval`, `vgg2-full-with-eval`. 

128 The `vgg2-short` and `vgg2-full` present the sample amount of identities but 

129 varies with respect to the number of samples per identity. 

130 The `vgg2-full` preserves the number of samples per identity from the original dataset. 

131 On the other hand, the `vgg2-short` presents 10 samples per identity at the probe and training sets. 

132 With that the training set of `vgg2-short` contains 86'310 samples instead of 3'141'890 samples 

133 from `vgg2-full`. 

134 The protocols with the suffix `-with-eval`, splits the original test set into a dev and eval sets 

135 containing 250 identities each. 

136 

137 

138 All the landmarks and face crops provided in the original dataset is provided with this interface. 

139 

140 .. warning:: 

141 

142 To use this dataset protocol, you need to have the original files of the VGG2 dataset. 

143 Once you have it downloaded, please run the following command to set the path for Bob 

144 

145 .. code-block:: sh 

146 

147 bob config set bob.bio.face.vgg2.directory [VGG2 PATH] 

148 bob config set bob.bio.face.vgg2.extension [VGG2 EXTENSION] 

149 

150 For more information check: 

151 

152 .. code-block:: latex 

153 

154 @inproceedings{cao2018vggface2, 

155 title={Vggface2: A dataset for recognising faces across pose and age}, 

156 author={Cao, Qiong and Shen, Li and Xie, Weidi and Parkhi, Omkar M and Zisserman, Andrew}, 

157 booktitle={2018 13th IEEE international conference on automatic face \\& gesture recognition (FG 2018)}, 

158 pages={67--74}, 

159 year={2018}, 

160 organization={IEEE} 

161 } 

162 """ 

163 

164 name = "vgg2" 

165 category = "face" 

166 dataset_protocols_name = "vgg2.tar.gz" 

167 dataset_protocols_urls = [ 

168 "https://www.idiap.ch/software/bob/databases/latest/face/vgg2-8c067663.tar.gz", 

169 "http://www.idiap.ch/software/bob/databases/latest/face/vgg2-8c067663.tar.gz", 

170 ] 

171 dataset_protocols_hash = "8c067663" 

172 

173 def __init__( 

174 self, 

175 protocol, 

176 dataset_original_directory=rc.get("bob.bio.face.vgg2.directory", ""), 

177 dataset_original_extension=rc.get( 

178 "bob.bio.face.vgg2.extension", ".jpg" 

179 ), 

180 annotation_type="eyes-center", 

181 fixed_positions=None, 

182 ): 

183 super().__init__( 

184 name=self.name, 

185 protocol=protocol, 

186 transformer=make_pipeline( 

187 FileSampleLoader( 

188 data_loader=bob.io.base.load, 

189 dataset_original_directory=dataset_original_directory, 

190 extension=dataset_original_extension, 

191 ), 

192 VGG2Annotations(), 

193 ), 

194 templates_metadata=["gender", "race"], 

195 annotation_type=annotation_type, 

196 fixed_positions=fixed_positions, 

197 ) 

198 

199 def background_model_samples(self): 

200 if self.protocol == "vgg2-full": 

201 logger.warning( 

202 "This set is very long (3M samples). It might take ~4 minutes to load everything" 

203 ) 

204 return super().background_model_samples()