#!/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
from sklearn.base import TransformerMixin, BaseEstimator
from sklearn.utils import check_array
from bob.pipelines.sample import SampleBatch
class DCTBlocks(TransformerMixin, BaseEstimator):
"""Extracts *Discrete Cosine Transform* (DCT) features from (overlapping) image blocks.
These features are based on the :py:class:`bob.ip.base.DCTFeatures` class.
The default parametrization is the one that performed best on the BANCA database in [WMM11]_.
Usually, these features are used in combination with the algorithms defined in :ref:`bob.bio.gmm <bob.bio.gmm>`.
However, you can try to use them with other algorithms.
**Parameters:**
block_size : int or (int, int)
The size of the blocks that will be extracted.
This parameter might be either a single integral value, or a pair ``(block_height, block_width)`` of integral values.
block_overlap : int or (int, int)
The overlap of the blocks in vertical and horizontal direction.
This parameter might be either a single integral value, or a pair ``(block_overlap_y, block_overlap_x)`` of integral values.
It needs to be smaller than the ``block_size``.
number_of_dct_coefficients : int
The number of DCT coefficients to use.
The actual number will be one less since the first DCT coefficient (which should be 0, if normalization is used) will be removed.
normalize_blocks : bool
Normalize the values of the blocks to zero mean and unit standard deviation before extracting DCT coefficients.
normalize_dcts : bool
Normalize the values of the DCT components to zero mean and unit standard deviation. Default is ``True``.
"""
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,
):
self.block_size = (block_size,)
self.block_overlap = block_overlap
self.number_of_dct_coefficients = number_of_dct_coefficients
self.normalize_blocks = normalize_blocks
self.normalize_dcts = normalize_dcts
self.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.number_of_dct_coefficients = number_of_dct_coefficients
self.block_size = block_size
self.block_overlap = block_overlap
self.normalize_blocks = normalize_blocks
self.normalize_dcts = normalize_dcts
self._init_non_pickables()
def _init_non_pickables(self):
self.dct_features = bob.ip.base.DCTFeatures(
self.number_of_dct_coefficients,
self.block_size,
self.block_overlap,
self.normalize_blocks,
self.normalize_dcts,
)
def _more_tags(self):
return {"stateless": True, "requires_fit": False}
[docs] def fit(self, X, y=None):
return self
def __getstate__(self):
d = self.__dict__.copy()
d.pop("dct_features")
return d
def __setstate__(self, d):
self.__dict__ = d
self._init_non_pickables()