Commit 1079384a authored by Amir MOHAMMADI's avatar Amir MOHAMMADI

Merge branch 'new-db' into 'master'

Add SWAN and OULU-NPU databases

See merge request !116
parents d23704c2 2a3c6702
Pipeline #49344 passed with stages
in 9 minutes and 19 seconds
"""The `OULU-NPU`_ Database.
A mobile face presentation attack database with real-world variations database.
To configure the location of the database on your computer, run::
bob config set bob.db.oulunpu.directory /path/to/oulunpu/database
If you use this database, please cite the following publication::
@INPROCEEDINGS{OULU_NPU_2017,
author = {Boulkenafet, Z. and Komulainen, J. and Li, Lei. and Feng, X. and Hadid, A.},
keywords = {biometrics, face recognition, anti-spoofing, presentation attack, generalization, colour texture},
month = May,
title = {{OULU-NPU}: A mobile face presentation attack database with real-world variations},
journal = {IEEE International Conference on Automatic Face and Gesture Recognition},
year = {2017},
}
.. include:: links.rst
"""
from bob.pad.face.database import OulunpuPadDatabase
database = OulunpuPadDatabase()
"""The Swan_ Database.
To configure the location of the database on your computer, run::
bob config set bob.db.swan.directory /path/to/swan/database
The Idiap part of the dataset comprises 150 subjects that are captured in six
different sessions reflecting real-life scenarios of smartphone assisted
authentication. One of the unique features of this dataset is that it is
collected in four different geographic locations representing a diverse
population and ethnicity. Additionally, it also contains a multimodal
Presentation Attack (PA) or spoofing dataset using low-cost Presentation Attack
Instruments (PAI) such as print and electronic display attacks. The novel
acquisition protocols and the diversity of the data subjects collected from
different geographic locations will allow developing a novel algorithm for
either unimodal or multimodal biometrics.
PAD protocols are created according to the SWAN-PAD-protocols document.
Bona-fide session 2 data is split into 3 sets of training, development, and
evaluation. The bona-fide data from sessions 3,4,5,6 are used for evaluation as
well. PA samples are randomly split into 3 sets of training, development, and
evaluation. All the random splits are done 10 times to created 10 different
protocols. The PAD protocols contain only one type of attacks. For convenience,
PA_F and PA_V protocols are created for face and voice, respectively which
contain all the attacks.
.. include:: links.rst
"""
from bob.pad.face.database import SwanPadDatabase
database = SwanPadDatabase()
......@@ -5,6 +5,8 @@ from .casiasurf import CasiaSurfPadDatabase
from .maskattack import MaskAttackPadDatabase
from .replay_attack import ReplayAttackPadDatabase
from .replay_mobile import ReplayMobilePadDatabase
from .swan import SwanPadDatabase
from .oulunpu import OulunpuPadDatabase
# gets sphinx autodoc done right - don't remove it
......@@ -30,6 +32,8 @@ __appropriate__(
MaskAttackPadDatabase,
CasiaSurfPadDatabase,
CasiaFasdPadDatabase,
SwanPadDatabase,
OulunpuPadDatabase,
)
__all__ = [_ for _ in dir() if not _.startswith('_')]
......@@ -17,6 +17,7 @@ def delayed_video_load(
max_number_of_frames=None,
step_size=None,
get_transform=None,
keep_extension_for_annotation=False,
):
if get_transform is None:
def get_transform(x):
......@@ -37,7 +38,9 @@ def delayed_video_load(
)
annotations, delayed_attributes = None, None
if annotation_directory:
path = os.path.splitext(sample.filename)[0]
path = sample.filename
if not keep_extension_for_annotation:
path = os.path.splitext(sample.filename)[0]
delayed_annotations = partial(
read_annotation_file,
file_name=f"{annotation_directory}:{path}.json",
......@@ -63,6 +66,7 @@ def VideoPadSample(
max_number_of_frames=None,
step_size=None,
get_transform=None,
keep_extension_for_annotation=False,
):
return FunctionTransformer(
delayed_video_load,
......@@ -74,6 +78,7 @@ def VideoPadSample(
max_number_of_frames=max_number_of_frames,
step_size=step_size,
get_transform=get_transform,
keep_extension_for_annotation=keep_extension_for_annotation,
),
)
......
import logging
from bob.extension import rc
from bob.extension.download import get_file
from bob.pad.base.database import FileListPadDatabase
from bob.pad.face.database import VideoPadSample
logger = logging.getLogger(__name__)
def OulunpuPadDatabase(
protocol="Protocol_1",
selection_style=None,
max_number_of_frames=None,
step_size=None,
annotation_directory=None,
annotation_type=None,
fixed_positions=None,
**kwargs,
):
name = "pad-face-oulunpu-75221078.tar.gz"
dataset_protocols_path = get_file(
name,
[f"http://www.idiap.ch/software/bob/data/bob/bob.pad.face/{name}"],
cache_subdir="protocols",
file_hash="75221078",
)
if annotation_directory is None:
name = "annotations-oulunpu-mtcnn-3bee9b6d.tar.xz"
annotation_directory = get_file(
name,
[f"http://www.idiap.ch/software/bob/data/bob/bob.pad.face/{name}"],
cache_subdir="annotations",
file_hash="3bee9b6d",
)
annotation_type = "eyes-center"
transformer = VideoPadSample(
original_directory=rc.get("bob.db.oulunpu.directory"),
annotation_directory=annotation_directory,
selection_style=selection_style,
max_number_of_frames=max_number_of_frames,
step_size=step_size,
)
database = FileListPadDatabase(
dataset_protocols_path,
protocol,
transformer=transformer,
**kwargs,
)
database.annotation_type = annotation_type
database.fixed_positions = fixed_positions
return database
import logging
from bob.extension import rc
from bob.extension.download import get_file
from bob.pad.base.database import FileListPadDatabase
from bob.pad.face.database import VideoPadSample
logger = logging.getLogger(__name__)
def SwanPadDatabase(
protocol="pad_p2_face_f1",
selection_style=None,
max_number_of_frames=None,
step_size=None,
annotation_directory=None,
annotation_type=None,
fixed_positions=None,
**kwargs,
):
name = "pad-face-swan-711dffcf.tar.gz"
dataset_protocols_path = get_file(
name,
[f"http://www.idiap.ch/software/bob/data/bob/bob.pad.face/{name}"],
cache_subdir="protocols",
file_hash="711dffcf",
)
if annotation_directory is None:
name = "annotations-swan-mtcnn-cff2f062.tar.xz"
annotation_directory = get_file(
name,
[f"http://www.idiap.ch/software/bob/data/bob/bob.pad.face/{name}"],
cache_subdir="annotations",
file_hash="cff2f062",
)
annotation_type = "eyes-center"
transformer = VideoPadSample(
original_directory=rc.get("bob.db.swan.directory"),
annotation_directory=annotation_directory,
selection_style=selection_style,
max_number_of_frames=max_number_of_frames,
step_size=step_size,
keep_extension_for_annotation=True,
)
database = FileListPadDatabase(
dataset_protocols_path,
protocol,
transformer=transformer,
**kwargs,
)
database.annotation_type = annotation_type
database.fixed_positions = fixed_positions
return database
......@@ -15,22 +15,33 @@ def test_replayattack():
package_prefix="bob.pad.",
)
assert database.protocols() == ['digitalphoto', 'grandtest', 'highdef', 'mobile', 'photo', 'print', 'smalltest', 'video']
assert database.protocols() == [
"digitalphoto",
"grandtest",
"highdef",
"mobile",
"photo",
"print",
"smalltest",
"video",
]
assert database.groups() == ["dev", "eval", "train"]
assert len(database.samples(groups=["train", "dev", "eval"])) == 1200
assert len(database.samples(groups=["train", "dev"])) == 720
assert len(database.samples(groups=["train"])) == 360
assert len(database.samples(groups=["train", "dev", "eval"])) == 1200
assert (
len(database.samples(groups=["train", "dev", "eval"], purposes="real")) == 200
)
assert (
len(database.samples(groups=["train", "dev", "eval"], purposes="attack")) == 1000
len(database.samples(groups=["train", "dev", "eval"], purposes="attack"))
== 1000
)
sample = database.sort(database.samples())[0]
try:
assert sample.annotations["0"] == {
annot = dict(sample.annotations["0"])
assert annot["leye"][1] > annot["reye"][1], annot
assert annot == {
"bottomright": [213, 219],
"topleft": [58, 108],
"leye": [118, 190],
......@@ -45,7 +56,6 @@ def test_replayattack():
raise SkipTest(e)
def test_replaymobile():
database = bob.bio.base.load_resource(
"replay-mobile",
......@@ -59,7 +69,6 @@ def test_replaymobile():
assert len(database.samples(groups=["train", "dev", "eval"])) == 1030
assert len(database.samples(groups=["train", "dev"])) == 728
assert len(database.samples(groups=["train"])) == 312
assert len(database.samples(groups=["train", "dev", "eval"])) == 1030
assert (
len(database.samples(groups=["train", "dev", "eval"], purposes="real")) == 390
)
......@@ -69,7 +78,9 @@ def test_replaymobile():
sample = database.sort(database.samples())[0]
try:
assert sample.annotations["0"] == {
annot = dict(sample.annotations["0"])
assert annot["leye"][1] > annot["reye"][1], annot
assert annot == {
"bottomright": [760, 498],
"topleft": [374, 209],
"leye": [518, 417],
......@@ -94,8 +105,7 @@ def test_maskattack():
)
# all real sequences: 2 sessions, 5 recordings for 17 individuals
assert (
len(maskattack.samples(groups=["train", "dev", "eval"], purposes="real"))
== 170
len(maskattack.samples(groups=["train", "dev", "eval"], purposes="real")) == 170
)
# all attacks: 1 session, 5 recordings for 17 individuals
assert (
......@@ -139,6 +149,7 @@ def test_maskattack():
# == 57710
# )
def test_casiasurf_color_protocol():
casiasurf = bob.bio.base.load_resource(
"casiasurf-color",
......@@ -150,18 +161,14 @@ def test_casiasurf_color_protocol():
assert len(casiasurf.samples(groups=["train"], purposes="attack")) == 20324
assert len(casiasurf.samples(groups=("dev",), purposes=("real",))) == 2994
assert len(casiasurf.samples(groups=("dev",), purposes=("attack",))) == 6614
assert (
len(casiasurf.samples(groups=("dev",), purposes=("real", "attack"))) == 9608
)
assert len(casiasurf.samples(groups=("dev",), purposes=("real", "attack"))) == 9608
assert len(casiasurf.samples(groups=("eval",), purposes=("real",))) == 17458
assert len(casiasurf.samples(groups=("eval",), purposes=("attack",))) == 40252
assert (
len(casiasurf.samples(groups=("eval",), purposes=("real", "attack")))
== 57710
len(casiasurf.samples(groups=("eval",), purposes=("real", "attack"))) == 57710
)
def test_casia_fasd():
casia_fasd = bob.bio.base.load_resource(
"casiafasd",
......@@ -177,3 +184,107 @@ def test_casia_fasd():
assert len(casia_fasd.samples(groups="train")) == 180
assert len(casia_fasd.samples(groups="dev")) == 60
assert len(casia_fasd.samples(groups="eval")) == 360
def test_swan():
database = bob.bio.base.load_resource(
"swan",
"database",
preferred_package="bob.pad.face",
package_prefix="bob.pad.",
)
assert database.protocols() == [
"pad_p2_face_f1",
"pad_p2_face_f2",
"pad_p2_face_f3",
"pad_p2_face_f4",
"pad_p2_face_f5",
]
assert database.groups() == ["dev", "eval", "train"]
assert len(database.samples(groups=["train", "dev", "eval"])) == 5802
assert len(database.samples(groups=["train", "dev"])) == 2803
assert len(database.samples(groups=["train"])) == 2001
assert (
len(database.samples(groups=["train", "dev", "eval"], purposes="real")) == 3300
)
assert (
len(database.samples(groups=["train", "dev", "eval"], purposes="attack"))
== 2502
)
sample = database.sort(database.samples())[0]
try:
annot = dict(sample.annotations["0"])
assert annot["leye"][1] > annot["reye"][1], annot
assert annot == {
"bottomright": [849, 564],
"leye": [511, 453],
"mouthleft": [709, 271],
"mouthright": [711, 445],
"nose": [590, 357],
"reye": [510, 265],
"topleft": [301, 169],
}
assert sample.data.shape == (20, 3, 720, 1280)
assert sample.data[0][0, 0, 0] == 87
except RuntimeError as e:
raise SkipTest(e)
def test_oulunpu():
database = bob.bio.base.load_resource(
"oulunpu",
"database",
preferred_package="bob.pad.face",
package_prefix="bob.pad.",
)
assert database.protocols() == [
"Protocol_1",
"Protocol_1_2",
"Protocol_1_3",
"Protocol_2",
"Protocol_3_1",
"Protocol_3_2",
"Protocol_3_3",
"Protocol_3_4",
"Protocol_3_5",
"Protocol_3_6",
"Protocol_4_1",
"Protocol_4_2",
"Protocol_4_3",
"Protocol_4_4",
"Protocol_4_5",
"Protocol_4_6",
]
assert database.groups() == ["dev", "eval", "train"]
assert len(database.samples(groups=["train", "dev", "eval"])) == 1200 + 900 + 600
assert len(database.samples(groups=["train", "dev"])) == 1200 + 900
assert len(database.samples(groups=["train"])) == 1200
assert (
len(database.samples(groups=["train", "dev", "eval"], purposes="real"))
== 240 + 180 + 120
)
assert (
len(database.samples(groups=["train", "dev", "eval"], purposes="attack"))
== 960 + 720 + 480
)
sample = database.sort(database.samples())[0]
try:
annot = dict(sample.annotations["0"])
assert annot["leye"][1] > annot["reye"][1], annot
assert annot == {
"bottomright": [1124, 773],
"leye": [818, 638],
"mouthleft": [1005, 489],
"mouthright": [1000, 634],
"nose": [906, 546],
"reye": [821, 470],
"topleft": [632, 394],
}
assert sample.data.shape == (20, 3, 1920, 1080)
assert sample.data[0][0, 0, 0] == 195
except RuntimeError as e:
raise SkipTest(e)
......@@ -14,3 +14,5 @@
.. _dependencies: https://gitlab.idiap.ch/bob/bob/wikis/Dependencies
.. _MIFS: http://www.antitza.com/makeup-datasets.html
.. _CELEBA: http://mmlab.ie.cuhk.edu.hk/projects/CelebA.html
.. _Swan: https://www.idiap.ch/dataset/swan
.. _oulu-npu: https://sites.google.com/site/oulunpudatabase/
......@@ -62,6 +62,8 @@ setup(
"maskattack = bob.pad.face.config.maskattack:database",
"casiasurf-color = bob.pad.face.config.casiasurf_color:database",
"casiasurf = bob.pad.face.config.casiasurf:database",
"swan = bob.pad.face.config.swan:database",
"oulunpu = bob.pad.face.config.oulunpu:database",
],
# registered configurations:
"bob.pad.config": [
......@@ -70,6 +72,10 @@ setup(
"replay-mobile = bob.pad.face.config.replay_mobile",
"casiafasd = bob.pad.face.config.casiafasd",
"maskattack = bob.pad.face.config.maskattack",
"casiasurf-color = bob.pad.face.config.casiasurf_color",
"casiasurf = bob.pad.face.config.casiasurf",
"swan = bob.pad.face.config.swan",
"oulunpu = bob.pad.face.config.oulunpu",
# LBPs
"lbp = bob.pad.face.config.lbp_64",
# quality measure
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment