Esempio n. 1
0
    def __init__(self,
                 config,
                 pca_components=25,
                 n_components=2,
                 metric='euclidean',
                 face_detect=True,
                 transform=None,
                 img_size=(200, 180)):
        # type: (Config, int, int, str, bool, transforms.Compose, Tuple[int, int]) -> None
        self.pca_components = pca_components
        self.n_components = n_components
        self.metric = metric
        self.pca_lda = None
        self.label2name = None
        self.transform = transform

        if face_detect:
            self.face_detector = FaceDetector(
                prototxt='face_detect/checkpoints/deploy.prototxt.txt',
                checkpoint_path=
                'face_detect/checkpoints/res10_300x300_ssd_iter_140000.caffemodel',
                img_size=img_size)
        else:
            self.face_detector = None
        self.result_writer = ResultWriter(config, 'fisher')
Esempio n. 2
0
    def __init__(self, config, C=100.0, random_state=42, max_iter=6000, num_points=24, radius=8, face_detect=False,
                 transform=None, img_size=(200, 180)):
        # type: (Config, float, int, int, int, int, bool, transforms.Compose, Tuple[int, int])->None
        self.clf = LinearSVC(C=C, random_state=random_state, max_iter=max_iter)
        self.lbp = LocalBinaryPatterns(numPoints=num_points, radius=radius)
        self.transform = transform
        self.img_size = img_size
        if face_detect:
            self.face_detector = FaceDetector(
                prototxt='face_detect/checkpoints/deploy.prototxt.txt',
                checkpoint_path='face_detect/checkpoints/res10_300x300_ssd_iter_140000.caffemodel',
                img_size=img_size
            )
        else:
            self.face_detector = None

        self.result_writer = ResultWriter(config=config, method='lbph')
    def __init__(self,
                 config,
                 transform=None,
                 distance_type='norm2',
                 face_detect=True,
                 img_size=(200, 180)):
        # type: (Config, transforms.Compose, str, bool, Tuple[int, int]) -> None
        assert distance_type == 'norm2' or distance_type == 'mahalanobis', f'invalid distance type: {distance_type}'
        self.distance_type = distance_type
        self.avg_face = None
        self.eigen_faces = None
        self.transform = transform
        self.classes_representation = []

        if face_detect:
            self.face_detector = FaceDetector(
                prototxt='face_detect/checkpoints/deploy.prototxt.txt',
                checkpoint_path=
                'face_detect/checkpoints/res10_300x300_ssd_iter_140000.caffemodel',
                img_size=img_size)
        else:
            self.face_detector = None

        self.result_writer = ResultWriter(config, 'eigen')
 def __init__(self, config: Config):
     self.clf = svm.SVC(gamma='scale')
     self.result_writer = ResultWriter(config=config, method='face_rec')
class FaceRecognizer:
    def __init__(self, config: Config):
        self.clf = svm.SVC(gamma='scale')
        self.result_writer = ResultWriter(config=config, method='face_rec')

    def train(self, train_csv_path: str):
        assert os.path.exists(train_csv_path), f'invalid csv file path: {train_csv_path}'

        encodings = []
        names = []

        with open(train_csv_path, 'r') as csv_file:
            csv_reader = csv.reader(csv_file)
            print('get image encoding...')
            for img_file_path, person in tqdm(csv_reader):
                try:
                    face = fr.load_image_file(img_file_path)
                    face_enc = fr.face_encodings(face)[0]
                except:
                    continue

                encodings.append(face_enc)
                names.append(person)
        print('start to fit...')
        self.clf.fit(encodings, names)

    def save_model(self, save_path: str):
        os.makedirs(os.path.dirname(save_path), exist_ok=True)
        with open(save_path, 'wb') as f:
            pickle.dump(self.clf, f)

    def load_model(self, pkl_path: str):
        with open(pkl_path, 'rb') as f:
            self.clf = pickle.load(f)

    def predict_img(self, img_path: str) -> str:
        assert os.path.exists(img_path), f'invalid image path: {img_path}'
        img = fr.load_image_file(img_path)
        img_enc = fr.face_encodings(img)[0]
        name = self.clf.predict([img_enc])
        return name

    def predict(self, csv_file_path: str, data_type: str) -> float:
        assert os.path.exists(csv_file_path), f'invalid csv file path: {csv_file_path}'
        print('get image encoding...')
        right_num = 0
        encoding, names, img_file_paths = [], [], []
        with open(csv_file_path, 'r') as csv_file:
            csv_reader = csv.reader(csv_file)
            for img_file_path, person in tqdm(csv_reader):
                try:
                    face = fr.load_image_file(img_file_path)
                    face_enc = fr.face_encodings(face)[0]
                except:
                    continue
                encoding.append(face_enc)
                img_file_paths.append(img_file_path)
                names.append(person)
        pred_names = self.clf.predict(encoding)
        for i in range(len(pred_names)):
            if pred_names[i] == names[i]:
                right_num += 1
            else:
                print(f'pred: {pred_names[i]}, gt: {names[i]}')

        acc = right_num / len(pred_names)
        self.result_writer.write(image_paths=img_file_paths,
                                 pred_names=pred_names,
                                 names=names,
                                 accuracy=acc,
                                 fname=data_type + '.csv')
        return acc
class EigenFaceRecognizer:
    def __init__(self,
                 config,
                 transform=None,
                 distance_type='norm2',
                 face_detect=True,
                 img_size=(200, 180)):
        # type: (Config, transforms.Compose, str, bool, Tuple[int, int]) -> None
        assert distance_type == 'norm2' or distance_type == 'mahalanobis', f'invalid distance type: {distance_type}'
        self.distance_type = distance_type
        self.avg_face = None
        self.eigen_faces = None
        self.transform = transform
        self.classes_representation = []

        if face_detect:
            self.face_detector = FaceDetector(
                prototxt='face_detect/checkpoints/deploy.prototxt.txt',
                checkpoint_path=
                'face_detect/checkpoints/res10_300x300_ssd_iter_140000.caffemodel',
                img_size=img_size)
        else:
            self.face_detector = None

        self.result_writer = ResultWriter(config, 'eigen')

    def get_representation(self, img_path: str):
        if self.avg_face is None or self.eigen_faces is None:
            raise ValueError('Model has not been trained')
        assert os.path.exists(img_path), f'invalid image path: {img_path}'
        image = Image.open(img_path)
        image = image.convert('RGB')
        if self.face_detector is not None:
            x_begin, x_end, y_begin, y_end = self.face_detector.detect(
                img_path)
            image = image.crop((x_begin, y_begin, x_end, y_end))
        if self.transform is not None:
            image = self.transform(image)
        image = np.array(image, dtype=np.float32)

        image_vector = image.flatten().reshape((-1, 1))
        image_vector -= self.avg_face.reshape((-1, 1))

        return np.dot(self.eigen_faces, image_vector)

    def train(self, train_csv_path: str):
        with open(train_csv_path, 'r') as csv_file:
            csv_reader = csv.reader(csv_file)
            image_paths, names = [], []
            for img_path, name in csv_reader:
                image_paths.append(img_path)
                names.append(name)

            eigen_faces, self.avg_face = self.get_eigen_face(
                image_paths, transform=self.transform)
            self.avg_face = self.avg_face.flatten()
            self.eigen_faces = np.zeros(
                (len(eigen_faces), len(eigen_faces[0])))
            for i in range(len(eigen_faces)):
                self.eigen_faces[i, :] = eigen_faces[i].T
        with open(train_csv_path, 'r') as csv_file:
            csv_reader = csv.reader(csv_file)
            cur_rep, cur_num, cur_name = None, 0, None
            for img_path, name in tqdm(csv_reader):
                try:
                    rep = self.get_representation(img_path)
                except:
                    continue
                if cur_name is None:
                    cur_name = name
                elif cur_name != name:
                    self.classes_representation.append(
                        (cur_name, cur_rep / cur_num))
                    cur_name = name
                    cur_num = 0
                    cur_rep = None

                if cur_rep is None:
                    cur_rep = rep
                else:
                    cur_rep += rep
                cur_num += 1

    def predict(self, csv_path: str, data_type: str) -> float:
        if self.avg_face is None or self.eigen_faces is None:
            raise ValueError('Model has not been trained')
        with open(csv_path, 'r') as csv_file:
            csv_reader = csv.reader(csv_file)
            img_representations, names, img_file_paths = [], [], []
            for img_path, name in csv_reader:
                try:
                    rep = self.get_representation(img_path)
                except:
                    continue
                img_representations.append(rep.flatten())
                names.append(name)
                img_file_paths.append(img_path)
        pred_names = []
        for rep in img_representations:
            min_dist = None
            pred_name = None
            for name, class_rep in self.classes_representation:
                # X = np.vstack([rep, class_rep.flatten()])
                # d = pdist(X, 'mahalanobis')
                d = np.sum((class_rep.flatten() - rep)**2)
                if min_dist is None or min_dist > d:
                    min_dist = d
                    pred_name = name
            pred_names.append(pred_name)

        right_num = 0
        for i in range(len(names)):
            if names[i] != pred_names[i]:
                pass
                # print(f'pred: {pred_names[i]}, gt: {names[i]}')
            else:
                right_num += 1
        acc = right_num / len(names)

        self.result_writer.write(image_paths=img_file_paths,
                                 pred_names=pred_names,
                                 names=names,
                                 accuracy=acc,
                                 fname=data_type + '.csv')
        return acc

    @staticmethod
    def _createDataMatrix(images):
        print("Creating data matrix", end=" ... ")
        ''' 
        Allocate space for all images in one data matrix. 
            The size of the data matrix is
            ( w  * h  * 3,  numImages )
    
            where,
            w = width of an image in the dataset.
            h = height of an image in the dataset.
            3 is for the 3 color channels.
        '''

        numImages = len(images)
        sz = images[0].shape
        data = np.zeros((numImages, sz[0] * sz[1] * sz[2]), dtype=np.float32)
        for i in range(0, numImages):
            image = images[i].flatten()
            data[i, :] = image

        print("DONE")
        return data.T

    @staticmethod
    def _PCA(matrix: np.ndarray, PCA_size=10):
        avg_face = np.average(matrix, axis=1)
        A = matrix.T - avg_face
        A = A.T
        eigen_values, eigen_vectors = np.linalg.eigh(np.dot(A.T, A))
        sorted_indices = np.argsort(eigen_values)
        top_indices = sorted_indices[:-PCA_size - 1:-1]
        eigen_vectors = eigen_vectors[top_indices]

        ret_eigen_vectors = [
            cv2.normalize(src=np.dot(A, eigen_vector).T,
                          dst=None,
                          norm_type=cv2.NORM_L2)
            for eigen_vector in eigen_vectors
        ]
        return avg_face, ret_eigen_vectors

    @staticmethod
    def get_eigen_face(image_paths: List[str],
                       eigen_size: int = 100,
                       transform=None):
        """
        Generate eigen face for image
        :param eigen_size: size for eigen vector after PCA
        :param image_paths: the list of  paths of images to process
        :param transform: transformation on image. Default is None.
        :return: eigen faces and average face
        """
        images = []
        print('Read images...')
        for image_path in tqdm(image_paths):
            assert os.path.exists(
                image_path), f'invalid image path: {image_path}'
            try:
                img = Image.open(image_path)
                img = img.convert('RGB')
            except:
                continue
            if transform is not None:
                img = transform(img)
            img = np.array(img)
            images.append(img)

        shape = images[0].shape

        img_data = EigenFaceRecognizer._createDataMatrix(images)

        print('Calculate PCA', end=' ... ')
        mean, eigen_vectors = EigenFaceRecognizer._PCA(img_data, eigen_size)
        print('DONE')

        avg_face = mean.reshape(shape)

        print('Get eigen faces for images', end=' ... ')
        eigen_faces = []
        for eigen_vector in eigen_vectors:
            # eigen_face = eigen_vector.reshape(shape)
            eigen_faces.append(eigen_vector)
        print('DONE')

        return eigen_faces, avg_face

    def save_model(self, save_path: str):
        os.makedirs(os.path.dirname(save_path), exist_ok=True)
        with open(save_path, 'wb') as f:
            pickle.dump(
                {
                    'classes_representation': self.classes_representation,
                    'avg_face': self.avg_face,
                    'eigen_faces': self.eigen_faces
                }, f)

    def load_model(self, pkl_path: str):
        with open(pkl_path, 'rb') as f:
            checkpoint = pickle.load(f)
            self.classes_representation = checkpoint['classes_representation']
            self.avg_face = checkpoint['avg_face']
            self.eigen_faces = checkpoint['eigen_faces']
Esempio n. 7
0
class PCALDAClassifier(Classifier):
    def __init__(self,
                 config,
                 pca_components=25,
                 n_components=2,
                 metric='euclidean',
                 face_detect=True,
                 transform=None,
                 img_size=(200, 180)):
        # type: (Config, int, int, str, bool, transforms.Compose, Tuple[int, int]) -> None
        self.pca_components = pca_components
        self.n_components = n_components
        self.metric = metric
        self.pca_lda = None
        self.label2name = None
        self.transform = transform

        if face_detect:
            self.face_detector = FaceDetector(
                prototxt='face_detect/checkpoints/deploy.prototxt.txt',
                checkpoint_path=
                'face_detect/checkpoints/res10_300x300_ssd_iter_140000.caffemodel',
                img_size=img_size)
        else:
            self.face_detector = None
        self.result_writer = ResultWriter(config, 'fisher')

    def _get_image_data_from_csv(self, csv_path):
        # type: (str) -> Tuple[np.ndarray, np.ndarray, Dict[int:str], List[str]]
        assert os.path.exists(csv_path), f'invalid path: {csv_path}'

        csv_file = open(csv_path, 'r')
        csv_reader = csv.reader(csv_file)

        label2name, name2label = {}, {}
        images, labels, imgs_paths = [], [], []

        label = 0
        print('Reading images ... ', end='')
        for image_path, name in csv_reader:
            try:
                img = Image.open(image_path).convert('RGB')
                if self.face_detector is not None:
                    x_begin, x_end, y_begin, y_end = self.face_detector.detect(
                        image_path, False)
                    img = img.crop((x_begin, y_begin, x_end, y_end))
                if self.transform is not None:
                    img = self.transform(img)
                img = np.array(img)
            except:
                continue
            imgs_paths.append(image_path)
            images.append(np.ravel(img))
            if name not in name2label:
                label2name[label] = name
                name2label[name] = label
                label += 1
            labels.append(name2label[name])

        csv_file.close()
        print('DONE')
        return np.vstack(images), np.hstack(labels), label2name, imgs_paths

    def train(self, X, y):
        # print(X.shape)
        print('start training ... ', end='')
        self.pca_lda = PCALDA(
            pca_components=self.pca_components,
            n_components=self.n_components,
        ).fit(X, y)
        print('DONE')
        return self

    def train_csv_file(self, csv_path: str):
        images, labels, label2name, _ = self._get_image_data_from_csv(
            csv_path=csv_path)
        self.train(images, labels)

    def predict(self, X, return_distances=False):
        assert self.pca_lda is not None, \
            'You must fit %s first' % self.__class__.__name__

        # Find the nearest class mean to each new sample
        class_means = self.pca_lda.lda.class_means

        projected = self.pca_lda.project(np.atleast_2d(X))

        distances = distance.cdist(projected, class_means, metric=self.metric)
        min_indices = np.argmin(distances, axis=1)

        if return_distances:
            return min_indices, distances
        return min_indices

    def predict_proba(self, X):
        indices, distances = self.predict(X, return_distances=True)
        # Perform softmax on negative distances because a good distance is a
        # low distance, and softmax does the inverse
        probs = softmax(-distances)
        return indices, probs

    def predict_csv_file(self, csv_path, data_type):
        # type: (str, str) -> float
        """
        :return: accuracy
        """
        assert os.path.exists(csv_path), f'invalid csv path: {csv_path}'
        assert self.pca_lda is not None, \
            'You must fit %s first' % self.__class__.__name__

        images, labels, label2name, img_paths = self._get_image_data_from_csv(
            csv_path)
        pred_indices = self.predict(images)
        # print(f'pred_indices len: {len(pred_indices)}, names len: {len(names)}')
        right_num = 0
        assert len(pred_indices) == len(labels)
        pred_names = [
            label2name[pred_indices[i]] for i in range(len(pred_indices))
        ]
        names = [label2name[labels[i]] for i in range(len(labels))]
        for i in range(len(pred_names)):
            if pred_names[i] == names[i]:
                right_num += 1
        acc = right_num / len(pred_indices)
        self.result_writer.write(image_paths=img_paths,
                                 pred_names=pred_names,
                                 names=names,
                                 accuracy=acc,
                                 fname=data_type + '.csv')
        return acc

    def save_model(self, fname):
        dir_name = os.path.dirname(fname)
        os.makedirs(dir_name, exist_ok=True)
        face_detector = self.face_detector
        self.face_detector = None
        with open(fname, 'wb') as f:
            pickle.dump(self, f)
        self.face_detector = face_detector

    def load_model(self, fname):
        assert os.path.exists(fname), f'invalid file name: {fname}'
        with open(fname, 'rb') as f:
            checkpoint = pickle.load(f)
            self.pca_components = checkpoint.pca_components
            self.n_components = checkpoint.n_components
            self.metric = checkpoint.metric
            self.pca_lda = checkpoint.pca_lda
            self.label2name = checkpoint.label2name
            self.transform = checkpoint.transform
Esempio n. 8
0
class LBPHRecognizer:
    def __init__(self, config, C=100.0, random_state=42, max_iter=6000, num_points=24, radius=8, face_detect=False,
                 transform=None, img_size=(200, 180)):
        # type: (Config, float, int, int, int, int, bool, transforms.Compose, Tuple[int, int])->None
        self.clf = LinearSVC(C=C, random_state=random_state, max_iter=max_iter)
        self.lbp = LocalBinaryPatterns(numPoints=num_points, radius=radius)
        self.transform = transform
        self.img_size = img_size
        if face_detect:
            self.face_detector = FaceDetector(
                prototxt='face_detect/checkpoints/deploy.prototxt.txt',
                checkpoint_path='face_detect/checkpoints/res10_300x300_ssd_iter_140000.caffemodel',
                img_size=img_size
            )
        else:
            self.face_detector = None

        self.result_writer = ResultWriter(config=config, method='lbph')

    def _get_data_names_for_csv(self, csv_path):
        assert os.path.exists(csv_path), f'invalid csv path: {csv_path}'
        data, names, image_paths = [], [], []
        with open(csv_path, 'r') as csv_file:
            csv_reader = csv.reader(csv_file)
            for image_path, name in csv_reader:
                try:
                    img = Image.open(image_path).convert('L')
                    if self.face_detector is not None:
                        x_begin, x_end, y_begin, y_end = self.face_detector.detect(image_path, False)
                        img = img.crop((x_begin, y_begin, x_end, y_end))
                    if self.transform is not None:
                        img = self.transform(img)
                        img = self.transform(img)
                    # img.show()
                    img = np.array(img)
                except:
                    continue
                image_paths.append(image_path)
                hist = self.lbp.describe(img)
                data.append(hist)
                names.append(name)
        return data, names, image_paths

    def train(self, csv_path):
        # type:(str)->None
        data, names, _ = self._get_data_names_for_csv(csv_path)
        self.clf.fit(data, names)

    def predict(self, csv_path, data_type):
        # type: (str, str) -> float
        """
        :return: accuracy
        """
        data, names, image_paths = self._get_data_names_for_csv(csv_path)
        pred_names = self.clf.predict(data)
        right_num = 0
        assert len(names) == len(pred_names)
        for i in range(len(pred_names)):
            if names[i] == pred_names[i]:
                right_num += 1
        acc = right_num / len(pred_names)
        self.result_writer.write(image_paths, pred_names, names, acc, data_type + '.csv')
        return acc

    def save_model(self, file_name: str):
        os.makedirs(os.path.dirname(file_name), exist_ok=True)
        face_detector = self.face_detector
        self.face_detector = None
        with open(file_name, 'wb') as f:
            pickle.dump(self, f)
        self.face_detector = face_detector

    def load_model(self, file_name: str):
        assert os.path.exists(file_name), f'invalid file name: {file_name}'
        with open(file_name, 'rb') as f:
            checkpoint = pickle.load(f)
        self.clf = checkpoint.clf
        self.lbp = checkpoint.lbp
        self.transform = checkpoint.transform