diff --git a/bob/bio/face/config/database/casia_africa.py b/bob/bio/face/config/database/casia_africa.py new file mode 100644 index 0000000000000000000000000000000000000000..1501bdbd50c74364534a7729a49f21c66f7c9411 --- /dev/null +++ b/bob/bio/face/config/database/casia_africa.py @@ -0,0 +1,9 @@ +from bob.bio.face.database import CasiaAfricaDatabase + +# In case protocol is comming from chain loading +# https://www.idiap.ch/software/bob/docs/bob/bob.extension/stable/py_api.html#bob.extension.config.load +if "protocol" not in locals(): + protocol = "ID-V-All-Ep1" + + +database = CasiaAfricaDatabase(protocol=protocol) diff --git a/bob/bio/face/database/__init__.py b/bob/bio/face/database/__init__.py index 8450b9f7f12e7966d70cd86da37d304e94d5b758..b4576b238c19f5046ce66b93a47fa240490e91b6 100644 --- a/bob/bio/face/database/__init__.py +++ b/bob/bio/face/database/__init__.py @@ -14,6 +14,7 @@ from .replaymobile import ReplayMobileBioDatabase from .fargo import FargoBioDatabase from .meds import MEDSDatabase from .morph import MorphDatabase +from .casia_africa import CasiaAfricaDatabase # gets sphinx autodoc done right - don't remove it @@ -47,5 +48,6 @@ __appropriate__( FargoBioDatabase, MEDSDatabase, MorphDatabase, + CasiaAfricaDatabase, ) __all__ = [_ for _ in dir() if not _.startswith("_")] diff --git a/bob/bio/face/database/casia_africa.py b/bob/bio/face/database/casia_africa.py new file mode 100644 index 0000000000000000000000000000000000000000..833a18585cdf83f4d84c2bb22af1519cd801a697 --- /dev/null +++ b/bob/bio/face/database/casia_africa.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : +# Tiago de Freitas Pereira <tiago.pereira@idiap.ch> + +""" + CASIA-Face-Africa: database implementation +""" + +from bob.bio.base.database import CSVDataset +from bob.bio.base.database import CSVToSampleLoaderBiometrics +from bob.bio.face.database.sample_loaders import EyesAnnotations +from bob.extension import rc +from bob.extension.download import get_file +import bob.io.base +from sklearn.pipeline import make_pipeline + + +class CasiaAfricaDatabase(CSVDataset): + """ + The Casia-Face-Africa dataset is composed of 1133 identities from different ethical groups in Nigeria. + + The capturing locations are: + - Dabai city in Katsina state + - Hotoro in Kano state + - Birget in Kano state + - Gandun Albasa in Kano state + - Sabon Gari inKano state + - Kano State School of Technology + + These locations were strategically selected as they are known to have diverse population of local ethnicities. + + .. warning:: + Only 17 subjects had their images capture in two sessions. + + Images were captured during daytime and night using three different cameras: + - C1: Visual Light Camera + - C2: Visual Light Camera + - C3: NIR camera + + + This dataset interface implemented the three verificatio protocols: "ID-V-All-Ep1", "ID-V-All-Ep2", and "ID-V-All-Ep3" + and they are organized as the following: + + +------------------------------------------------------------------------------------+ + | Dev. Set | + +------------------+----------------------------+------------+----------+------------+ + | protocol name | Cameras (gallery/probe) | Identities | Gallery | Probes | + +==================+============================+============+==========+============+ + | ID-V-All-Ep1 | C1/C2 | 1133 | 2455 | 2426 | + +------------------+----------------------------+------------+----------+------------+ + | ID-V-All-Ep2 | C1/C3 | 1133 | 2455 | 1171 | + +------------------+----------------------------+------------+----------+------------+ + | ID-V-All-Ep3 | C2/C3 | 1133 | 2466 | 1193 | + +------------------+----------------------------+------------+----------+------------+ + + + .. warning:: + Use the command below to set the path of the real data:: + + $ bob config set bob.db.casia-africa.directory [PATH-TO-MEDS-DATA] + + + .. code-block:: latex + + @article{jawad2020, + author = {Jawad, Muhammad and Yunlong, Wang andCaiyong, Wang and Kunbo, Zhang and Zhenan, Sun}, + title = {CASIA-Face-Africa: A Large-scale African Face Image Database}, + journal = {IEEE Transactions on Information Forensics and Security}, + pages = {}, + ISSN = {}, + year = {}, + type = {Journal Article} + } + + + Example + ------- + + Fetching biometric references:: + + >>> from bob.bio.face.database import CasiaAfricaDatabase + >>> database = CasiaAfricaDatabase(protocol="ID-V-All-Ep1") + >>> database.references() + + + Fetching probes:: + + >>> from bob.bio.face.database import CasiaAfricaDatabase + >>> database = CasiaAfricaDatabase(protocol="ID-V-All-Ep1") + >>> database.probes() + + + Parameters + ---------- + + protocol: str + One of the database protocols. Options are "ID-V-All-Ep1", "ID-V-All-Ep2" and "ID-V-All-Ep3" + """ + + def __init__(self, protocol): + + # Downloading model if not exists + urls = CasiaAfricaDatabase.urls() + filename = get_file( + "casia_face_africa.tar.gz", + urls, + file_hash="324bd69b581477d30606417be8e30d2a", + ) + + self.annotation_type = "eyes-center" + self.fixed_positions = None + + directory = ( + rc["bob.db.casia-africa.directory"] + if rc["bob.db.casia-africa.directory "] + else "" + ) + + super().__init__( + filename, + protocol, + csv_to_sample_loader=make_pipeline( + CSVToSampleLoaderBiometrics( + data_loader=bob.io.base.load, + dataset_original_directory=directory, + extension=".jpg", + reference_id_equal_subject_id=False, + ), + EyesAnnotations(), + ), + ) + + @staticmethod + def protocols(): + # TODO: Until we have (if we have) a function that dumps the protocols, let's use this one. + return [ + "ID-V-All-Ep1", + "ID-V-All-Ep2", + "ID-V-All-Ep3", + ] + + @staticmethod + def urls(): + return [ + "https://www.idiap.ch/software/bob/databases/latest/casia_face_africa.tar.gz", + "http://www.idiap.ch/software/bob/databases/latest/casia_face_africa.tar.gz", + ] diff --git a/bob/bio/face/database/multipie.py b/bob/bio/face/database/multipie.py index 6e1dabb3cee1ea9976cb1a4091583fa8b8f9bef6..6a257c046af5a165e2a376a5e12fa2c80999d839 100644 --- a/bob/bio/face/database/multipie.py +++ b/bob/bio/face/database/multipie.py @@ -17,7 +17,73 @@ from sklearn.pipeline import make_pipeline class MultipieDatabase(CSVDataset): """ - The Multipie database.. + + The `CMU Multi-PIE face database <http://www.cs.cmu.edu/afs/cs/project/PIE/MultiPie/Multi-Pie/Home.html>`_ contains more than 750,000 images + of 337 people recorded in up to four sessions over the span of five months. Subjects were imaged under 15 view points and 19 illumination + conditions while displaying a range of facial expressions. In addition, high resolution frontal images were acquired as well. + In total, the database contains more than 305 GB of face data. + + The data has been recorded over 4 sessions. For each session, the subjects were asked to display a few + different expressions. For each of those expressions, a complete set of 30 pictures is captured that includes + 15 different view points times 20 different illumination conditions (18 with various flashes, plus 2 pictures with no flash at all). + + Available expressions: + + - Session 1 : *neutral*, *smile* + - Session 2 : *neutral*, *surprise*, *squint* + - Session 3 : *neutral*, *smile*, *disgust* + - Session 4 : *neutral*, *neutral*, *scream*. + + Camera and flash positioning: + + The different view points are obtained by a set of 13 cameras located at head height, spaced at 15° intervals, + from the -90° to the 90° angle, plus 2 additional cameras located above the subject to simulate a typical + surveillance view. A flash coincides with each camera, and 3 additional flashes are positioned above the subject, for a total + of 18 different possible flashes. + + Protocols: + + **Expression protocol** + + **Protocol E** + + * Only frontal view (camera 05_1); only no-flash (shot 0) + * Enrolled : 1x neutral expression (session 1; recording 1) + * Probes : 4x neutral expression + other expressions (session 2, 3, 4; all recordings) + + **Pose protocol** + + **Protocol P** + + * Only neutral expression (recording 1 from each session, + recording 2 from session 4); only no-flash (shot 0) + * Enrolled : 1x frontal view (session 1; camera 05_1) + * Probes : all views from cameras at head height (i.e excluding 08_1 and 19_1), including camera 05_1 from session 2,3,4. + + **Illumination protocols** + + N.B : shot 19 is never used in those protocols as it is redundant with shot 0 (both are no-flash). + + **Protocol M** + + * Only frontal view (camera 05_1); only neutral expression (recording 1 from each session, + recording 2 from session 4) + * Enrolled : no-flash (session 1; shot 0) + * Probes : no-flash (session 2, 3, 4; shot 0) + + **Protocol U** + + * Only frontal view (camera 05_1); only neutral expression (recording 1 from each session, + recording 2 from session 4) + * Enrolled : no-flash (session 1; shot 0) + * Probes : all shots from session 2, 3, 4, including shot 0. + + **Protocol G** + + * Only frontal view (camera 05_1); only neutral expression (recording 1 from each session, + recording 2 from session 4) + * Enrolled : all shots (session 1; all shots) + * Probes : all shots from session 2, 3, 4. + + + + """ def __init__(self, protocol): diff --git a/bob/bio/face/test/test_databases.py b/bob/bio/face/test/test_databases.py index b3b3171091a8c10de5a7ab534a718a580bb0faed..c3fb8dca5a85fbb9b8f709e30efe1f8e1a35ee39 100644 --- a/bob/bio/face/test/test_databases.py +++ b/bob/bio/face/test/test_databases.py @@ -23,9 +23,7 @@ import pytest import os import bob.bio.base from bob.bio.base.test.utils import db_available -from bob.bio.base.test.test_database_implementations import ( - check_database, -) +from bob.bio.base.test.test_database_implementations import check_database import bob.core from bob.extension.download import get_file @@ -72,9 +70,9 @@ def test_arface(): try: check_database(database, groups=("dev", "eval")) except IOError as e: - pytest.skip("The database could not queried; probably the db.sql3 file is missing. Here is the error: '%s'" + pytest.skip( + "The database could not queried; probably the db.sql3 file is missing. Here is the error: '%s'" % e - ) try: _check_annotations(database) @@ -396,3 +394,13 @@ def test_morph(): assert len(database.references(group="eval")) == 6742 assert len(database.probes(group="eval")) == 6553 + + +def test_casia_africa(): + + from bob.bio.face.database import CasiaAfricaDatabase + + database = CasiaAfricaDatabase("ID-V-All-Ep1") + + assert len(database.references()) == 2455 + assert len(database.probes()) == 2426 diff --git a/doc/implemented.rst b/doc/implemented.rst index a4de538e10395f752443a1c4082c3f919b3e279e..0891df4824563aeb61aea5a9794cc42bd71ec883 100644 --- a/doc/implemented.rst +++ b/doc/implemented.rst @@ -13,6 +13,7 @@ Databases .. autosummary:: bob.bio.face.database.ARFaceBioDatabase bob.bio.face.database.AtntBioDatabase + bob.bio.face.database.CasiaAfricaDatabase bob.bio.face.database.MobioDatabase bob.bio.face.database.ReplayBioDatabase bob.bio.face.database.ReplayMobileBioDatabase diff --git a/setup.py b/setup.py index 4fd8cf61adbe60ca34b9454a721be08bf950b153..a62ca7be8698f1a50cd69d6f2fc6c4f3ea50b0d1 100644 --- a/setup.py +++ b/setup.py @@ -112,6 +112,7 @@ setup( "fargo = bob.bio.face.config.database.fargo:database", "meds = bob.bio.face.config.database.meds:database", "morph = bob.bio.face.config.database.morph:database", + "casia-africa = bob.bio.face.config.database.casia_africa:database", ], "bob.bio.annotator": [ "facedetect = bob.bio.face.config.annotator.facedetect:annotator", @@ -177,6 +178,7 @@ setup( "fargo = bob.bio.face.config.database.fargo", "meds = bob.bio.face.config.database.meds", "morph = bob.bio.face.config.database.morph", + "casia-africa = bob.bio.face.config.database.casia_africa", "resnet50-msceleb-arcface-2021 = bob.bio.face.config.baseline.resnet50_msceleb_arcface_2021", "resnet50-vgg2-arcface-2021 = bob.bio.face.config.baseline.resnet50_vgg2_arcface_2021", "mobilenetv2-msceleb-arcface-2021 = bob.bio.face.config.baseline.mobilenetv2_msceleb_arcface_2021",