LBPHistogram.py 4.88 KB
Newer Older
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
1
from bob.ip.base import LBP, histogram
2
import numpy as np
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
3 4
from sklearn.base import BaseEstimator
from sklearn.base import TransformerMixin
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
5 6


Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
7
class LBPHistogram(TransformerMixin, BaseEstimator):
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
8
    """Calculates a normalized LBP histogram over an image.
9
    These features are implemented based on [CAM12]_.
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
10 11 12

    Parameters
    ----------
13
    lbp_type : str
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
14
        The type of the LBP operator (regular, uniform or riu2)
15 16 17 18 19 20 21
    elbp_type : str
        Which type of LBP codes should be computed; possible values: ('regular',
        'transitional', 'direction-coded'). For the old 'modified' method,
        specify `elbp_type` as 'regular` and `to_average` as True.
    to_average : bool
        Compare the neighbors to the average of the pixels instead of the central pixel?
    radius : float
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
22 23 24 25 26
        The radius of the circle on which the points are taken (for circular
        LBP)
    neighbors : int
        The number of points around the central point on which LBP is
        computed (4, 8, 16)
27
    circular : bool
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
28
        True if circular LBP is needed, False otherwise
29 30 31 32 33 34
    n_hor : int
        Number of blocks horizontally for spatially-enhanced LBP/MCT
        histograms. Default: 1
    n_vert
        Number of blocks vertically for spatially-enhanced LBP/MCT
        histograms. Default: 1
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
35 36 37 38 39 40

    Attributes
    ----------
    dtype : numpy.dtype
        If a ``dtype`` is specified in the contructor, it is assured that the
        resulting features have that dtype.
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
41
    lbp : LBP
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
42 43 44
        The LPB extractor object.
    """

Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
45 46
    def __init__(
        self,
47 48 49 50
        lbp_type="uniform",
        elbp_type="regular",
        to_average=False,
        radius=1,
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
51
        neighbors=8,
52
        circular=False,
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
53 54 55 56 57 58 59
        dtype=None,
        n_hor=1,
        n_vert=1,
        **kwargs,
    ):

        super().__init__(**kwargs)
60 61 62 63 64 65
        self.lbp_type = lbp_type
        self.elbp_type = elbp_type
        self.to_average = to_average
        self.radius = radius
        self.neighbors = neighbors
        self.circular = circular
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
66
        self.dtype = dtype
67 68
        self.n_hor = n_hor
        self.n_vert = n_vert
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
69

70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
        self.fit()

    def fit(self, X=None, y=None):

        self.lbp_ = LBP(
            neighbors=self.neighbors,
            radius=self.radius,
            circular=self.circular,
            to_average=self.to_average,
            uniform=self.lbp_type in ("uniform", "riu2"),
            rotation_invariant=self.lbp_type == "riu2",
            elbp_type=self.elbp_type,
        )
        return self

    def __getstate__(self):
        d = self.__dict__.copy()
        d.pop("lbp_")
        return d

    def __setstate__(self, state):
        self.__dict__.update(state)
        self.fit()

94 95 96
    def comp_block_histogram(self, data):
        """
        Extracts LBP/MCT histograms from a gray-scale image/block.
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112

        Takes data of arbitrary dimensions and linearizes it into a 1D vector;
        Then, calculates the histogram.
        enforcing the data type, if desired.

        Parameters
        ----------
        data : numpy.ndarray
            The preprocessed data to be transformed into one vector.

        Returns
        -------
        1D :py:class:`numpy.ndarray`
            The extracted feature vector, of the desired ``dtype`` (if
            specified)
        """
113
        assert isinstance(data, np.ndarray)
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
114 115

        # allocating the image with lbp codes
116 117 118 119
        lbpimage = np.ndarray(self.lbp_.lbp_shape(data), "uint16")
        self.lbp_(data, lbpimage)  # calculating the lbp image
        hist = histogram(lbpimage, (0, self.lbp_.max_label - 1), self.lbp_.max_label)
        hist = hist / np.sum(hist)  # histogram normalization
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
120 121 122
        if self.dtype is not None:
            hist = hist.astype(self.dtype)
        return hist
123

Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
124
    def transform_one_image(self, data):
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
        """
        Extracts spatially-enhanced LBP/MCT histograms from a gray-scale image.

        Parameters
        ----------
        data : numpy.ndarray
            The preprocessed data to be transformed into one vector.

        Returns
        -------
        1D :py:class:`numpy.ndarray`
            The extracted feature vector, of the desired ``dtype`` (if
            specified)

        """

        # Make sure the data can be split into equal blocks:
        row_max = int(data.shape[0] / self.n_vert) * self.n_vert
        col_max = int(data.shape[1] / self.n_hor) * self.n_hor
        data = data[:row_max, :col_max]

Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
146 147 148 149 150
        blocks = [
            sub_block
            for block in np.hsplit(data, self.n_hor)
            for sub_block in np.vsplit(block, self.n_vert)
        ]
151 152 153 154 155 156 157 158

        hists = [self.comp_block_histogram(block) for block in blocks]

        hist = np.hstack(hists)

        hist = hist / len(blocks)  # histogram normalization

        return hist
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
159 160 161 162 163 164

    def transform(self, images):
        return [self.transform_one_image(img) for img in images]

    def _more_tags(self):
        return {"stateless": True, "requires_fit": False}