Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
bob
bob.bio.face
Commits
d77ef348
Commit
d77ef348
authored
May 29, 2015
by
Manuel Günther
Browse files
Added extractors from FaceRecLib
parent
97ef6a7c
Changes
20
Show whitespace changes
Inline
Side-by-side
bob/bio/face/__init__.py
View file @
d77ef348
from
.
import
preprocessor
from
.
import
extractor
from
.
import
algorithm
from
.
import
test
...
...
bob/bio/face/config/extractor/__init__.py
0 → 100644
View file @
d77ef348
bob/bio/face/config/extractor/dct_blocks.py
0 → 100644
View file @
d77ef348
#!/usr/bin/env python
import
bob.bio.face
extractor
=
bob
.
bio
.
face
.
extractor
.
DCTBlocks
(
block_size
=
12
,
block_overlap
=
11
,
number_of_dct_coefficients
=
45
)
bob/bio/face/config/extractor/eigenface.py
0 → 100644
View file @
d77ef348
#!/usr/bin/env python
import
bob.bio.face
# compute eigenfaces using the training database
extractor
=
bob
.
bio
.
face
.
extractor
.
Eigenface
(
subspace_dimension
=
100
)
bob/bio/face/config/extractor/grid_graph.py
0 → 100644
View file @
d77ef348
#!/usr/bin/env python
import
bob.bio.base
import
bob.bio.face
import
math
# load the face cropping parameters
cropper
=
bob
.
bio
.
base
.
load_resource
(
"face-crop-eyes"
,
"preprocessor"
)
extractor
=
bob
.
bio
.
face
.
extractor
.
GridGraph
(
# Gabor parameters
gabor_sigma
=
math
.
sqrt
(
2.
)
*
math
.
pi
,
# what kind of information to extract
normalize_gabor_jets
=
True
,
# setup of the fixed grid
node_distance
=
(
4
,
4
),
first_node
=
(
6
,
6
),
image_resolution
=
cropper
.
cropped_image_size
)
bob/bio/face/config/extractor/lgbphs.py
0 → 100644
View file @
d77ef348
#!/usr/bin/env python
import
bob.bio.face
import
math
# feature extraction
extractor
=
bob
.
bio
.
face
.
extractor
.
LGBPHS
(
# block setup
block_size
=
10
,
block_overlap
=
4
,
# Gabor parameters
gabor_sigma
=
math
.
sqrt
(
2.
)
*
math
.
pi
,
# LBP setup (we use the defaults)
# histogram setup
sparse_histogram
=
True
)
bob/bio/face/extractor/DCTBlocks.py
0 → 100644
View file @
d77ef348
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# Laurent El Shafey <Laurent.El-Shafey@idiap.ch>
"""Features for face recognition"""
import
bob.ip.base
import
numpy
from
bob.bio.base.extractor
import
Extractor
class
DCTBlocks
(
Extractor
):
"""Extracts DCT blocks"""
def
__init__
(
self
,
block_size
=
12
,
# 1 or two parameters for block size
block_overlap
=
11
,
# 1 or two parameters for block overlap
number_of_dct_coefficients
=
45
,
normalize_blocks
=
True
,
normalize_dcts
=
True
,
auto_reduce_coefficients
=
False
):
# call base class constructor
Extractor
.
__init__
(
self
,
block_size
=
block_size
,
block_overlap
=
block_overlap
,
number_of_dct_coefficients
=
number_of_dct_coefficients
,
normalize_blocks
=
normalize_blocks
,
normalize_dcts
=
normalize_dcts
,
auto_reduce_coefficients
=
auto_reduce_coefficients
)
# block parameters
block_size
=
block_size
if
isinstance
(
block_size
,
(
tuple
,
list
))
else
(
block_size
,
block_size
)
block_overlap
=
block_overlap
if
isinstance
(
block_overlap
,
(
tuple
,
list
))
else
(
block_overlap
,
block_overlap
)
if
block_size
[
0
]
<
block_overlap
[
0
]
or
block_size
[
1
]
<
block_overlap
[
1
]:
raise
ValueError
(
"The overlap '%s' is bigger than the block size '%s'. This won't work. Please check your setup!"
%
(
block_overlap
,
block_size
))
if
block_size
[
0
]
*
block_size
[
1
]
<=
number_of_dct_coefficients
:
if
auto_reduce_coefficients
:
number_of_dct_coefficients
=
block_size
[
0
]
*
block_size
[
1
]
-
1
else
:
raise
ValueError
(
"You selected more coefficients %d than your blocks have %d. This won't work. Please check your setup!"
%
(
number_of_dct_coefficients
,
block_size
[
0
]
*
block_size
[
1
]))
self
.
dct_features
=
bob
.
ip
.
base
.
DCTFeatures
(
number_of_dct_coefficients
,
block_size
,
block_overlap
,
normalize_blocks
,
normalize_dcts
)
def
__call__
(
self
,
image
):
"""Computes and returns DCT blocks for the given input image"""
assert
isinstance
(
image
,
numpy
.
ndarray
)
assert
image
.
ndim
==
2
assert
image
.
dtype
==
numpy
.
float64
# Computes DCT features
return
self
.
dct_features
(
image
)
bob/bio/face/extractor/Eigenface.py
0 → 100644
View file @
d77ef348
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# Manuel Guenther <Manuel.Guenther@idiap.ch>
import
numpy
import
bob.learn.linear
import
bob.io.base
from
bob.bio.base.extractor
import
Extractor
import
logging
logger
=
logging
.
getLogger
(
"bob.bio.face"
)
class
Eigenface
(
Extractor
):
"""Extracts grid graphs from the images"""
def
__init__
(
self
,
subspace_dimension
):
# We have to register that this function will need a training step
Extractor
.
__init__
(
self
,
requires_training
=
True
,
subspace_dimension
=
subspace_dimension
)
self
.
subspace_dimension
=
subspace_dimension
def
_check_data
(
self
,
data
):
assert
isinstance
(
data
,
numpy
.
ndarray
)
assert
data
.
ndim
==
2
assert
data
.
dtype
==
numpy
.
float64
def
train
(
self
,
image_list
,
extractor_file
):
"""Trains the eigenface extractor using the given list of training images"""
[
self
.
_check_data
(
image
)
for
image
in
image_list
]
# Initializes an array for the data
data
=
numpy
.
vstack
([
image
.
flatten
()
for
image
in
image_list
])
logger
.
info
(
" -> Training LinearMachine using PCA (SVD)"
)
t
=
bob
.
learn
.
linear
.
PCATrainer
()
self
.
machine
,
__eig_vals
=
t
.
train
(
data
)
# Machine: get shape, then resize
self
.
machine
.
resize
(
self
.
machine
.
shape
[
0
],
self
.
subspace_dimension
)
self
.
machine
.
save
(
bob
.
io
.
base
.
HDF5File
(
extractor_file
,
"w"
))
def
load
(
self
,
extractor_file
):
# read PCA projector
self
.
machine
=
bob
.
learn
.
linear
.
Machine
(
bob
.
io
.
base
.
HDF5File
(
extractor_file
))
def
__call__
(
self
,
image
):
"""Projects the data using the stored covariance matrix"""
self
.
_check_data
(
image
)
# Projects the data
return
self
.
machine
(
image
.
flatten
())
bob/bio/face/extractor/GridGraph.py
0 → 100644
View file @
d77ef348
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# Manuel Guenther <Manuel.Guenther@idiap.ch>
import
bob.ip.gabor
import
bob.io.base
import
numpy
import
math
from
bob.bio.base.extractor
import
Extractor
class
GridGraph
(
Extractor
):
"""Extracts grid graphs from the images"""
def
__init__
(
self
,
# Gabor parameters
gabor_directions
=
8
,
gabor_scales
=
5
,
gabor_sigma
=
2.
*
math
.
pi
,
gabor_maximum_frequency
=
math
.
pi
/
2.
,
gabor_frequency_step
=
math
.
sqrt
(.
5
),
gabor_power_of_k
=
0
,
gabor_dc_free
=
True
,
# what kind of information to extract
normalize_gabor_jets
=
True
,
# setup of the aligned grid
eyes
=
None
,
# if set, the grid setup will be aligned to the eye positions {'leye' : LEFT_EYE_POS, 'reye' : RIGHT_EYE_POS},
nodes_between_eyes
=
4
,
nodes_along_eyes
=
2
,
nodes_above_eyes
=
3
,
nodes_below_eyes
=
7
,
# setup of static grid
node_distance
=
None
,
# one or two integral values
image_resolution
=
None
,
# always two integral values
first_node
=
None
,
# one or two integral values, or None -> automatically determined
):
# call base class constructor
Extractor
.
__init__
(
self
,
gabor_directions
=
gabor_directions
,
gabor_scales
=
gabor_scales
,
gabor_sigma
=
gabor_sigma
,
gabor_maximum_frequency
=
gabor_maximum_frequency
,
gabor_frequency_step
=
gabor_frequency_step
,
gabor_power_of_k
=
gabor_power_of_k
,
gabor_dc_free
=
gabor_dc_free
,
normalize_gabor_jets
=
normalize_gabor_jets
,
eyes
=
eyes
,
nodes_between_eyes
=
nodes_between_eyes
,
nodes_along_eyes
=
nodes_along_eyes
,
nodes_above_eyes
=
nodes_above_eyes
,
nodes_below_eyes
=
nodes_below_eyes
,
node_distance
=
node_distance
,
image_resolution
=
image_resolution
,
first_node
=
first_node
)
# create Gabor wavelet transform class
self
.
gwt
=
bob
.
ip
.
gabor
.
Transform
(
number_of_scales
=
gabor_scales
,
number_of_directions
=
gabor_directions
,
sigma
=
gabor_sigma
,
k_max
=
gabor_maximum_frequency
,
k_fac
=
gabor_frequency_step
,
power_of_k
=
gabor_power_of_k
,
dc_free
=
gabor_dc_free
)
# create graph extractor
if
eyes
is
not
None
:
self
.
graph
=
bob
.
ip
.
gabor
.
Graph
(
righteye
=
[
int
(
e
)
for
e
in
eyes
[
'reye'
]],
lefteye
=
[
int
(
e
)
for
e
in
eyes
[
'leye'
]],
between
=
int
(
nodes_between_eyes
),
along
=
int
(
nodes_along_eyes
),
above
=
int
(
nodes_above_eyes
),
below
=
int
(
nodes_below_eyes
)
)
else
:
if
node_distance
is
None
or
image_resolution
is
None
:
raise
ValueError
(
"Please specify either 'eyes' or the grid parameters 'first_node', 'last_node', and 'node_distance'!"
)
if
isinstance
(
node_distance
,
(
int
,
float
)):
node_distance
=
(
int
(
node_distance
),
int
(
node_distance
))
if
first_node
is
None
:
first_node
=
[
0
,
0
]
for
i
in
(
0
,
1
):
offset
=
int
((
image_resolution
[
i
]
-
int
(
image_resolution
[
i
]
/
node_distance
[
i
])
*
node_distance
[
i
])
/
2
)
if
offset
<
node_distance
[
i
]
//
2
:
# This is not tested, but should ALWAYS be the case.
offset
+=
node_distance
[
i
]
//
2
first_node
[
i
]
=
offset
last_node
=
tuple
([
int
(
image_resolution
[
i
]
-
max
(
first_node
[
i
],
1
))
for
i
in
(
0
,
1
)])
# take the specified nodes
self
.
graph
=
bob
.
ip
.
gabor
.
Graph
(
first
=
first_node
,
last
=
last_node
,
step
=
node_distance
)
self
.
normalize_jets
=
normalize_gabor_jets
self
.
trafo_image
=
None
def
__call__
(
self
,
image
):
assert
image
.
ndim
==
2
assert
isinstance
(
image
,
numpy
.
ndarray
)
assert
image
.
dtype
==
numpy
.
float64
if
self
.
trafo_image
is
None
or
self
.
trafo_image
.
shape
[
1
:
3
]
!=
image
.
shape
:
# create trafo image
self
.
trafo_image
=
numpy
.
ndarray
((
self
.
gwt
.
number_of_wavelets
,
image
.
shape
[
0
],
image
.
shape
[
1
]),
numpy
.
complex128
)
# perform Gabor wavelet transform
self
.
gwt
.
transform
(
image
,
self
.
trafo_image
)
# extract face graph
jets
=
self
.
graph
.
extract
(
self
.
trafo_image
)
# normalize the Gabor jets of the graph only
if
self
.
normalize_jets
:
[
j
.
normalize
()
for
j
in
jets
]
# return the extracted face graph
return
jets
def
write_feature
(
self
,
feature
,
feature_file
):
feature_file
=
feature_file
if
isinstance
(
feature_file
,
bob
.
io
.
base
.
HDF5File
)
else
bob
.
io
.
base
.
HDF5File
(
feature_file
,
'w'
)
bob
.
ip
.
gabor
.
save_jets
(
feature
,
feature_file
)
def
read_feature
(
self
,
feature_file
):
return
bob
.
ip
.
gabor
.
load_jets
(
bob
.
io
.
base
.
HDF5File
(
feature_file
))
bob/bio/face/extractor/LGBPHS.py
0 → 100644
View file @
d77ef348
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# Manuel Guenther <Manuel.Guenther@idiap.ch>
import
bob.ip.gabor
import
bob.ip.base
import
numpy
import
math
from
bob.bio.base.extractor
import
Extractor
class
LGBPHS
(
Extractor
):
"""Extractor for local Gabor binary pattern histogram sequences"""
def
__init__
(
self
,
# Block setup
block_size
,
# one or two parameters for block size
block_overlap
=
0
,
# one or two parameters for block overlap
# Gabor parameters
gabor_directions
=
8
,
gabor_scales
=
5
,
gabor_sigma
=
2.
*
math
.
pi
,
gabor_maximum_frequency
=
math
.
pi
/
2.
,
gabor_frequency_step
=
math
.
sqrt
(.
5
),
gabor_power_of_k
=
0
,
gabor_dc_free
=
True
,
use_gabor_phases
=
False
,
# LBP parameters
lbp_radius
=
2
,
lbp_neighbor_count
=
8
,
lbp_uniform
=
True
,
lbp_circular
=
True
,
lbp_rotation_invariant
=
False
,
lbp_compare_to_average
=
False
,
lbp_add_average
=
False
,
# histogram options
sparse_histogram
=
False
,
split_histogram
=
None
):
"""Initializes the local Gabor binary pattern histogram sequence tool chain with the given file selector object"""
# call base class constructor
Extractor
.
__init__
(
self
,
block_size
=
block_size
,
block_overlap
=
block_overlap
,
gabor_directions
=
gabor_directions
,
gabor_scales
=
gabor_scales
,
gabor_sigma
=
gabor_sigma
,
gabor_maximum_frequency
=
gabor_maximum_frequency
,
gabor_frequency_step
=
gabor_frequency_step
,
gabor_power_of_k
=
gabor_power_of_k
,
gabor_dc_free
=
gabor_dc_free
,
use_gabor_phases
=
use_gabor_phases
,
lbp_radius
=
lbp_radius
,
lbp_neighbor_count
=
lbp_neighbor_count
,
lbp_uniform
=
lbp_uniform
,
lbp_circular
=
lbp_circular
,
lbp_rotation_invariant
=
lbp_rotation_invariant
,
lbp_compare_to_average
=
lbp_compare_to_average
,
lbp_add_average
=
lbp_add_average
,
sparse_histogram
=
sparse_histogram
,
split_histogram
=
split_histogram
)
# block parameters
self
.
block_size
=
block_size
if
isinstance
(
block_size
,
(
tuple
,
list
))
else
(
block_size
,
block_size
)
self
.
block_overlap
=
block_overlap
if
isinstance
(
block_overlap
,
(
tuple
,
list
))
else
(
block_overlap
,
block_overlap
)
if
self
.
block_size
[
0
]
<
self
.
block_overlap
[
0
]
or
self
.
block_size
[
1
]
<
self
.
block_overlap
[
1
]:
raise
ValueError
(
"The overlap is bigger than the block size. This won't work. Please check your setup!"
)
# Gabor wavelet transform class
self
.
gwt
=
bob
.
ip
.
gabor
.
Transform
(
number_of_scales
=
gabor_scales
,
number_of_directions
=
gabor_directions
,
sigma
=
gabor_sigma
,
k_max
=
gabor_maximum_frequency
,
k_fac
=
gabor_frequency_step
,
power_of_k
=
gabor_power_of_k
,
dc_free
=
gabor_dc_free
)
self
.
trafo_image
=
None
self
.
use_phases
=
use_gabor_phases
self
.
lbp
=
bob
.
ip
.
base
.
LBP
(
neighbors
=
lbp_neighbor_count
,
radius
=
float
(
lbp_radius
),
circular
=
lbp_circular
,
to_average
=
lbp_compare_to_average
,
add_average_bit
=
lbp_add_average
,
uniform
=
lbp_uniform
,
rotation_invariant
=
lbp_rotation_invariant
,
border_handling
=
'wrap'
)
self
.
split
=
split_histogram
self
.
sparse
=
sparse_histogram
if
self
.
sparse
and
self
.
split
:
raise
ValueError
(
"Sparse histograms cannot be split! Check your setup!"
)
def
_fill
(
self
,
lgbphs_array
,
lgbphs_blocks
,
j
):
"""Copies the given array into the given blocks"""
# fill array in the desired shape
if
self
.
split
is
None
:
start
=
j
*
self
.
n_bins
*
self
.
n_blocks
for
b
in
range
(
self
.
n_blocks
):
lgbphs_array
[
start
+
b
*
self
.
n_bins
:
start
+
(
b
+
1
)
*
self
.
n_bins
]
=
lgbphs_blocks
[
b
][:]
elif
self
.
split
==
'blocks'
:
for
b
in
range
(
self
.
n_blocks
):
lgbphs_array
[
b
,
j
*
self
.
n_bins
:
(
j
+
1
)
*
self
.
n_bins
]
=
lgbphs_blocks
[
b
][:]
elif
self
.
split
==
'wavelets'
:
for
b
in
range
(
self
.
n_blocks
):
lgbphs_array
[
j
,
b
*
self
.
n_bins
:
(
b
+
1
)
*
self
.
n_bins
]
=
lgbphs_blocks
[
b
][:]
elif
self
.
split
==
'both'
:
for
b
in
range
(
self
.
n_blocks
):
lgbphs_array
[
j
*
self
.
n_blocks
+
b
,
0
:
self
.
n_bins
]
=
lgbphs_blocks
[
b
][:]
def
_sparsify
(
self
,
array
):
"""This function generates a sparse histogram from a non-sparse one."""
if
not
self
.
sparse
:
return
array
if
len
(
array
.
shape
)
==
2
and
array
.
shape
[
0
]
==
2
:
# already sparse
return
array
assert
len
(
array
.
shape
)
==
1
indices
=
[]
values
=
[]
for
i
in
range
(
array
.
shape
[
0
]):
if
array
[
i
]
!=
0.
:
indices
.
append
(
i
)
values
.
append
(
array
[
i
])
return
numpy
.
array
([
indices
,
values
],
dtype
=
numpy
.
float64
)
def
__call__
(
self
,
image
):
"""Extracts the local Gabor binary pattern histogram sequence from the given image"""
assert
image
.
ndim
==
2
assert
isinstance
(
image
,
numpy
.
ndarray
)
assert
image
.
dtype
==
numpy
.
float64
# perform GWT on image
if
self
.
trafo_image
is
None
or
self
.
trafo_image
.
shape
[
1
:
3
]
!=
image
.
shape
:
# create trafo image
self
.
trafo_image
=
numpy
.
ndarray
((
self
.
gwt
.
number_of_wavelets
,
image
.
shape
[
0
],
image
.
shape
[
1
]),
numpy
.
complex128
)
# perform Gabor wavelet transform
self
.
gwt
.
transform
(
image
,
self
.
trafo_image
)
jet_length
=
self
.
gwt
.
number_of_wavelets
*
(
2
if
self
.
use_phases
else
1
)
lgbphs_array
=
None
# iterate through the layers of the trafo image
for
j
in
range
(
self
.
gwt
.
number_of_wavelets
):
# compute absolute part of complex response
abs_image
=
numpy
.
abs
(
self
.
trafo_image
[
j
])
# Computes LBP histograms
abs_blocks
=
bob
.
ip
.
base
.
lbphs
(
abs_image
,
self
.
lbp
,
self
.
block_size
,
self
.
block_overlap
)
# Converts to Blitz array (of different dimensionalities)
self
.
n_bins
=
abs_blocks
.
shape
[
1
]
self
.
n_blocks
=
abs_blocks
.
shape
[
0
]
if
self
.
split
is
None
:
shape
=
(
self
.
n_blocks
*
self
.
n_bins
*
jet_length
,)
elif
self
.
split
==
'blocks'
:
shape
=
(
self
.
n_blocks
,
self
.
n_bins
*
jet_length
)
elif
self
.
split
==
'wavelets'
:
shape
=
(
jet_length
,
self
.
n_bins
*
self
.
n_blocks
)
elif
self
.
split
==
'both'
:
shape
=
(
jet_length
*
self
.
n_blocks
,
self
.
n_bins
)
else
:
raise
ValueError
(
"The split parameter must be one of ['blocks', 'wavelets', 'both'] or None"
)
# create new array if not done yet
if
lgbphs_array
is
None
:
lgbphs_array
=
numpy
.
ndarray
(
shape
,
'float64'
)
# fill the array with the absolute values of the Gabor wavelet transform
self
.
_fill
(
lgbphs_array
,
abs_blocks
,
j
)
if
self
.
use_phases
:
# compute phase part of complex response
phase_image
=
numpy
.
angle
(
self
.
trafo_image
[
j
])
# Computes LBP histograms
phase_blocks
=
bob
.
ip
.
base
.
lbphs
(
phase_image
,
self
.
lbp
,
self
.
block_size
,
self
.
block_overlap
)
# fill the array with the phases at the end of the blocks
self
.
_fill
(
lgbphs_array
,
phase_blocks
,
j
+
self
.
gwt
.
number_of_wavelets
)
# return the concatenated list of all histograms
return
self
.
_sparsify
(
lgbphs_array
)
bob/bio/face/extractor/__init__.py
0 → 100644
View file @
d77ef348
from
.DCTBlocks
import
DCTBlocks
from
.GridGraph
import
GridGraph
from
.LGBPHS
import
LGBPHS
from
.Eigenface
import
Eigenface
bob/bio/face/test/__init__.py
View file @
d77ef348
from
.
import
dummy
bob/bio/face/test/data/dct_blocks.hdf5
0 → 100644
View file @
d77ef348
File added
bob/bio/face/test/data/eigenface_extractor.hdf5
0 → 100644
View file @
d77ef348
File added
bob/bio/face/test/data/eigenface_feature.hdf5
0 → 100644
View file @
d77ef348
File added
bob/bio/face/test/data/graph_regular.hdf5
0 → 100644
View file @
d77ef348
File added
bob/bio/face/test/data/lgbphs_sparse.hdf5
0 → 100644
View file @
d77ef348
File added
bob/bio/face/test/data/lgbphs_with_phase.hdf5
0 → 100644
View file @
d77ef348
File added
bob/bio/face/test/test_extractors.py
0 → 100644
View file @
d77ef348
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# @author: Manuel Guenther <Manuel.Guenther@idiap.ch>
# @date: Thu May 24 10:41:42 CEST 2012
#
# Copyright (C) 2011-2012 Idiap Research Institute, Martigny, Switzerland
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import
bob.bio.base
import
bob.bio.face
import
unittest
import
os
import
numpy
import
math
from
nose.plugins.skip
import
SkipTest
import
bob.io.base.test_utils
from
bob.bio.base.test
import
utils
import
pkg_resources
regenerate_refs
=
False
def
_compare
(
data
,
reference
,
write_function
=
bob
.
bio
.
base
.
save
,
read_function
=
bob
.
bio
.
base
.
load
):
# write reference?
if
regenerate_refs
:
write_function
(
data
,
reference
)
# compare reference
reference
=
read_function
(
reference
)
assert
numpy
.
allclose
(
data
,
reference
,
atol
=
1e-5
)
def
_data
():
return
bob
.
bio
.
base
.
load
(
pkg_resources
.
resource_filename
(
'bob.bio.face.test'
,
'data/cropped.hdf5'
))
def
test_dct_blocks
():
# read input
data
=
_data
()
dct
=
bob
.
bio
.
base
.
load_resource
(
'dct-blocks'
,
'extractor'
)
assert
isinstance
(
dct
,
bob
.
bio
.
face
.
extractor
.
DCTBlocks
)
assert
isinstance
(
dct
,
bob
.
bio
.
base
.
extractor
.
Extractor
)
assert
not
dct
.
requires_training
# generate smaller extractor, using mixed tuple and int input for the block size and overlap
dct
=
bob
.
bio
.
face
.
extractor
.
DCTBlocks
(
8
,
(
0
,
0
),
15
)
# extract features
feature
=
dct
(
data
)
assert
feature
.
ndim
==
2
# feature dimension is one lower than the block size, since blocks are normalized by default
assert
feature
.
shape
==
(
80
,
14
)