Skip to content

Commit

Permalink
Making face recognition system independent of dataset. Major refactor…
Browse files Browse the repository at this point in the history
…ing.

Former-commit-id: ebeed61
  • Loading branch information
ldulcic committed Aug 22, 2019
1 parent 04c21ba commit 65029aa
Show file tree
Hide file tree
Showing 26 changed files with 126 additions and 226 deletions.
2 changes: 1 addition & 1 deletion __init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .arsfutura_face_recognition import face_recogniser_factory
from .face_recognition import face_recogniser_factory

face_recognizer = face_recogniser_factory(include_predictions=True)

Expand Down
1 change: 0 additions & 1 deletion arsfutura_face_recognition/__init__.py

This file was deleted.

10 changes: 0 additions & 10 deletions arsfutura_face_recognition/aligner/__init__.py

This file was deleted.

5 changes: 0 additions & 5 deletions arsfutura_face_recognition/aligner/factory.py

This file was deleted.

15 changes: 0 additions & 15 deletions arsfutura_face_recognition/aligner/mtcnn.py

This file was deleted.

9 changes: 0 additions & 9 deletions arsfutura_face_recognition/dataset.py

This file was deleted.

59 changes: 0 additions & 59 deletions arsfutura_face_recognition/face_recogniser.py

This file was deleted.

10 changes: 0 additions & 10 deletions arsfutura_face_recognition/facenet/__init__.py

This file was deleted.

15 changes: 0 additions & 15 deletions arsfutura_face_recognition/facenet/facenet.py

This file was deleted.

5 changes: 0 additions & 5 deletions arsfutura_face_recognition/facenet/factory.py

This file was deleted.

41 changes: 0 additions & 41 deletions arsfutura_face_recognition/train.py

This file was deleted.

49 changes: 0 additions & 49 deletions bin/exif_orientation_normalize.py

This file was deleted.

7 changes: 4 additions & 3 deletions face_recognition.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python

from arsfutura_face_recognition import face_recogniser_factory
import joblib
import argparse
import cv2
import numpy as np
Expand All @@ -11,6 +11,7 @@ def parse_args(args=None):
parser = argparse.ArgumentParser(
'Script for recognising faces on picture. Output of this script is json with list of people on picture and '
'base64 encoded picture which has bounding boxes of people.')
parser.add_argument('-m', '--model-path', required=True, help='Path to face recogniser model.')
parser.add_argument('--image-path', required=True, help='Path to image file.')
return parser.parse_args(args)

Expand All @@ -25,8 +26,8 @@ def draw_bb_on_img(faces, img):


def _recognise_faces(args):
img = Image.open(args.image_path)
faces = face_recogniser_factory(include_predictions=True)(img)
img = Image.open(args.image_path).convert('RGB')
faces = joblib.load(args.model_path)(img)
img_cv = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
draw_bb_on_img(faces, img_cv)
return faces, img_cv
Expand Down
2 changes: 2 additions & 0 deletions face_recognition/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .face_recogniser import FaceRecogniser
from .face_features_extractor import FaceFeaturesExtractor
27 changes: 27 additions & 0 deletions face_recognition/face_features_extractor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import torch
from facenet_pytorch import MTCNN, InceptionResnetV1
from torchvision import transforms
from . import preprocessing
from facenet_pytorch.models.utils.detect_face import extract_face


class FaceFeaturesExtractor:
def __init__(self):
self.aligner_preprocess = transforms.Compose([preprocessing.ExifOrientationNormalize()])
self.aligner = MTCNN(prewhiten=False, keep_all=True)
self.facenet_preprocess = transforms.Compose([preprocessing.Whitening()])
self.facenet = InceptionResnetV1(pretrained='vggface2').eval()

def extract_features(self, img):
bbs, _ = self.aligner.detect(self.aligner_preprocess(img))
if bbs is None:
# if no face is detected
return None, None

faces = torch.stack([extract_face(img, bb) for bb in bbs])
embeddings = self.facenet(faces).detach().numpy()

return bbs, embeddings

def __call__(self, img):
return self.extract_features(img)
41 changes: 41 additions & 0 deletions face_recognition/face_recogniser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from collections import namedtuple

Prediction = namedtuple('Prediction', 'id name confidence')
Face = namedtuple('Face', 'top_prediction bb all_predictions')
BoundingBox = namedtuple('BoundingBox', 'left top right bottom')


def top_prediction(idx_to_class, probs):
top_label = probs.argmax()
return Prediction(id=top_label, name=idx_to_class[top_label], confidence=probs[top_label])


def to_predictions(idx_to_class, probs):
return [Prediction(id=i, name=idx_to_class[i], confidence=prob) for i, prob in enumerate(probs)]


class FaceRecogniser:
def __init__(self, feature_extractor, classifier, idx_to_class):
self.feature_extractor = feature_extractor
self.classifier = classifier
self.idx_to_class = idx_to_class

def recognise_faces(self, img):
bbs, embeddings = self.feature_extractor(img)
if bbs is None:
# if no faces are detected
return []

predictions = self.classifier.predict_proba(embeddings)

return [
Face(
top_prediction=top_prediction(self.idx_to_class, probs),
bb=BoundingBox(left=bb[0], top=bb[1], right=bb[2], bottom=bb[3]),
all_predictions=to_predictions(self.idx_to_class, probs)
)
for bb, probs in zip(bbs, predictions)
]

def __call__(self, img):
return self.recognise_faces(img)
File renamed without changes.
Binary file removed models/model.pkl
Binary file not shown.
12 changes: 10 additions & 2 deletions real_time_face_detection.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
#!/usr/bin/env python

import argparse
import joblib
import cv2
from PIL import Image
from arsfutura_face_recognition import face_recogniser_factory


def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('-m', '--model-path', required=True, help='Path to face recogniser model.')
return parser.parse_args()


def main():
args = parse_args()
cap = cv2.VideoCapture(0)
face_recogniser = face_recogniser_factory()
face_recogniser = joblib.load(args.model_path)

while True:
# Capture frame-by-frame
Expand Down
Empty file added training/__init__.py
Empty file.
Loading

0 comments on commit 65029aa

Please sign in to comment.