Switching to VGG-Face and mtcnn

Signed-off-by: James Ketrenos <james_git@ketrenos.com>
This commit is contained in:
James Ketr 2023-01-06 13:09:11 -08:00
parent 4263d18fec
commit 6847a35ca5
2 changed files with 94 additions and 31 deletions

View File

@ -1,15 +1,34 @@
import sys
import zlib
import json
import os
import piexif
import sqlite3
from sqlite3 import Error
from PIL import Image
from PIL import Image, ImageOps
from deepface import DeepFace
from deepface.detectors import FaceDetector
from retinaface import RetinaFace
import numpy as np
import cv2
import uu
from io import BytesIO
def zlib_uuencode(databytes, name='<data>'):
''' Compress databytes with zlib & uuencode the result '''
inbuff = BytesIO(zlib.compress(databytes, 9))
outbuff = BytesIO()
uu.encode(inbuff, outbuff, name=name)
return outbuff.getvalue()
def zlib_uudecode(databytes):
''' uudecode databytes and decompress the result with zlib '''
inbuff = BytesIO(databytes)
outbuff = BytesIO()
uu.decode(inbuff, outbuff)
return zlib.decompress(outbuff.getvalue())
class NpEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, np.integer):
@ -21,7 +40,10 @@ class NpEncoder(json.JSONEncoder):
models = ["VGG-Face", "Facenet", "Facenet512", "OpenFace", "DeepFace", "DeepID", "ArcFace", "Dlib", "SFace"]
model = DeepFace.build_model('ArcFace')
model_name = 'VGG-Face' # 'ArcFace'
detector_backend = 'mtcnn' # 'retinaface'
model = DeepFace.build_model(model_name)
face_detector = FaceDetector.build_model(detector_backend)
input_shape = DeepFace.functions.find_input_shape(model)
@ -52,27 +74,46 @@ def alignment_procedure(img, left_eye, right_eye):
return img
def extract_faces(img, threshold=0.75, model = None, allow_upscaling = True):
faces = RetinaFace.detect_faces(
img_path = img,
threshold = threshold,
model = model,
allow_upscaling = allow_upscaling)
def extract_faces(img, threshold=0.75, allow_upscaling = True):
if detector_backend == 'retinaface':
faces = RetinaFace.detect_faces(
img_path = img,
threshold = threshold,
model = model,
allow_upscaling = allow_upscaling)
elif detector_backend == 'mtcnn':
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # mtcnn expects RGB
res = face_detector.detect_faces(img_rgb)
faces = {}
if type(res) == list:
for i, face in enumerate(res):
faces[f'face_{i+1}'] = { # standardize properties
'facial_area': [
face['box'][1], face['box'][1] + face['box'][3],
face['box'][0], face['box'][0] + face['box'][2],
],
'landmarks': {
'left_eye': list(face['keypoints']['left_eye']),
'right_eye': list(face['keypoints']['right_eye']),
},
'score': face['confidence'],
}
print(face, faces[f'face_{i+1}'])
# Re-implementation of 'extract_faces' with the addition of keeping a
# copy of the face image for caching on disk
if type(faces) == dict:
k=1
for key in faces:
print(f'Processing face {k}/{len(faces)}')
k+=1
for k, key in enumerate(faces):
print(f'Processing face {k+1}/{len(faces)}')
identity = faces[key]
facial_area = identity["facial_area"]
landmarks = identity["landmarks"]
left_eye = landmarks["left_eye"]
right_eye = landmarks["right_eye"]
if False: # Draw the face rectangle and eyes
markup = True
# markup = False
if markup == True: # Draw the face rectangle and eyes
cv2.rectangle(img,
(int(facial_area[0]), int(facial_area[1])),
(int(facial_area[2]), int(facial_area[3])),
@ -116,9 +157,9 @@ def extract_faces(img, threshold=0.75, model = None, allow_upscaling = True):
identity['vector'] = DeepFace.represent(
img_path = resized,
model_name = 'ArcFace',
model = model, # pre-built
detector_backend = 'retinaface',
model_name = model_name,
model = model, # pre-built
detector_backend = detector_backend,
enforce_detection = False)
identity["face"] = {
@ -217,25 +258,23 @@ with conn:
''')
rows = res.fetchall()
count = len(rows)
i=1
for row in rows:
for i, row in enumerate(rows):
photoId, photoFaces, albumPath, photoFilename = row
img_path = f'{base}{albumPath}{photoFilename}'
print(f'Processing {i}/{count}: {img_path}')
i+=1
print(f'Processing {i+1}/{count}: {img_path}')
img = Image.open(img_path)
img = ImageOps.exif_transpose(img) # auto-rotate if needed
img = img.convert()
img = np.asarray(img)
faces = extract_faces(img)
if faces is None:
print(f'Image no faces: {img_path}')
update_face_count(conn, photoId, 0)
continue
j=1
for key in faces:
for j, key in enumerate(faces):
face = faces[key]
image = face['image']
print(f'Writing face {j}/{len(faces)}')
j+=1
print(f'Writing face {j+1}/{len(faces)}')
#face['analysis'] = DeepFace.analyze(img_path = img, actions = ['age', 'gender', 'race', 'emotion'], enforce_detection = False)
#face['analysis'] = DeepFace.analyze(img, actions = ['emotion'])
@ -245,8 +284,7 @@ with conn:
face['version'] = 1 # version 1 doesn't add much...
data = {k: face[k] for k in set(list(face.keys())) - set(['image', 'facial_area', 'landmarks'])}
json_str = json.dumps(data, ensure_ascii=False, indent=2, cls=NpEncoder)
json_str = json.dumps(data, ensure_ascii=False, cls=NpEncoder)
faceDescriptorId = create_face_descriptor(conn, face)
faceId = create_face(conn, {
@ -260,7 +298,7 @@ with conn:
'descriptorId': faceDescriptorId,
})
path = f'faces/{faceId % 10}'
path = f'faces/{"{:02d}".format(faceId % 10)}'
try:
os.mkdir(path)
except FileExistsError:
@ -269,13 +307,13 @@ with conn:
with open(f'{path}/{faceId}.json', 'w', encoding = 'utf-8') as f:
f.write(json_str)
compressed_str = zlib_uuencode(json_str.encode())
# Encode this data into the JPG as Exif
exif_ifd = {piexif.ExifIFD.UserComment: json_str.encode()}
exif_ifd = {piexif.ExifIFD.UserComment: compressed_str}
exif_dict = {"0th": {}, "Exif": exif_ifd, "1st": {},
"thumbnail": None, "GPS": {}}
image.save(f'{path}/{faceId}.jpg', exif = piexif.dump(exif_dict))
#df = DeepFace.find(img, db_path = '/db')
#print(df.head())
exit(1)
update_face_count(conn, photoId, len(faces))

25
server/headers.py Normal file
View File

@ -0,0 +1,25 @@
import sys
import zlib
import json
import piexif
from PIL import Image
import uu
from io import BytesIO
def zlib_uudecode(databytes):
''' uudecode databytes and decompress the result with zlib '''
inbuff = BytesIO(databytes)
outbuff = BytesIO()
uu.decode(inbuff, outbuff)
return zlib.decompress(outbuff.getvalue())
faceId = int(sys.argv[1])
path = f'faces/{"{:02d}".format(faceId % 10)}'
img = Image.open(f'{path}/{faceId}.jpg')
exif_dict = piexif.load(img.info["exif"])
compressed_str = exif_dict["Exif"][piexif.ExifIFD.UserComment]
str = zlib_uudecode(compressed_str)
json = json.loads(str)
print(json)