Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
bob
bob.pad.face
Commits
7c72e080
Commit
7c72e080
authored
Feb 10, 2020
by
Amir MOHAMMADI
Browse files
[replaymobile][replay][msu_mfsd] improve interfaces to make files independent
parent
006b0c9e
Changes
3
Hide whitespace changes
Inline
Side-by-side
bob/pad/face/database/msu_mfsd.py
View file @
7c72e080
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
#==============================================================================
# Used in ReplayMobilePadFile class
from
bob.bio.video
import
FrameSelector
,
FrameContainer
from
bob.pad.face.database
import
VideoPadFile
# Used in MsuMfsdPadFile class
from
bob.pad.base.database
import
PadDatabase
from
bob.extension
import
rc
import
os
import
numpy
as
np
#==============================================================================
class
MsuMfsdPadFile
(
VideoPadFile
):
"""
A high level implementation of the File class for the MSU MFSD database.
...
...
@@ -40,18 +34,20 @@ class MsuMfsdPadFile(VideoPadFile):
if
f
.
is_real
():
attack_type
=
None
else
:
attack_type
=
'
attack
'
attack_type
=
"
attack
"
# attack_type is a string and I decided to make it like this for this
# particular database. You can do whatever you want for your own database.
super
(
MsuMfsdPadFile
,
self
).
__init__
(
client_id
=
f
.
client_id
,
path
=
f
.
path
,
attack_type
=
attack_type
,
file_id
=
f
.
id
)
#==========================================================================
def
load
(
self
,
directory
=
None
,
extension
=
None
,
frame_selector
=
FrameSelector
(
selection_style
=
'all'
)):
client_id
=
f
.
client_id
,
path
=
f
.
path
,
attack_type
=
attack_type
,
file_id
=
f
.
id
)
def
load
(
self
,
directory
=
None
,
extension
=
None
,
frame_selector
=
FrameSelector
(
selection_style
=
"all"
),
):
"""
Overridden version of the load method defined in the ``VideoPadFile``.
...
...
@@ -76,26 +72,27 @@ class MsuMfsdPadFile(VideoPadFile):
for further details.
"""
_
,
extension
=
os
.
path
.
splitext
(
self
.
f
.
videofile
())
# get file extension
_
,
extension
=
os
.
path
.
splitext
(
self
.
f
.
videofile
())
# get file extension
video_data_array
=
self
.
f
.
load
(
directory
=
directory
,
extension
=
extension
)
video_data_array
=
self
.
f
.
load
(
directory
=
directory
,
extension
=
extension
)
return
frame_selector
(
video_data_array
)
#==============================================================================
class
MsuMfsdPadDatabase
(
PadDatabase
):
"""
A high level implementation of the Database class for the MSU MFSD database.
"""
def
__init__
(
self
,
protocol
=
'grandtest'
,
# grandtest is the default protocol for this database
original_directory
=
None
,
original_extension
=
None
,
**
kwargs
):
self
,
protocol
=
"grandtest"
,
# grandtest is the default protocol for this database
original_directory
=
None
,
original_extension
=
None
,
annotation_directory
=
None
,
annotation_extension
=
'.json'
,
annotation_type
=
'json'
,
**
kwargs
):
"""
**Parameters:**
...
...
@@ -119,19 +116,24 @@ class MsuMfsdPadDatabase(PadDatabase):
# Since the high level API expects different group names than what the low
# level API offers, you need to convert them when necessary
self
.
low_level_group_names
=
(
'train'
,
'devel'
,
'test'
)
# group names in the low-level database interface
"train"
,
"devel"
,
"test"
,
)
# group names in the low-level database interface
self
.
high_level_group_names
=
(
'train'
,
'dev'
,
'eval'
)
# names are expected to be like that in objects() function
"train"
,
"dev"
,
"eval"
,
)
# names are expected to be like that in objects() function
# Always use super to call parent class methods.
super
(
MsuMfsdPadDatabase
,
self
).
__init__
(
name
=
'
msu-mfsd
'
,
name
=
"
msu-mfsd
"
,
protocol
=
protocol
,
original_directory
=
original_directory
,
original_extension
=
original_extension
,
**
kwargs
)
**
kwargs
)
@
property
def
original_directory
(
self
):
...
...
@@ -141,13 +143,9 @@ class MsuMfsdPadDatabase(PadDatabase):
def
original_directory
(
self
,
value
):
self
.
db
.
original_directory
=
value
#==========================================================================
def
objects
(
self
,
groups
=
None
,
protocol
=
None
,
purposes
=
None
,
model_ids
=
None
,
**
kwargs
):
def
objects
(
self
,
groups
=
None
,
protocol
=
None
,
purposes
=
None
,
model_ids
=
None
,
**
kwargs
):
"""
This function returns lists of MsuMfsdPadFile objects, which fulfill the given restrictions.
...
...
@@ -179,16 +177,21 @@ class MsuMfsdPadDatabase(PadDatabase):
# Convert group names to low-level group names here.
groups
=
self
.
convert_names_to_lowlevel
(
groups
,
self
.
low_level_group_names
,
self
.
high_level_group_names
)
groups
,
self
.
low_level_group_names
,
self
.
high_level_group_names
)
# Since this database was designed for PAD experiments, nothing special
# needs to be done here.
files
=
self
.
db
.
objects
(
group
=
groups
,
cls
=
purposes
,
**
kwargs
)
files
=
[
MsuMfsdPadFile
(
f
)
for
f
in
files
]
for
f
in
files
:
f
.
original_directory
=
self
.
original_directory
f
.
annotation_directory
=
self
.
annotation_directory
f
.
annotation_extension
=
self
.
annotation_extension
f
.
annotation_type
=
self
.
annotation_type
return
files
#==========================================================================
def
annotations
(
self
,
f
):
"""
Return annotations for a given file object ``f``, which is an instance
...
...
@@ -220,12 +223,14 @@ class MsuMfsdPadDatabase(PadDatabase):
for
frame_annots
in
annots
:
topleft
=
(
np
.
int
(
frame_annots
[
2
]),
np
.
int
(
frame_annots
[
1
]))
bottomright
=
(
np
.
int
(
frame_annots
[
2
]
+
frame_annots
[
4
]),
np
.
int
(
frame_annots
[
1
]
+
frame_annots
[
3
]))
bottomright
=
(
np
.
int
(
frame_annots
[
2
]
+
frame_annots
[
4
]),
np
.
int
(
frame_annots
[
1
]
+
frame_annots
[
3
]),
)
annotations
[
str
(
np
.
int
(
frame_annots
[
0
]))]
=
{
'
topleft
'
:
topleft
,
'
bottomright
'
:
bottomright
"
topleft
"
:
topleft
,
"
bottomright
"
:
bottomright
,
}
return
annotations
bob/pad/face/database/replay.py
View file @
7c72e080
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Used in ReplayMobilePadFile class
from
bob.pad.base.database
import
PadDatabase
from
bob.pad.base.database
import
PadDatabase
# Used in ReplayMobilePadFile class
from
bob.pad.face.database
import
VideoPadFile
# Used in ReplayPadFile class
from
bob.pad.face.utils
import
frames
,
number_of_frames
from
bob.extension
import
rc
from
bob.ip.facedetect
import
expected_eye_positions
,
BoundingBox
from
bob.db.base.annotations
import
read_annotation_file
REPLAY_ATTACK_FRAME_SHAPE
=
(
3
,
240
,
320
)
class
ReplayPadFile
(
VideoPadFile
):
...
...
@@ -35,16 +37,73 @@ class ReplayPadFile(VideoPadFile):
if
f
.
is_real
():
attack_type
=
None
else
:
attack_type
=
'
attack
'
attack_type
=
"
attack
"
# attack_type is a string and I decided to make it like this for this
# particular database. You can do whatever you want for your own
# database.
super
(
ReplayPadFile
,
self
).
__init__
(
client_id
=
f
.
client_id
,
path
=
f
.
path
,
attack_type
=
attack_type
,
file_id
=
f
.
id
)
client_id
=
f
.
client_id
,
path
=
f
.
path
,
attack_type
=
attack_type
,
file_id
=
f
.
id
)
@
property
def
frame_shape
(
self
):
"""Returns the size of each frame in this database.
Returns
-------
(int, int, int)
The (#Channels, Height, Width) which is (3, 240, 320).
"""
return
REPLAY_ATTACK_FRAME_SHAPE
@
property
def
annotations
(
self
):
"""
Return annotations as a dictionary of dictionaries.
If the file object has an attribute of annotation_directory, it will read
annotations from there instead of loading annotations that are shipped with the
database.
Returns
-------
annotations : :py:class:`dict`
A dictionary containing the annotations for each frame in the
video. Dictionary structure:
``annotations = {'1': frame1_dict, '2': frame1_dict, ...}``.Where
``frameN_dict = {'topleft': (row, col), 'bottomright': (row, col)}``
is the dictionary defining the coordinates of the face bounding box
in frame N.
"""
if
(
hasattr
(
self
,
"annotation_directory"
)
and
self
.
annotation_directory
is
not
None
):
path
=
self
.
make_path
(
self
.
annotation_directory
,
extension
=
".json"
)
return
read_annotation_file
(
path
,
annotation_type
=
"json"
)
# numpy array containing the face bounding box data for each video
# frame, returned data format described in the f.bbx() method of the
# low level interface
annots
=
self
.
f
.
bbx
(
directory
=
self
.
original_directory
)
annotations
=
{}
# dictionary to return
for
fn
,
frame_annots
in
enumerate
(
annots
):
topleft
=
(
frame_annots
[
2
],
frame_annots
[
1
])
bottomright
=
(
frame_annots
[
2
]
+
frame_annots
[
4
],
frame_annots
[
1
]
+
frame_annots
[
3
],
)
annotations
[
str
(
fn
)]
=
{
"topleft"
:
topleft
,
"bottomright"
:
bottomright
}
size
=
(
bottomright
[
0
]
-
topleft
[
0
],
bottomright
[
1
]
-
topleft
[
1
])
bounding_box
=
BoundingBox
(
topleft
,
size
)
annotations
[
str
(
fn
)].
update
(
expected_eye_positions
(
bounding_box
))
return
annotations
class
ReplayPadDatabase
(
PadDatabase
):
...
...
@@ -54,12 +113,14 @@ class ReplayPadDatabase(PadDatabase):
"""
def
__init__
(
self
,
# grandtest is the default protocol for this database
protocol
=
'grandtest'
,
original_directory
=
rc
[
'bob.db.replay.directory'
],
original_extension
=
'.mov'
,
**
kwargs
):
self
,
# grandtest is the default protocol for this database
protocol
=
"grandtest"
,
original_directory
=
rc
[
"bob.db.replay.directory"
],
original_extension
=
".mov"
,
annotation_directory
=
None
,
**
kwargs
):
"""
Parameters
----------
...
...
@@ -86,19 +147,25 @@ class ReplayPadDatabase(PadDatabase):
# Since the high level API expects different group names than what the
# low level API offers, you need to convert them when necessary
self
.
low_level_group_names
=
(
'train'
,
'devel'
,
'test'
)
# group names in the low-level database interface
"train"
,
"devel"
,
"test"
,
)
# group names in the low-level database interface
self
.
high_level_group_names
=
(
'train'
,
'dev'
,
'eval'
)
# names are expected to be like that in objects() function
"train"
,
"dev"
,
"eval"
,
)
# names are expected to be like that in objects() function
# Always use super to call parent class methods.
super
(
ReplayPadDatabase
,
self
).
__init__
(
name
=
'
replay
'
,
name
=
"
replay
"
,
protocol
=
protocol
,
original_directory
=
original_directory
,
original_extension
=
original_extension
,
**
kwargs
)
annotation_directory
=
annotation_directory
,
**
kwargs
)
@
property
def
original_directory
(
self
):
...
...
@@ -108,12 +175,9 @@ class ReplayPadDatabase(PadDatabase):
def
original_directory
(
self
,
value
):
self
.
db
.
original_directory
=
value
def
objects
(
self
,
groups
=
None
,
protocol
=
None
,
purposes
=
None
,
model_ids
=
None
,
**
kwargs
):
def
objects
(
self
,
groups
=
None
,
protocol
=
None
,
purposes
=
None
,
model_ids
=
None
,
**
kwargs
):
"""
This function returns lists of ReplayPadFile objects, which fulfill the
given restrictions.
...
...
@@ -146,12 +210,19 @@ class ReplayPadDatabase(PadDatabase):
# Convert group names to low-level group names here.
groups
=
self
.
convert_names_to_lowlevel
(
groups
,
self
.
low_level_group_names
,
self
.
high_level_group_names
)
groups
,
self
.
low_level_group_names
,
self
.
high_level_group_names
)
# Since this database was designed for PAD experiments, nothing special
# needs to be done here.
files
=
self
.
db
.
objects
(
protocol
=
protocol
,
groups
=
groups
,
cls
=
purposes
,
**
kwargs
)
protocol
=
protocol
,
groups
=
groups
,
cls
=
purposes
,
**
kwargs
)
files
=
[
ReplayPadFile
(
f
)
for
f
in
files
]
# set the attributes
for
f
in
files
:
f
.
original_directory
=
self
.
original_directory
f
.
original_extension
=
self
.
original_extension
f
.
annotation_directory
=
self
.
annotation_directory
return
files
def
annotations
(
self
,
f
):
...
...
@@ -178,26 +249,7 @@ class ReplayPadDatabase(PadDatabase):
is the dictionary defining the coordinates of the face bounding box
in frame N.
"""
# numpy array containing the face bounding box data for each video
# frame, returned data format described in the f.bbx() method of the
# low level interface
annots
=
f
.
f
.
bbx
(
directory
=
self
.
original_directory
)
annotations
=
{}
# dictionary to return
for
fn
,
frame_annots
in
enumerate
(
annots
):
topleft
=
(
frame_annots
[
2
],
frame_annots
[
1
])
bottomright
=
(
frame_annots
[
2
]
+
frame_annots
[
4
],
frame_annots
[
1
]
+
frame_annots
[
3
])
annotations
[
str
(
fn
)]
=
{
'topleft'
:
topleft
,
'bottomright'
:
bottomright
}
return
annotations
return
f
.
annotations
def
frames
(
self
,
padfile
):
"""Yields the frames of the padfile one by one.
...
...
@@ -212,11 +264,7 @@ class ReplayPadDatabase(PadDatabase):
:any:`numpy.array`
A frame of the video. The size is (3, 240, 320).
"""
vfilename
=
padfile
.
make_path
(
directory
=
self
.
original_directory
,
extension
=
self
.
original_extension
)
for
retval
in
frames
(
vfilename
):
yield
retval
return
padfile
.
frames
def
number_of_frames
(
self
,
padfile
):
"""Returns the number of frames in a video file.
...
...
@@ -231,10 +279,7 @@ class ReplayPadDatabase(PadDatabase):
int
The number of frames.
"""
vfilename
=
padfile
.
make_path
(
directory
=
self
.
original_directory
,
extension
=
self
.
original_extension
)
return
number_of_frames
(
vfilename
)
return
padfile
.
number_of_frames
@
property
def
frame_shape
(
self
):
...
...
@@ -245,4 +290,4 @@ class ReplayPadDatabase(PadDatabase):
(int, int, int)
The (#Channels, Height, Width) which is (3, 240, 320).
"""
return
(
3
,
240
,
320
)
return
REPLAY_ATTACK_FRAME_SHAPE
bob/pad/face/database/replay_mobile.py
View file @
7c72e080
...
...
@@ -5,48 +5,13 @@
from
bob.bio.video
import
FrameSelector
from
bob.pad.base.database
import
PadDatabase
from
bob.pad.face.database
import
VideoPadFile
from
bob.pad.face.utils
import
frames
,
number_of_frames
from
bob.pad.face.utils
import
number_of_frames
from
bob.db.base.annotations
import
read_annotation_file
import
numpy
from
bob.extension
import
rc
REPLAYMOBILE_FRAME_SHAPE
=
(
3
,
1280
,
720
)
def
replaymobile_annotations
(
lowlevelfile
,
original_directory
):
# numpy array containing the face bounding box data for each video
# frame, returned data format described in the f.bbx() method of the
# low level interface
annots
=
lowlevelfile
.
bbx
(
directory
=
original_directory
)
annotations
=
{}
# dictionary to return
for
fn
,
frame_annots
in
enumerate
(
annots
):
topleft
=
(
frame_annots
[
1
],
frame_annots
[
0
])
bottomright
=
(
frame_annots
[
1
]
+
frame_annots
[
3
],
frame_annots
[
0
]
+
frame_annots
[
2
])
annotations
[
str
(
fn
)]
=
{
'topleft'
:
topleft
,
'bottomright'
:
bottomright
}
return
annotations
def
replaymobile_frames
(
lowlevelfile
,
original_directory
):
vfilename
=
lowlevelfile
.
make_path
(
directory
=
original_directory
,
extension
=
'.mov'
)
is_not_tablet
=
not
lowlevelfile
.
is_tablet
()
for
frame
in
frames
(
vfilename
):
frame
=
numpy
.
rollaxis
(
frame
,
2
,
1
)
if
is_not_tablet
:
frame
=
frame
[:,
::
-
1
,
:]
yield
frame
class
ReplayMobilePadFile
(
VideoPadFile
):
"""
A high level implementation of the File class for the Replay-Mobile
...
...
@@ -116,6 +81,7 @@ class ReplayMobilePadFile(VideoPadFile):
@
property
def
annotations
(
self
):
from
bob.db.replaymobile.models
import
replaymobile_annotations
if
self
.
annotation_directory
is
not
None
:
# return the external annotations
annotations
=
read_annotation_file
(
...
...
@@ -129,6 +95,7 @@ class ReplayMobilePadFile(VideoPadFile):
@
property
def
frames
(
self
):
from
bob.db.replaymobile.models
import
replaymobile_frames
return
replaymobile_frames
(
self
.
f
,
self
.
original_directory
)
@
property
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment