# Path: facerec_py/facerec/util.py
# def asColumnMatrix(X):
#     """
#     Creates a column-matrix from multi-dimensional data items in list X.
#     
#     X [list] List with multi-dimensional data.
#     """
#     if len(X) == 0:
#         return np.array([])
#     total = 1
#     for i in range(0, np.ndim(X[0])):
#         total = total * X[0].shape[i]
#     mat = np.empty([total, 0], dtype=X[0].dtype)
#     for col in X:
#         mat = np.append(mat, col.reshape(-1, 1), axis=1)  # same as hstack
#     return np.asmatrix(mat)
# 
# Path: facerec_py/facerec/operators.py
# class ChainOperator(FeatureOperator):
#     """
#     The ChainOperator chains two feature extraction modules:
#         model2.compute(model1.compute(X,y),y)
#     Where X can be generic input data.
#     
#     Args:
#         model1 [AbstractFeature]
#         model2 [AbstractFeature]
#     """
# 
#     def __init__(self, model1, model2):
#         FeatureOperator.__init__(self, model1, model2)
# 
#     def compute(self, X, y):
#         X = self.model1.compute(X, y)
#         return self.model2.compute(X, y)
# 
#     def extract(self, X):
#         X = self.model1.extract(X)
#         return self.model2.extract(X)
# 
#     def __repr__(self):
#         return "ChainOperator(" + repr(self.model1) + "," + repr(self.model2) + ")"
# 
# class CombineOperator(FeatureOperator):
#     """
#     The CombineOperator combines the output of two feature extraction modules as:
#       (model1.compute(X,y),model2.compute(X,y))
#     , where    the output of each feature is a [1xN] or [Nx1] feature vector.
#         
#         
#     Args:
#         model1 [AbstractFeature]
#         model2 [AbstractFeature]
#         
#     """
# 
#     def __init__(self, model1, model2):
#         FeatureOperator.__init__(self, model1, model2)
# 
#     def compute(self, X, y):
#         A = self.model1.compute(X, y)
#         B = self.model2.compute(X, y)
#         C = []
#         for i in range(0, len(A)):
#             ai = np.asarray(A[i]).reshape(1, -1)
#             bi = np.asarray(B[i]).reshape(1, -1)
#             C.append(np.hstack((ai, bi)))
#         return C
# 
#     def extract(self, X):
#         ai = self.model1.extract(X)
#         bi = self.model2.extract(X)
#         ai = np.asarray(ai).reshape(1, -1)
#         bi = np.asarray(bi).reshape(1, -1)
#         return np.hstack((ai, bi))
# 
#     def __repr__(self):
#         return "CombineOperator(" + repr(self.model1) + "," + repr(self.model2) + ")"


import numpy as np
from facerec_py.facerec.util import asColumnMatrix
from facerec_py.facerec.operators import ChainOperator, CombineOperator
from facerec_py.facerec.lbp import *



class PCA(AbstractFeature):
    def __init__(self, num_components=0):
        AbstractFeature.__init__(self)
        self._num_components = num_components
        self._total_energy = 0
        self._mean = None
        self._eigenvectors = None
        self._eigenvalues = None

    def compute(self, X, y):
        """
        PCA over the entire images set
        dimension reduction for entire images set


        * Prepare the data with each column representing an image.
        * Subtract the mean image from the data.
        * Calculate the eigenvectors and eigenvalues of the covariance matrix.
        * Find the optimal transformation matrix by selecting the principal components (eigenvectors with largest eigenvalues).
        * Project the centered data into the subspace.
        Reference: http://en.wikipedia.org/wiki/Eigenface#Practical_implementation

        :param X: The images, which is a Python list of numpy arrays.
        :param y: The corresponding labels (the unique number of the subject, person) in a Python list.
        :return:
        """
        # build the column matrix

# Path: facerec_py/facerec/util.py
# def asColumnMatrix(X):
#     """
#     Creates a column-matrix from multi-dimensional data items in list X.
#     
#     X [list] List with multi-dimensional data.
#     """
#     if len(X) == 0:
#         return np.array([])
#     total = 1
#     for i in range(0, np.ndim(X[0])):
#         total = total * X[0].shape[i]
#     mat = np.empty([total, 0], dtype=X[0].dtype)
#     for col in X:
#         mat = np.append(mat, col.reshape(-1, 1), axis=1)  # same as hstack
#     return np.asmatrix(mat)
# 
# Path: facerec_py/facerec/operators.py
# class ChainOperator(FeatureOperator):
#     """
#     The ChainOperator chains two feature extraction modules:
#         model2.compute(model1.compute(X,y),y)
#     Where X can be generic input data.
#     
#     Args:
#         model1 [AbstractFeature]
#         model2 [AbstractFeature]
#     """
# 
#     def __init__(self, model1, model2):
#         FeatureOperator.__init__(self, model1, model2)
# 
#     def compute(self, X, y):
#         X = self.model1.compute(X, y)
#         return self.model2.compute(X, y)
# 
#     def extract(self, X):
#         X = self.model1.extract(X)
#         return self.model2.extract(X)
# 
#     def __repr__(self):
#         return "ChainOperator(" + repr(self.model1) + "," + repr(self.model2) + ")"
# 
# class CombineOperator(FeatureOperator):
#     """
#     The CombineOperator combines the output of two feature extraction modules as:
#       (model1.compute(X,y),model2.compute(X,y))
#     , where    the output of each feature is a [1xN] or [Nx1] feature vector.
#         
#         
#     Args:
#         model1 [AbstractFeature]
#         model2 [AbstractFeature]
#         
#     """
# 
#     def __init__(self, model1, model2):
#         FeatureOperator.__init__(self, model1, model2)
# 
#     def compute(self, X, y):
#         A = self.model1.compute(X, y)
#         B = self.model2.compute(X, y)
#         C = []
#         for i in range(0, len(A)):
#             ai = np.asarray(A[i]).reshape(1, -1)
#             bi = np.asarray(B[i]).reshape(1, -1)
#             C.append(np.hstack((ai, bi)))
#         return C
# 
#     def extract(self, X):
#         ai = self.model1.extract(X)
#         bi = self.model2.extract(X)
#         ai = np.asarray(ai).reshape(1, -1)
#         bi = np.asarray(bi).reshape(1, -1)
#         return np.hstack((ai, bi))
# 
#     def __repr__(self):
#         return "CombineOperator(" + repr(self.model1) + "," + repr(self.model2) + ")"


# Path: facerec_py/facerec/feature.py
import numpy as np
from facerec_py.facerec.util import asColumnMatrix
from facerec_py.facerec.operators import ChainOperator, CombineOperator
from facerec_py.facerec.lbp import *




class PCA(AbstractFeature):
    def __init__(self, num_components=0):
        AbstractFeature.__init__(self)
        self._num_components = num_components
        self._total_energy = 0
        self._mean = None
        self._eigenvectors = None
        self._eigenvalues = None

    def compute(self, X, y):
        """
        PCA over the entire images set
        dimension reduction for entire images set


        * Prepare the data with each column representing an image.
        * Subtract the mean image from the data.
        * Calculate the eigenvectors and eigenvalues of the covariance matrix.
        * Find the optimal transformation matrix by selecting the principal components (eigenvectors with largest eigenvalues).
        * Project the centered data into the subspace.
        Reference: http://en.wikipedia.org/wiki/Eigenface#Practical_implementation

        :param X: The images, which is a Python list of numpy arrays.
        :param y: The corresponding labels (the unique number of the subject, person) in a Python list.
        :return:
        """
        # build the column matrix

        XC = asColumnMatrix(X)