Skip to content
Snippets Groups Projects
Commit 209b4bd3 authored by Amir MOHAMMADI's avatar Amir MOHAMMADI
Browse files

port to imageio-ffmpeg and code cleanup

parent f211fb6c
No related branches found
No related tags found
1 merge request!120port to imageio-ffmpeg and code cleanup
Pipeline #58496 passed with warnings
from .database import VideoPadFile
from .database import VideoPadSample # noqa: F401
from .casiafasd import CasiaFasdPadDatabase
from .casiasurf import CasiaSurfPadDatabase
......@@ -26,7 +25,6 @@ def __appropriate__(*args):
__appropriate__(
VideoPadFile,
ReplayAttackPadDatabase,
ReplayMobilePadDatabase,
MaskAttackPadDatabase,
......
......@@ -2,12 +2,15 @@ from functools import partial
import os
from bob.pad.base.database import PadFile
import bob.bio.video
import bob.io.video
from bob.db.base.annotations import read_annotation_file
from sklearn.preprocessing import FunctionTransformer
from bob.bio.video import VideoAsArray
from bob.pipelines import DelayedSample
from ..utils import frames, number_of_frames
def get_no_transform(x):
return None
def delayed_video_load(
samples,
......@@ -19,9 +22,7 @@ def delayed_video_load(
get_transform=None,
keep_extension_for_annotation=False,
):
if get_transform is None:
def get_transform(x):
return None
get_transform = get_transform or get_no_transform
original_directory = original_directory or ""
annotation_directory = annotation_directory or ""
......@@ -81,119 +82,3 @@ def VideoPadSample(
keep_extension_for_annotation=keep_extension_for_annotation,
),
)
class VideoPadFile(PadFile):
"""A simple base class that defines basic properties of File object for the
use in face PAD experiments.
"""
def __init__(
self,
attack_type,
client_id,
path,
file_id=None,
original_directory=None,
original_extension=".avi",
annotation_directory=None,
annotation_extension=None,
annotation_type=None,
selection_style=None,
max_number_of_frames=None,
step_size=None,
):
super().__init__(
attack_type=attack_type,
client_id=client_id,
path=path,
file_id=file_id,
original_directory=original_directory,
original_extension=original_extension,
annotation_directory=annotation_directory,
annotation_extension=annotation_extension,
annotation_type=annotation_type,
)
self.selection_style = selection_style or "all"
self.max_number_of_frames = max_number_of_frames
self.step_size = step_size
def load(
self,
):
"""Loads the video file and returns in a `bob.bio.video.FrameContainer`.
Returns
-------
:any:`bob.bio.video.VideoAsArray`
The loaded frames inside a frame container.
"""
path = self.make_path(self.original_directory, self.original_extension)
video = bob.bio.video.VideoAsArray(
path,
selection_style=self.selection_style,
max_number_of_frames=self.max_number_of_frames,
step_size=self.step_size,
)
return video
@property
def frames(self):
"""Returns an iterator of frames in the video.
If your database video files need to be loaded in a special way, you need to
override this property.
Returns
-------
collections.abc.Iterator
An iterator returning frames of the video.
"""
path = self.make_path(
directory=self.original_directory, extension=self.original_extension
)
return iter(bob.io.video.reader(path))
@property
def number_of_frames(self):
path = self.make_path(
directory=self.original_directory, extension=self.original_extension
)
return bob.io.video.reader(path).number_of_frames
@property
def frame_shape(self):
"""Returns the size of each frame in this database.
This implementation assumes all frames have the same shape.
It's best to override this method in your database implementation and return
a constant.
Returns
-------
(int, int, int)
The (Channels, Height, Width) sizes.
"""
path = self.make_path(
directory=self.original_directory, extension=self.original_extension
)
frame = next(bob.io.video.reader(path))
return frame.shape
@property
def annotations(self):
"""Reads the annotations
For this property to work, you need to set ``annotation_directory``,
``annotation_extension``, and ``annotation_type`` attributes of the files when
database's object method is called.
Returns
-------
dict
The annotations as a dictionary.
"""
if self.annotation_directory is None:
return None
annotation_file = self.make_path(
directory=self.annotation_directory, extension=self.annotation_extension
)
return read_annotation_file(annotation_file, self.annotation_type)
......@@ -16,10 +16,9 @@ def get_rm_video_transform(sample):
should_flip = sample.should_flip
def transform(video):
video = np.asarray(video)
video = np.rollaxis(video, -1, -2)
if should_flip:
video = video[..., ::-1, :]
if not should_flip:
# after changing to imageio-ffmpeg, we need to flip other way around
video = video[..., ::-1]
return video
return transform
......
......@@ -5,6 +5,7 @@
from nose.plugins.skip import SkipTest
import bob.bio.base
import numpy as np
def test_replayattack():
......@@ -51,8 +52,8 @@ def test_replayattack():
"nose": [152, 164],
}
assert sample.data.shape == (20, 3, 240, 320)
assert sample.data[0][0, 0, 0] == 8
except RuntimeError as e:
np.testing.assert_equal(sample.data[0][:, 0, 0], [8, 9, 11])
except (RuntimeError, FileNotFoundError) as e:
raise SkipTest(e)
......@@ -76,22 +77,49 @@ def test_replaymobile():
len(database.samples(groups=["train", "dev", "eval"], purposes="attack")) == 640
)
sample = database.sort(database.samples())[0]
all_samples = database.sort(database.samples())
sample = all_samples[0]
assert (
sample.key
== "devel/attack/attack_client005_session01_mattescreen_fixed_mobile_photo_lightoff.mov"
), sample.key
assert sample.should_flip
annot = dict(sample.annotations["0"])
assert annot["leye"][1] > annot["reye"][1], annot
assert annot == {
"bottomright": [760, 498],
"topleft": [374, 209],
"leye": [518, 417],
"reye": [522, 291],
"mouthleft": [669, 308],
"mouthright": [666, 407],
"nose": [585, 358],
}, annot
sample2 = [s for s in all_samples if not s.should_flip][0]
assert (
sample2.key
== "devel/attack/attack_client005_session01_mattescreen_fixed_tablet_photo_lightoff.mov"
), sample2.key
assert not sample2.should_flip
annot = dict(sample2.annotations["0"])
assert annot["leye"][1] > annot["reye"][1], annot
assert annot == {
"reye": [873, 305],
"leye": [879, 423],
"nose": [937, 365],
"mouthleft": [1018, 313],
"mouthright": [1023, 405],
"topleft": [747, 226],
"bottomright": [1111, 495],
}, annot
try:
annot = dict(sample.annotations["0"])
assert annot["leye"][1] > annot["reye"][1], annot
assert annot == {
"bottomright": [760, 498],
"topleft": [374, 209],
"leye": [518, 417],
"reye": [522, 291],
"mouthleft": [669, 308],
"mouthright": [666, 407],
"nose": [585, 358],
}
assert sample.data.shape == (20, 3, 720, 1280)
assert sample.data[0][0, 0, 0] == 13
except RuntimeError as e:
assert sample.data.shape == (20, 3, 1280, 720), sample.data.shape
np.testing.assert_equal(sample.data[0][:, 0, 0], [13, 13, 13])
assert sample2.data.shape == (20, 3, 1280, 720), sample2.data.shape
np.testing.assert_equal(sample2.data[0][:, 0, 0], [19, 33, 30])
except (RuntimeError, FileNotFoundError) as e:
raise SkipTest(e)
......@@ -226,9 +254,9 @@ def test_swan():
"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:
assert sample.data.shape == (20, 3, 1280, 720)
np.testing.assert_equal(sample.data[0][:, 0, 0], [255, 255, 253])
except (RuntimeError, FileNotFoundError) as e:
raise SkipTest(e)
......@@ -285,6 +313,6 @@ def test_oulunpu():
"topleft": [632, 394],
}
assert sample.data.shape == (20, 3, 1920, 1080)
assert sample.data[0][0, 0, 0] == 195
except RuntimeError as e:
np.testing.assert_equal(sample.data[0][:, 0, 0], [195, 191, 199])
except (RuntimeError, FileNotFoundError) as e:
raise SkipTest(e)
from bob.pad.face.test.dummy.database import DummyDatabase as Database
from bob.pad.face.utils import yield_faces, scale_face, blocks
from bob.pad.face.utils import yield_faces, scale_face, blocks, frames, number_of_frames
from nose.tools import raises
import numpy
import imageio
def get_pad_sample(none_annotations=False):
......@@ -12,6 +13,26 @@ def get_pad_sample(none_annotations=False):
image = get_pad_sample().data[0]
def test_video_frames():
# get the path to cockatoo.mp4 from imageio-ffmpeg
path = imageio.core.Request("imageio:cockatoo.mp4", "r").get_local_filename()
# read 2 frames
for i, frame in enumerate(frames(path)):
assert frame.shape == (3, 720, 1280), frame.shape
assert frame.ndim == 3, frame.ndim
if i == 0:
numpy.testing.assert_equal(frame[:, 0, 0], [116, 119, 104])
elif i == 1:
numpy.testing.assert_equal(frame[:, 0, 0], [116, 119, 104])
else:
break
# test number of frames
n_frames = number_of_frames(path)
assert n_frames == 280, n_frames
def dummy_cropper(frame, annotations=None):
return frame
......
from bob.bio.face.annotator import min_face_size_validator
from bob.bio.video.annotator import normalize_annotations
from bob.io.video import reader
from imageio import get_reader
from bob.ip.base import scale, block, block_output_shape, block_generator
from bob.ip.color import rgb_to_yuv, rgb_to_hsv
from bob.ip.facedetect import bounding_box_from_annotation
......@@ -8,6 +8,7 @@ from collections import OrderedDict
from functools import partial
import numpy
import random
import bob.io.image
def frames(path):
......@@ -23,8 +24,9 @@ def frames(path):
numpy.ndarray
A frame of the video. The size is (3, 240, 320).
"""
video = reader(path)
return iter(video)
video = get_reader(path)
for frame in video:
yield bob.io.image.to_bob(frame)
def number_of_frames(path):
......@@ -40,8 +42,8 @@ def number_of_frames(path):
int
The number of frames. Then, it yields the frames.
"""
video = reader(path)
return video.number_of_frames
video = get_reader(path)
return video.count_frames()
def bbx_cropper(frame, annotations):
......
......@@ -34,12 +34,14 @@ requirements:
- numpy {{ numpy }}
- scikit-learn {{ scikit_learn }}
- scikit-image {{ scikit_image }}
- imageio-ffmpeg {{ imageio_ffmpeg }}
run:
- python
- setuptools
- {{ pin_compatible('numpy') }}
- {{ pin_compatible('scikit-learn', min_pin='x.x') }}
- {{ pin_compatible('scikit-image') }}
- {{ pin_compatible('imageio-ffmpeg') }}
test:
imports:
......
......@@ -4,66 +4,14 @@
[buildout]
parts = scripts
eggs = bob.pad.face
bob.extension
bob.blitz
bob.core
bob.sp
bob.math
bob.io.base
bob.ip.gabor
bob.measure
bob.ip.base
bob.learn.boosting
bob.io.image
bob.ip.draw
bob.ip.color
bob.io.video
bob.io.matlab
bob.ip.flandmark
bob.ip.facedetect
bob.ip.dlib
bob.ip.qualitymeasure
bob.learn.linear
bob.db.base
bob.learn.em
bob.db.atnt
bob.bio.base
bob.bio.face
bob.bio.video
bob.pad.base
extensions = bob.buildout
mr.developer
auto-checkout = *
develop = src/bob.extension
src/bob.blitz
src/bob.core
src/bob.sp
src/bob.math
src/bob.io.base
src/bob.ip.gabor
src/bob.measure
src/bob.ip.base
src/bob.learn.boosting
src/bob.io.image
src/bob.ip.draw
src/bob.ip.color
src/bob.io.video
src/bob.io.matlab
src/bob.ip.flandmark
src/bob.ip.facedetect
src/bob.ip.dlib
src/bob.ip.qualitymeasure
src/bob.learn.linear
src/bob.db.base
src/bob.learn.em
src/bob.db.atnt
src/bob.bio.base
src/bob.bio.face
src/bob.bio.video
src/bob.pad.base
develop = src/bob.bio.video
.
; options for bob.buildout
......@@ -72,33 +20,7 @@ verbose = true
newest = false
[sources]
bob.extension = git git@gitlab.idiap.ch:bob/bob.extension
bob.blitz = git git@gitlab.idiap.ch:bob/bob.blitz
bob.core = git git@gitlab.idiap.ch:bob/bob.core
bob.sp = git git@gitlab.idiap.ch:bob/bob.sp
bob.math = git git@gitlab.idiap.ch:bob/bob.math
bob.io.base = git git@gitlab.idiap.ch:bob/bob.io.base
bob.ip.gabor = git git@gitlab.idiap.ch:bob/bob.ip.gabor
bob.measure = git git@gitlab.idiap.ch:bob/bob.measure
bob.ip.base = git git@gitlab.idiap.ch:bob/bob.ip.base
bob.learn.boosting = git git@gitlab.idiap.ch:bob/bob.learn.boosting
bob.io.image = git git@gitlab.idiap.ch:bob/bob.io.image
bob.ip.draw = git git@gitlab.idiap.ch:bob/bob.ip.draw
bob.ip.color = git git@gitlab.idiap.ch:bob/bob.ip.color
bob.io.video = git git@gitlab.idiap.ch:bob/bob.io.video
bob.io.matlab = git git@gitlab.idiap.ch:bob/bob.io.matlab
bob.ip.flandmark = git git@gitlab.idiap.ch:bob/bob.ip.flandmark
bob.ip.facedetect = git git@gitlab.idiap.ch:bob/bob.ip.facedetect
bob.ip.dlib = git git@gitlab.idiap.ch:bob/bob.ip.dlib
bob.ip.qualitymeasure = git git@gitlab.idiap.ch:bob/bob.ip.qualitymeasure
bob.learn.linear = git git@gitlab.idiap.ch:bob/bob.learn.linear
bob.db.base = git git@gitlab.idiap.ch:bob/bob.db.base
bob.learn.em = git git@gitlab.idiap.ch:bob/bob.learn.em
bob.db.atnt = git git@gitlab.idiap.ch:bob/bob.db.atnt
bob.bio.base = git git@gitlab.idiap.ch:bob/bob.bio.base
bob.bio.face = git git@gitlab.idiap.ch:bob/bob.bio.face
bob.bio.video = git git@gitlab.idiap.ch:bob/bob.bio.video
bob.pad.base = git git@gitlab.idiap.ch:bob/bob.pad.base
[scripts]
......
......@@ -12,12 +12,6 @@ This section lists all the functionality available in this library allowing to r
Database Interfaces
------------------------------
Base classes
============
.. autoclass:: bob.pad.face.database.VideoPadFile
REPLAY-ATTACK Database
========================
......
......@@ -12,3 +12,4 @@ bob.ip.color
bob.ip.qualitymeasure
scikit-learn
scikit-image
imageio-ffmpeg
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment