Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
m-lyon committed Jun 3, 2020
1 parent 6415a08 commit 0c51d44
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 20 deletions.
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include face_compare/weights/facenet_weights.h5
44 changes: 44 additions & 0 deletions bin/compare_faces.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env python3
import cv2
import argparse
import numpy as np
from pathlib import Path

from face_compare.images import get_face
from face_compare.model import facenet_model, img_to_encoding

def run(image_one, image_two, save_dest=None):
# Load images
face_one = get_face(cv2.imread(str(image_one), 1))
face_two = get_face(cv2.imread(str(image_two), 1))

# Optionally save cropped images
if save_dest is not None:
print(f'Saving cropped images in {save_dest}.')
cv2.imwrite(str(save_dest.joinpath('face_one.png')), face_one)
cv2.imwrite(str(save_dest.joinpath('face_two.png')), face_two)

# load model
model = facenet_model(input_shape=(3, 96, 96))

# Calculate embedding vectors
embedding_one = img_to_encoding(face_one, model)
embedding_two = img_to_encoding(face_two, model)

dist = np.linalg.norm(embedding_one - embedding_two)
print(f'Distance between two images is {dist}')
if dist > 0.7:
print('These images are of two different people!')
else:
print('These images are of the same person!')


if __name__ == '__main__':
ap = argparse.ArgumentParser(description='Face Comparison Tool')

ap.add_argument('--image-one', dest='image_one', type=Path, required=True, help='Input Image One')
ap.add_argument('--image-two', dest='image_two', type=Path, required=True, help='Input Image Two')
ap.add_argument('-s', '--save-to', dest='save_dest', type=Path, help='Optionally save the cropped faces on disk. Input directory to save them to')
args = ap.parse_args()

run(args.image_one, args.image_two, args.save_dest)
File renamed without changes.
20 changes: 20 additions & 0 deletions face_compare/images.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import cv2

def get_face(img):
'''Crops image to only include face plus a border'''
height, width, channels = img.shape
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
face_box = face_cascade.detectMultiScale(img)
# Get dimensions of bounding box
x, y, w, h = tuple(map(tuple, face_box))[0]
# Calculate padding as segmentation is too tight.
pad_w = int(w/2.5)
pad_h = int(h/2.5)
# Get co-ordinates of crop
x1 = max(0, x-pad_w)
y1 = max(0, y-pad_h)
x2 = min(width, x+w+pad_w)
y2 = min(height, y+h+pad_h)
# Crop image
cropped = img[y1:y2,x1:x2]
return cropped
51 changes: 31 additions & 20 deletions face-compare/model.py → face_compare/model.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
import cv2
import numpy as np
import tensorflow as tf
import keras.backend.tensorflow_backend as tfback

from pathlib import Path

from keras.layers import Conv2D, ZeroPadding2D, Activation, Input, concatenate
from keras.models import Model
from keras.layers.normalization import BatchNormalization
from keras.layers.pooling import MaxPooling2D, AveragePooling2D
from keras.layers.core import Lambda, Flatten, Dense

# from weights import load_weights

import cv2


def _get_available_gpus():
"""Get a list of available gpu devices (formatted as strings).
# Returns
A list of available GPU devices.
"""
#global _LOCAL_DEVICES
if tfback._LOCAL_DEVICES is None:
devices = tf.config.list_logical_devices()
tfback._LOCAL_DEVICES = [x.name for x in devices]
return [x for x in tfback._LOCAL_DEVICES if 'device:gpu' in x.lower()]


tfback._get_available_gpus = _get_available_gpus
tfback._get_available_gpus()
tfback.set_image_data_format('channels_first')


def conv2d_bn(x, layer_name, filters, kernel_size=(1, 1), strides=(1, 1), i='', epsilon=0.00001):
'''2D Convolutional Block with Batch normalization and ReLU activation.
Expand Down Expand Up @@ -248,26 +250,35 @@ def facenet_model(input_shape):

# Create model instance
model = Model(inputs = X_input, outputs = X, name='FaceNetModel')

weight_fpath = Path(__file__).parent.joinpath('weights', 'facenet_weights.h5')
model.load_weights(weight_fpath)

return model

if __name__ == '__main__':
img = cv2.imread('/Users/matt/Dev/git/facenet-test/facenet-face-recognition/images/mutty.jpg')
image = cv2.resize(img, (96, 96))
img = image[...,::-1]
img = np.around(np.transpose(img, (2,0,1))/255.0, decimals=12)
x_train = np.array([img])
def img_to_encoding(image, model):
# Resize for model
resized = cv2.resize(image, (96, 96))
# Swap channel dimensions
input_img = resized[...,::-1]
# Switch to channels first and round to specific precision.
input_img = np.around(np.transpose(input_img, (2,0,1))/255.0, decimals=12)
x_train = np.array([input_img])
embedding = model.predict_on_batch(x_train)
return embedding

tfback._get_available_gpus = _get_available_gpus
tfback._get_available_gpus()
tfback.set_image_data_format('channels_first')
# if __name__ == '__main__':
# image_path = '/Users/matt/Dev/git/face-comparison/face-compare/data/example.jpg'
# img = cv2.imread(image_path, 1)

model = facenet_model(input_shape=(3, 96, 96))
# cropped = get_face(img)

weight_fpath = '/Users/matt/Dev/git/face-comparison/face-compare/facenet_weights.h5'
model.load_weights(weight_fpath)
# model = facenet_model(input_shape=(3, 96, 96))

embedding = model.predict_on_batch(x_train)
print(embedding)
# weight_fpath = '/Users/matt/Dev/git/face-comparison/face-compare/facenet_weights.h5'
# model.load_weights(weight_fpath)

# embedding_one = img_to_encoding(cropped, model)
# print(embedding)


Empty file.
File renamed without changes.
File renamed without changes.
25 changes: 25 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1 +1,26 @@
#!/usr/bin/env python3
'''Use this to install module'''
from setuptools import setup, find_packages

setup(
name='face_compare',
version='1.0.0',
description='Compare if two faces are from the same person.',
author='Matt Lyon',
author_email='[email protected]',
python_requires='>=3.7',
license='MIT License',
packages=find_packages(),
install_requires=[
'tensorflow',
'keras',
'opencv-python'
],
classifiers=[
'Programming Language :: Python',
'Operating System :: Unix',
'Operating System :: MacOS',
],
scripts=['bin/compare_faces.py'],
include_package_data=True
)

0 comments on commit 0c51d44

Please sign in to comment.