Coverage for src/bob/bio/base/database/database.py: 41%

174 statements  

« prev     ^ index     » next       coverage.py v7.6.0, created at 2024-07-12 22:34 +0200

1#!/usr/bin/env python 

2# vim: set fileencoding=utf-8 : 

3 

4import abc 

5import os 

6 

7from .file import BioFile 

8from .legacy import FileDatabase as LegacyFileDatabase 

9 

10 

11class BioDatabase(LegacyFileDatabase, metaclass=abc.ABCMeta): 

12 """This class represents the basic API for database access. 

13 Please use this class as a base class for your database access classes. 

14 Do not forget to call the constructor of this base class in your derived class. 

15 

16 **Parameters:** 

17 

18 name : str 

19 A unique name for the database. 

20 

21 all_files_options : dict 

22 Dictionary of options passed to the :py:meth:`bob.bio.base.database.BioDatabase.objects` database query when retrieving all data. 

23 

24 extractor_training_options : dict 

25 Dictionary of options passed to the :py:meth:`bob.bio.base.database.BioDatabase.objects` database query used to retrieve the files for the extractor training. 

26 

27 projector_training_options : dict 

28 Dictionary of options passed to the :py:meth:`bob.bio.base.database.BioDatabase.objects` database query used to retrieve the files for the projector training. 

29 

30 enroller_training_options : dict 

31 Dictionary of options passed to the :py:meth:`bob.bio.base.database.BioDatabase.objects` database query used to retrieve the files for the enroller training. 

32 

33 check_original_files_for_existence : bool 

34 Enables to test for the original data files when querying the database. 

35 

36 original_directory : str 

37 The directory where the original data of the database are stored. 

38 

39 original_extension : str 

40 The file name extension of the original data. 

41 

42 annotation_directory : str 

43 The directory where the image annotations of the database are stored, if any. 

44 

45 annotation_extension : str 

46 The file name extension of the annotation files. 

47 

48 annotation_type : str 

49 The type of the annotation file to read, only json works. 

50 

51 protocol : str or ``None`` 

52 The name of the protocol that defines the default experimental setup for this database. 

53 

54 training_depends_on_protocol : bool 

55 Specifies, if the training set used for training the extractor and the projector depend on the protocol. 

56 This flag is used to avoid re-computation of data when running on the different protocols of the same database. 

57 

58 models_depend_on_protocol : bool 

59 Specifies, if the models depend on the protocol. 

60 This flag is used to avoid re-computation of models when running on the different protocols of the same database. 

61 

62 kwargs : ``key=value`` pairs 

63 The arguments of the `Database` base class constructor. 

64 

65 """ 

66 

67 # tell test runners (such as nose and pytest) that this class is not a test class 

68 ___test___ = False 

69 

70 def __init__( 

71 self, 

72 name, 

73 all_files_options={}, # additional options for the database query that can be used to extract all files 

74 extractor_training_options={}, 

75 # additional options for the database query that can be used to extract the training files for the extractor training 

76 projector_training_options={}, 

77 # additional options for the database query that can be used to extract the training files for the extractor training 

78 enroller_training_options={}, 

79 # additional options for the database query that can be used to extract the training files for the extractor training 

80 check_original_files_for_existence=False, 

81 original_directory=None, 

82 original_extension=None, 

83 annotation_directory=None, 

84 annotation_extension=None, 

85 annotation_type=None, 

86 protocol="Default", 

87 training_depends_on_protocol=False, 

88 models_depend_on_protocol=False, 

89 **kwargs, 

90 ): 

91 assert isinstance(name, str) 

92 

93 super(BioDatabase, self).__init__( 

94 original_directory=original_directory, 

95 original_extension=original_extension, 

96 **kwargs, 

97 ) 

98 

99 self.name = name 

100 

101 self.all_files_options = all_files_options 

102 self.extractor_training_options = extractor_training_options 

103 self.projector_training_options = projector_training_options 

104 self.enroller_training_options = enroller_training_options 

105 self.check_existence = check_original_files_for_existence 

106 

107 self._kwargs = {} 

108 

109 self.annotation_directory = annotation_directory 

110 self.annotation_extension = annotation_extension or ".json" 

111 self.annotation_type = annotation_type or "json" 

112 self.protocol = protocol 

113 self.training_depends_on_protocol = training_depends_on_protocol 

114 self.models_depend_on_protocol = models_depend_on_protocol 

115 self.models_depend_on_protocol = models_depend_on_protocol 

116 

117 # try if the implemented model_ids_with_protocol() and objects() function have at least the required interface 

118 try: 

119 # create a value that is very unlikely a valid value for anything 

120 test_value = "#6T7+§X" 

121 # test if the parameters of the functions apply 

122 self.model_ids_with_protocol(groups=test_value, protocol=test_value) 

123 self.objects( 

124 groups=test_value, 

125 protocol=test_value, 

126 purposes=test_value, 

127 model_ids=(test_value,), 

128 ) 

129 self.annotations(file=BioFile(test_value, test_value, test_value)) 

130 except TypeError as e: 

131 # type error indicates that the given parameters are not valid. 

132 raise NotImplementedError( 

133 str(e) 

134 + "\nPlease implement:\n - the model_ids_with_protocol(...) function with at least the " 

135 "arguments 'groups' and 'protocol'\n - the objects(...) function with at least the " 

136 "arguments 'groups', 'protocol', 'purposes' and 'model_ids'\n - the annotations() " 

137 "function with at least the arguments 'file_id'." 

138 ) 

139 except Exception: 

140 # any other error is fine at this stage. 

141 pass 

142 

143 def __str__(self): 

144 """__str__() -> info 

145 

146 This function returns all parameters of this class. 

147 

148 **Returns:** 

149 

150 info : str 

151 A string containing the full information of all parameters of this class. 

152 """ 

153 params = ( 

154 "name=%s, protocol=%s, original_directory=%s, original_extension=%s" 

155 % ( 

156 self.name, 

157 self.protocol, 

158 self.original_directory, 

159 self.original_extension, 

160 ) 

161 ) 

162 params += ", ".join( 

163 ["%s=%s" % (key, value) for key, value in self._kwargs.items()] 

164 ) 

165 params += ", original_directory=%s, original_extension=%s" % ( 

166 self.original_directory, 

167 self.original_extension, 

168 ) 

169 if self.all_files_options: 

170 params += ", all_files_options=%s" % self.all_files_options 

171 if self.extractor_training_options: 

172 params += ( 

173 ", extractor_training_options=%s" 

174 % self.extractor_training_options 

175 ) 

176 if self.projector_training_options: 

177 params += ( 

178 ", projector_training_options=%s" 

179 % self.projector_training_options 

180 ) 

181 if self.enroller_training_options: 

182 params += ( 

183 ", enroller_training_options=%s" 

184 % self.enroller_training_options 

185 ) 

186 

187 return "%s(%s)" % (str(self.__class__), params) 

188 

189 def replace_directories(self, replacements=None): 

190 """This helper function replaces the ``original_directory`` and the ``annotation_directory`` of the database with the directories read from the given replacement file. 

191 

192 This function is provided for convenience, so that the database configuration files do not need to be modified. 

193 Instead, this function uses the given dictionary of replacements to change the original directory and the original extension (if given). 

194 

195 The given ``replacements`` can be of type ``dict``, including all replacements, or a file name (as a ``str``), in which case the file is read. 

196 The structure of the file should be: 

197 

198 .. code-block:: text 

199 

200 # Comments starting with # and empty lines are ignored 

201 

202 [YOUR_..._DATA_DIRECTORY] = /path/to/your/data 

203 [YOUR_..._ANNOTATION_DIRECTORY] = /path/to/your/annotations 

204 

205 If no annotation files are available (e.g. when they are stored inside the ``database``), the annotation directory can be left out. 

206 

207 **Parameters:** 

208 

209 replacements : dict or str 

210 A dictionary with replacements, or a name of a file to read the dictionary from. 

211 If the file name does not exist, no directories are replaced. 

212 """ 

213 if replacements is None: 

214 return 

215 if isinstance(replacements, str): 

216 if not os.path.exists(replacements): 

217 return 

218 # Open the database replacement file and reads its content 

219 with open(replacements) as f: 

220 replacements = {} 

221 for line in f: 

222 if line.strip() and not line.startswith("#"): 

223 splits = line.split("=") 

224 assert len(splits) == 2 

225 replacements[splits[0].strip()] = splits[1].strip() 

226 

227 assert isinstance(replacements, dict) 

228 

229 if self.original_directory in replacements: 

230 self.original_directory = replacements[self.original_directory] 

231 

232 try: 

233 if self.annotation_directory in replacements: 

234 self.annotation_directory = replacements[ 

235 self.annotation_directory 

236 ] 

237 except AttributeError: 

238 pass 

239 

240 ########################################################################### 

241 # Helper functions that you might want to use in derived classes 

242 ########################################################################### 

243 def uses_probe_file_sets(self, protocol=None): 

244 """Defines if, for the current protocol, the database uses several probe files to generate a score. 

245 Returns True if the given protocol specifies file sets for probes, instead of a single probe file. 

246 In this default implementation, False is returned, throughout. 

247 If you need different behavior, please overload this function in your derived class. 

248 """ 

249 return False 

250 

251 def arrange_by_client(self, files): 

252 """arrange_by_client(files) -> files_by_client 

253 

254 Arranges the given list of files by client id. 

255 This function returns a list of lists of File's. 

256 

257 **Parameters:** 

258 

259 files : :py:class:`bob.bio.base.database.BioFile` 

260 A list of files that should be split up by `BioFile.client_id`. 

261 

262 **Returns:** 

263 

264 files_by_client : [[:py:class:`bob.bio.base.database.BioFile`]] 

265 The list of lists of files, where each sub-list groups the files with the same `BioFile.client_id` 

266 """ 

267 client_files = {} 

268 for file in files: 

269 if file.client_id not in client_files: 

270 client_files[file.client_id] = [] 

271 client_files[file.client_id].append(file) 

272 

273 files_by_clients = [] 

274 for client in sorted(client_files.keys()): 

275 files_by_clients.append(client_files[client]) 

276 return files_by_clients 

277 

278 def file_names(self, files, directory, extension): 

279 """file_names(files, directory, extension) -> paths 

280 

281 Returns the full path of the given File objects. 

282 

283 **Parameters:** 

284 

285 files : [:py:class:`bob.bio.base.database.BioFile`] 

286 The list of file object to retrieve the file names for. 

287 

288 directory : str 

289 The base directory, where the files can be found. 

290 

291 extension : str 

292 The file name extension to add to all files. 

293 

294 **Returns:** 

295 

296 paths : [str] or [[str]] 

297 The paths extracted for the files, in the same order. 

298 If this database provides file sets, a list of lists of file names is returned, one sub-list for each file set. 

299 """ 

300 # return the paths of the files 

301 if self.uses_probe_file_sets() and files and hasattr(files[0], "files"): 

302 # List of Filesets: do not remove duplicates 

303 return [ 

304 [f.make_path(directory, extension) for f in file_set.files] 

305 for file_set in files 

306 ] 

307 else: 

308 # List of files, do not remove duplicates 

309 return [f.make_path(directory, extension) for f in files] 

310 

311 ################################################################# 

312 # Methods to be overwritten by derived classes 

313 ################################################################# 

314 @abc.abstractmethod 

315 def model_ids_with_protocol(self, groups=None, protocol=None, **kwargs): 

316 """model_ids_with_protocol(groups = None, protocol = None, **kwargs) -> ids 

317 

318 Returns a list of model ids for the given groups and given protocol. 

319 

320 **Parameters:** 

321 

322 groups : one or more of ``('world', 'dev', 'eval')`` 

323 The groups to get the model ids for. 

324 

325 protocol: a protocol name 

326 

327 **Returns:** 

328 

329 ids : [int] or [str] 

330 The list of (unique) model ids for the given groups. 

331 """ 

332 raise NotImplementedError( 

333 "Please implement this function in derived classes" 

334 ) 

335 

336 def groups(self, protocol=None): 

337 """ 

338 Returns the names of all registered groups in the database 

339 

340 Keyword parameters: 

341 

342 protocol: str 

343 The protocol for which the groups should be retrieved. 

344 If you do not have protocols defined, just ignore this field. 

345 """ 

346 raise NotImplementedError( 

347 "This function must be implemented in your derived class." 

348 ) 

349 

350 @abc.abstractmethod 

351 def objects( 

352 self, 

353 groups=None, 

354 protocol=None, 

355 purposes=None, 

356 model_ids=None, 

357 **kwargs, 

358 ): 

359 """This function returns a list of :py:class:`bob.bio.base.database.BioFile` objects or the list 

360 of objects which inherit from this class. Returned files fulfill the given restrictions. 

361 

362 Keyword parameters: 

363 

364 groups : str or [str] 

365 The groups of which the clients should be returned. 

366 Usually, groups are one or more elements of ('world', 'dev', 'eval') 

367 

368 protocol 

369 The protocol for which the clients should be retrieved. 

370 The protocol is dependent on your database. 

371 If you do not have protocols defined, just ignore this field. 

372 

373 purposes : str or [str] 

374 The purposes for which File objects should be retrieved. 

375 Usually, purposes are one of ('enroll', 'probe'). 

376 

377 model_ids : [various type] 

378 The model ids for which the File objects should be retrieved. 

379 What defines a 'model id' is dependent on the database. 

380 In cases, where there is only one model per client, model ids and client ids are identical. 

381 In cases, where there is one model per file, model ids and file ids are identical. 

382 But, there might also be other cases. 

383 """ 

384 raise NotImplementedError( 

385 "This function must be implemented in your derived class." 

386 ) 

387 

388 def annotations(self, file): 

389 """ 

390 Returns the annotations for the given File object, if available. 

391 You need to override this method in your high-level implementation. 

392 If your database does not have annotations, it should return ``None``. 

393 

394 **Parameters:** 

395 

396 file : :py:class:`bob.bio.base.database.BioFile` 

397 The file for which annotations should be returned. 

398 

399 **Returns:** 

400 

401 annots : dict or None 

402 The annotations for the file, if available. 

403 """ 

404 raise NotImplementedError( 

405 "This function must be implemented in your derived class." 

406 ) 

407 

408 ################################################################# 

409 # Methods to provide common functionality 

410 ################################################################# 

411 

412 def model_ids(self, groups="dev"): 

413 """model_ids(group = 'dev') -> ids 

414 

415 Returns a list of model ids for the given group, respecting the current protocol. 

416 

417 **Parameters:** 

418 

419 group : one of ``('dev', 'eval')`` 

420 The group to get the model ids for. 

421 

422 **Returns:** 

423 

424 ids : [int] or [str] 

425 The list of (unique) model ids for models of the given group. 

426 """ 

427 return sorted( 

428 self.model_ids_with_protocol(groups=groups, protocol=self.protocol) 

429 ) 

430 

431 def all_files(self, groups=None, **kwargs): 

432 """all_files(groups=None) -> files 

433 

434 Returns all files of the database, respecting the current protocol. 

435 The files can be limited using the ``all_files_options`` in the constructor. 

436 

437 **Parameters:** 

438 

439 groups : some of ``('world', 'dev', 'eval')`` or ``None`` 

440 The groups to get the data for. 

441 If ``None``, data for all groups is returned. 

442 

443 kwargs: ignored 

444 

445 **Returns:** 

446 

447 files : [:py:class:`bob.bio.base.database.BioFile`] 

448 The sorted and unique list of all files of the database. 

449 """ 

450 return self.sort( 

451 self.objects( 

452 protocol=self.protocol, groups=groups, **self.all_files_options 

453 ) 

454 ) 

455 

456 def training_files(self, step=None, arrange_by_client=False): 

457 """training_files(step = None, arrange_by_client = False) -> files 

458 

459 Returns all training files for the given step, and arranges them by client, if desired, respecting the current protocol. 

460 The files for the steps can be limited using the ``..._training_options`` defined in the constructor. 

461 

462 **Parameters:** 

463 

464 step : one of ``('train_extractor', 'train_projector', 'train_enroller')`` or ``None`` 

465 The step for which the training data should be returned. 

466 

467 arrange_by_client : bool 

468 Should the training files be arranged by client? 

469 If set to ``True``, training files will be returned in [[:py:class:`bob.bio.base.database.BioFile`]], where each sub-list contains the files of a single client. 

470 Otherwise, all files will be stored in a simple [:py:class:`bob.bio.base.database.BioFile`]. 

471 

472 **Returns:** 

473 

474 files : [:py:class:`bob.bio.base.database.BioFile`] or [[:py:class:`bob.bio.base.database.BioFile`]] 

475 The (arranged) list of files used for the training of the given step. 

476 """ 

477 if step is None: 

478 training_options = self.all_files_options 

479 elif step == "train_extractor": 

480 training_options = self.extractor_training_options 

481 elif step == "train_projector": 

482 training_options = self.projector_training_options 

483 elif step == "train_enroller": 

484 training_options = self.enroller_training_options 

485 else: 

486 raise ValueError( 

487 "The given step '%s' must be one of ('train_extractor', 'train_projector', 'train_enroller')" 

488 % step 

489 ) 

490 

491 files = self.sort( 

492 self.objects( 

493 protocol=self.protocol, groups="world", **training_options 

494 ) 

495 ) 

496 if arrange_by_client: 

497 return self.arrange_by_client(files) 

498 else: 

499 return files 

500 

501 def test_files(self, groups=["dev"]): 

502 """test_files(groups = ['dev']) -> files 

503 

504 Returns all test files (i.e., files used for enrollment and probing) for the given groups, respecting the current protocol. 

505 The files for the steps can be limited using the ``all_files_options`` defined in the constructor. 

506 

507 **Parameters:** 

508 

509 groups : some of ``('dev', 'eval')`` 

510 The groups to get the data for. 

511 

512 **Returns:** 

513 

514 files : [:py:class:`bob.bio.base.database.BioFile`] 

515 The sorted and unique list of test files of the database. 

516 """ 

517 return self.sort( 

518 self.objects( 

519 protocol=self.protocol, groups=groups, **self.all_files_options 

520 ) 

521 ) 

522 

523 def enroll_files(self, model_id=None, group="dev"): 

524 """enroll_files(model_id, group = 'dev') -> files 

525 

526 Returns a list of File objects that should be used to enroll the model with the given model id from the given group, respecting the current protocol. 

527 If the model_id is None (the default), enrollment files for all models are returned. 

528 

529 **Parameters:** 

530 

531 model_id : int or str 

532 A unique ID that identifies the model. 

533 

534 group : one of ``('dev', 'eval')`` 

535 The group to get the enrollment files for. 

536 

537 **Returns:** 

538 

539 files : [:py:class:`bob.bio.base.database.BioFile`] 

540 The list of files used for to enroll the model with the given model id. 

541 """ 

542 if model_id: 

543 return self.sort( 

544 self.objects( 

545 protocol=self.protocol, 

546 groups=group, 

547 model_ids=(model_id,), 

548 purposes="enroll", 

549 **self.all_files_options, 

550 ) 

551 ) 

552 else: 

553 return self.sort( 

554 self.objects( 

555 protocol=self.protocol, 

556 groups=group, 

557 purposes="enroll", 

558 **self.all_files_options, 

559 ) 

560 ) 

561 

562 def probe_files(self, model_id=None, group="dev"): 

563 """probe_files(model_id = None, group = 'dev') -> files 

564 

565 Returns a list of probe File objects, respecting the current protocol. 

566 If a ``model_id`` is specified, only the probe files that should be compared with the given model id are returned (for most databases, these are all probe files of the given group). 

567 Otherwise, all probe files of the given group are returned. 

568 

569 **Parameters:** 

570 

571 model_id : int or str or ``None`` 

572 A unique ID that identifies the model. 

573 

574 group : one of ``('dev', 'eval')`` 

575 The group to get the enrollment files for. 

576 

577 **Returns:** 

578 

579 files : [:py:class:`bob.bio.base.database.BioFile`] 

580 The list of files used for to probe the model with the given model id. 

581 """ 

582 if model_id is not None: 

583 files = self.objects( 

584 protocol=self.protocol, 

585 groups=group, 

586 model_ids=(model_id,), 

587 purposes="probe", 

588 **self.all_files_options, 

589 ) 

590 else: 

591 files = self.objects( 

592 protocol=self.protocol, 

593 groups=group, 

594 purposes="probe", 

595 **self.all_files_options, 

596 ) 

597 return self.sort(files) 

598 

599 def object_sets( 

600 self, 

601 groups=None, 

602 protocol=None, 

603 purposes=None, 

604 model_ids=None, 

605 **kwargs, 

606 ): 

607 """This function returns lists of FileSet objects, which fulfill the given restrictions. 

608 

609 Keyword parameters: 

610 

611 groups : str or [str] 

612 The groups of which the clients should be returned. 

613 Usually, groups are one or more elements of ('world', 'dev', 'eval') 

614 

615 protocol 

616 The protocol for which the clients should be retrieved. 

617 The protocol is dependent on your database. 

618 If you do not have protocols defined, just ignore this field. 

619 

620 purposes : str or [str] 

621 The purposes for which File objects should be retrieved. 

622 Usually, purposes are one of ('enroll', 'probe'). 

623 

624 model_ids : [various type] 

625 The model ids for which the File objects should be retrieved. 

626 What defines a 'model id' is dependent on the database. 

627 In cases, where there is only one model per client, model ids and client ids are identical. 

628 In cases, where there is one model per file, model ids and file ids are identical. 

629 But, there might also be other cases. 

630 """ 

631 raise NotImplementedError( 

632 "This function must be implemented in your derived class." 

633 ) 

634 

635 def probe_file_sets(self, model_id=None, group="dev"): 

636 """probe_file_sets(model_id = None, group = 'dev') -> files 

637 

638 Returns a list of probe FileSet objects, respecting the current protocol. 

639 If a ``model_id`` is specified, only the probe files that should be compared with the given model id are returned (for most databases, these are all probe files of the given group). 

640 Otherwise, all probe files of the given group are returned. 

641 

642 **Parameters:** 

643 

644 model_id : int or str or ``None`` 

645 A unique ID that identifies the model. 

646 

647 group : one of ``('dev', 'eval')`` 

648 The group to get the enrollment files for. 

649 

650 **Returns:** 

651 

652 files : [:py:class:`bob.bio.base.database.BioFileSet`] or something similar 

653 The list of file sets used to probe the model with the given model id. 

654 """ 

655 if model_id is not None: 

656 file_sets = self.object_sets( 

657 protocol=self.protocol, 

658 groups=group, 

659 model_ids=(model_id,), 

660 purposes="probe", 

661 **self.all_files_options, 

662 ) 

663 else: 

664 file_sets = self.object_sets( 

665 protocol=self.protocol, 

666 groups=group, 

667 purposes="probe", 

668 **self.all_files_options, 

669 ) 

670 return self.sort(file_sets) 

671 

672 def client_id_from_model_id(self, model_id, group="dev"): 

673 """Return the client id associated with the given model id. 

674 In this base class implementation, it is assumed that only one model is enrolled for each client and, thus, client id and model id are identical. 

675 All key word arguments are ignored. 

676 Please override this function in derived class implementations to change this behavior. 

677 """ 

678 return model_id 

679 

680 

681class ZTBioDatabase(BioDatabase): 

682 """This class defines another set of abstract functions that need to be implemented if your database provides the interface for computing scores used for ZT-normalization.""" 

683 

684 def __init__( 

685 self, name, z_probe_options={}, **kwargs 

686 ): # Limit the z-probes 

687 """**Construtctor Documentation** 

688 

689 This constructor tests if all implemented functions take the correct arguments. 

690 All keyword parameters will be passed unaltered to the :py:class:`bob.bio.base.database.BioDatabase` constructor. 

691 """ 

692 # call base class constructor 

693 super(ZTBioDatabase, self).__init__(name, **kwargs) 

694 

695 self.z_probe_options = z_probe_options 

696 

697 # try if the implemented tmodel_ids_with_protocol(), tobjects() and zobjects() function have at least the required interface 

698 try: 

699 # create a value that is very unlikely a valid value for anything 

700 test_value = "#F9S%3*Y" 

701 # test if the parameters of the functions apply 

702 self.tmodel_ids_with_protocol( 

703 groups=test_value, protocol=test_value 

704 ) 

705 self.tobjects( 

706 groups=test_value, protocol=test_value, model_ids=test_value 

707 ) 

708 self.zobjects(groups=test_value, protocol=test_value) 

709 except TypeError as e: 

710 # type error indicates that the given parameters are not valid. 

711 raise NotImplementedError( 

712 str(e) 

713 + "\nPlease implement:\n - the tmodel_ids_with_protocol(...) function with at least the " 

714 "arguments 'groups' and 'protocol'\n - the tobjects(...) function with at least the arguments " 

715 "'groups', 'protocol' and 'model_ids'\n - the zobjects(...) function with at " 

716 "least the arguments 'groups' and 'protocol'" 

717 ) 

718 except Exception: 

719 # any other error is fine at this stage. 

720 pass 

721 

722 @abc.abstractmethod 

723 def tobjects(self, groups=None, protocol=None, model_ids=None, **kwargs): 

724 """This function returns the File objects of the T-Norm models of the given groups for the given protocol and the given model ids. 

725 

726 Keyword parameters: 

727 

728 groups : str or [str] 

729 The groups of which the model ids should be returned. 

730 Usually, groups are one or more elements of ('dev', 'eval') 

731 

732 protocol : str 

733 The protocol for which the model ids should be retrieved. 

734 The protocol is dependent on your database. 

735 If you do not have protocols defined, just ignore this field. 

736 

737 model_ids : [various type] 

738 The model ids for which the File objects should be retrieved. 

739 What defines a 'model id' is dependent on the database. 

740 In cases, where there is only one model per client, model ids and client ids are identical. 

741 In cases, where there is one model per file, model ids and file ids are identical. 

742 But, there might also be other cases. 

743 """ 

744 raise NotImplementedError( 

745 "This function must be implemented in your derived class." 

746 ) 

747 

748 @abc.abstractmethod 

749 def zobjects(self, groups=None, protocol=None, **kwargs): 

750 """This function returns the File objects of the Z-Norm impostor files of the given groups for the given protocol. 

751 

752 Keyword parameters: 

753 

754 groups : str or [str] 

755 The groups of which the model ids should be returned. 

756 Usually, groups are one or more elements of ('dev', 'eval') 

757 

758 protocol : str 

759 The protocol for which the model ids should be retrieved. 

760 The protocol is dependent on your database. 

761 If you do not have protocols defined, just ignore this field. 

762 """ 

763 raise NotImplementedError( 

764 "This function must be implemented in your derived class." 

765 ) 

766 

767 def all_files(self, groups=["dev"], add_zt_files=True): 

768 """all_files(groups=None) -> files 

769 

770 Returns all files of the database, including those for ZT norm, respecting the current protocol. 

771 The files can be limited using the ``all_files_options`` and the the ``z_probe_options`` in the constructor. 

772 

773 **Parameters:** 

774 

775 groups : some of ``('world', 'dev', 'eval')`` or ``None`` 

776 The groups to get the data for. 

777 If ``None``, data for all groups is returned. 

778 

779 add_zt_files: bool 

780 If set (the default), files for ZT score normalization are added. 

781 

782 **Returns:** 

783 

784 files : [:py:class:`bob.bio.base.database.BioFile`] 

785 The sorted and unique list of all files of the database. 

786 """ 

787 files = self.objects( 

788 protocol=self.protocol, groups=groups, **self.all_files_options 

789 ) 

790 

791 # add all files that belong to the ZT-norm 

792 if add_zt_files and groups: 

793 for group in groups: 

794 if group == "world": 

795 continue 

796 files += self.tobjects( 

797 protocol=self.protocol, groups=group, model_ids=None 

798 ) 

799 files += self.zobjects( 

800 protocol=self.protocol, groups=group, **self.z_probe_options 

801 ) 

802 elif add_zt_files: 

803 files += self.tobjects( 

804 protocol=self.protocol, groups=groups, model_ids=None 

805 ) 

806 files += self.zobjects( 

807 protocol=self.protocol, groups=groups, **self.z_probe_options 

808 ) 

809 return self.sort(files) 

810 

811 @abc.abstractmethod 

812 def tmodel_ids_with_protocol(self, protocol=None, groups=None, **kwargs): 

813 """This function returns the ids of the T-Norm models of the given groups for the given protocol. 

814 

815 Keyword parameters: 

816 

817 groups : str or [str] 

818 The groups of which the model ids should be returned. 

819 Usually, groups are one or more elements of ('dev', 'eval') 

820 

821 protocol : str 

822 The protocol for which the model ids should be retrieved. 

823 The protocol is dependent on your database. 

824 If you do not have protocols defined, just ignore this field. 

825 """ 

826 raise NotImplementedError( 

827 "This function must be implemented in your derived class." 

828 ) 

829 

830 def t_model_ids(self, groups="dev"): 

831 """t_model_ids(group = 'dev') -> ids 

832 

833 Returns a list of model ids of T-Norm models for the given group, respecting the current protocol. 

834 

835 **Parameters:** 

836 

837 group : one of ``('dev', 'eval')`` 

838 The group to get the model ids for. 

839 

840 **Returns:** 

841 

842 ids : [int] or [str] 

843 The list of (unique) model ids for T-Norm models of the given group. 

844 """ 

845 return sorted( 

846 self.tmodel_ids_with_protocol(protocol=self.protocol, groups=groups) 

847 ) 

848 

849 def t_enroll_files(self, t_model_id, group="dev"): 

850 """t_enroll_files(t_model_id, group = 'dev') -> files 

851 

852 Returns a list of File objects that should be used to enroll the T-Norm model with the given model id from the given group, respecting the current protocol. 

853 

854 **Parameters:** 

855 

856 t_model_id : int or str 

857 A unique ID that identifies the model. 

858 

859 group : one of ``('dev', 'eval')`` 

860 The group to get the enrollment files for. 

861 

862 **Returns:** 

863 

864 files : [:py:class:`bob.bio.base.database.BioFile`] 

865 The sorted list of files used for to enroll the model with the given model id. 

866 """ 

867 return self.sort( 

868 self.tobjects( 

869 protocol=self.protocol, groups=group, model_ids=(t_model_id,) 

870 ) 

871 ) 

872 

873 def z_probe_files(self, group="dev"): 

874 """z_probe_files(group = 'dev') -> files 

875 

876 Returns a list of probe files used to compute the Z-Norm, respecting the current protocol. 

877 The Z-probe files can be limited using the ``z_probe_options`` in the query to :py:meth:`bob.bio.base.database.ZTBioDatabase.z_probe_files` 

878 

879 **Parameters:** 

880 

881 group : one of ``('dev', 'eval')`` 

882 The group to get the Z-norm probe files for. 

883 

884 **Returns:** 

885 

886 files : [:py:class:`bob.bio.base.database.BioFile`] 

887 The unique list of files used to compute the Z-norm. 

888 """ 

889 return self.sort( 

890 self.zobjects( 

891 protocol=self.protocol, groups=group, **self.z_probe_options 

892 ) 

893 ) 

894 

895 def z_probe_file_sets(self, group="dev"): 

896 """z_probe_file_sets(group = 'dev') -> files 

897 

898 Returns a list of probe FileSet objects used to compute the Z-Norm. 

899 This function needs to be implemented in derived class implementations. 

900 

901 **Parameters:** 

902 

903 group : one of ``('dev', 'eval')`` 

904 The group to get the Z-norm probe files for. 

905 

906 **Returns:** 

907 

908 files : [:py:class:`bob.bio.base.database.BioFileSet`] 

909 The unique list of file sets used to compute the Z-norm. 

910 """ 

911 raise NotImplementedError( 

912 "Please implement this function in derived classes" 

913 ) 

914 

915 def client_id_from_t_model_id(self, t_model_id, group="dev"): 

916 """client_id_from_t_model_id(t_model_id, group = 'dev') -> client_id 

917 Returns the client id for the given T-Norm model id. 

918 In this base class implementation, we just use the :py:meth:`BioDatabase.client_id_from_model_id` function. 

919 Overload this function if you need another behavior. 

920 

921 **Parameters:** 

922 

923 t_model_id : int or str 

924 A unique ID that identifies the T-Norm model. 

925 group : one of ``('dev', 'eval')`` 

926 The group to get the client ids for. 

927 

928 **Returns:** 

929 

930 client_id : [int] or [str] 

931 A unique ID that identifies the client, to which the T-Norm model belongs. 

932 """ 

933 return self.client_id_from_model_id(t_model_id, group)