Skip to content

Commit

Permalink
Merge pull request #917 from fseasy/master
Browse files Browse the repository at this point in the history
fix(represent): the `represent` is broken when user-given image. Fix it and support `pathlib.Path` for img_path
  • Loading branch information
serengil authored Dec 14, 2023
2 parents 44f191c + 7b1451a commit 64e6ace
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 14 deletions.
7 changes: 6 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,10 @@
"python.formatting.provider": "black",
"python.formatting.blackArgs": ["--line-length=100"],
"editor.fontWeight": "normal",
"python.analysis.extraPaths": ["./deepface"]
"python.analysis.extraPaths": [
"./deepface"
],
"black-formatter.args": [
"--line-length=100"
]
}
41 changes: 28 additions & 13 deletions deepface/DeepFace.py
Original file line number Diff line number Diff line change
Expand Up @@ -674,16 +674,31 @@ def represent(
This might be convenient for low resolution images.
detector_backend (string): set face detector backend to opencv, retinaface, mtcnn, ssd,
dlib, mediapipe or yolov8.
dlib, mediapipe or yolov8. A special value `skip` could be used to skip face-detection
and only encode the given image.
align (boolean): alignment according to the eye positions.
normalization (string): normalize the input image before feeding to model
Returns:
Represent function returns a list of object with multidimensional vector (embedding).
The number of dimensions is changing based on the reference model.
E.g. FaceNet returns 128 dimensional vector; VGG-Face returns 2622 dimensional vector.
Represent function returns a list of object, each object has fields as follows:
{
// Multidimensional vector
// The number of dimensions is changing based on the reference model.
// E.g. FaceNet returns 128 dimensional vector;
// VGG-Face returns 2622 dimensional vector.
"embedding": np.array,
// Detected Facial-Area by Face detection in dict format.
// (x, y) is left-corner point, and (w, h) is the width and height
// If `detector_backend` == `skip`, it is the full image area and nonsense.
"facial_area": dict{"x": int, "y": int, "w": int, "h": int},
// Face detection confidence.
// If `detector_backend` == `skip`, will be 0 and nonsense.
"face_confidence": float
}
"""
resp_objs = []

Expand All @@ -702,23 +717,20 @@ def represent(
align=align,
)
else: # skip
if isinstance(img_path, str):
img = functions.load_image(img_path)
elif type(img_path).__module__ == np.__name__:
img = img_path.copy()
else:
raise ValueError(f"unexpected type for img_path - {type(img_path)}")
# Try load. If load error, will raise exception internal
img, _ = functions.load_image(img_path)
# --------------------------------
if len(img.shape) == 4:
img = img[0] # e.g. (1, 224, 224, 3) to (224, 224, 3)
if len(img.shape) == 3:
img = cv2.resize(img, target_size)
img = np.expand_dims(img, axis=0)
# when represent is called from verify, this is already normalized
# when called from verify, this is already normalized. But needed when user given.
if img.max() > 1:
img /= 255
img = img.astype(np.float32) / 255.0
# --------------------------------
img_region = [0, 0, img.shape[1], img.shape[0]]
# make dummy region and confidence to keep compatibility with `extract_faces`
img_region = {"x": 0, "y": 0, "w": img.shape[1], "h": img.shape[2]}
img_objs = [(img, img_region, 0)]
# ---------------------------------

Expand All @@ -731,6 +743,9 @@ def represent(
# model.predict causes memory issue when it is called in a for loop
# embedding = model.predict(img, verbose=0)[0].tolist()
embedding = model(img, training=False).numpy()[0].tolist()
# if you still get verbose logging. try call
# - `tf.keras.utils.disable_interactive_logging()`
# in your main program
else:
# SFace and Dlib are not keras models and no verbose arguments
embedding = model.predict(img)[0].tolist()
Expand Down
3 changes: 3 additions & 0 deletions deepface/commons/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ def load_image(img):
if type(img).__module__ == np.__name__:
return img, None

if isinstance(img, Path):
img = str(img)

# The image is a base64 string
if img.startswith("data:image/"):
return loadBase64Img(img), None
Expand Down
21 changes: 21 additions & 0 deletions tests/unit_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,27 @@ def test_cases():
assert exception_thrown is False
# -------------------------------------------

# Test represent on user-given image (skip detector)
try:
face_img = dataset[1][0] # It's a face
img_objs = DeepFace.represent(img_path=face_img, detector_backend="skip")
assert len(img_objs) == 1
img_obj = img_objs[0]
assert "embedding" in img_obj.keys()
assert "facial_area" in img_obj.keys()
assert isinstance(img_obj["facial_area"], dict)
assert "x" in img_obj["facial_area"].keys()
assert "y" in img_obj["facial_area"].keys()
assert "w" in img_obj["facial_area"].keys()
assert "h" in img_obj["facial_area"].keys()
assert "face_confidence" in img_obj.keys()
exception_thrown = False
except Exception as e:
exception_thrown = True

assert exception_thrown is False

# -------------------------------------------
logger.info("-----------------------------------------")

logger.info("Extract faces test")
Expand Down

0 comments on commit 64e6ace

Please sign in to comment.