Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verification #1309

Merged
merged 4 commits into from
Aug 16, 2024
Merged

Verification #1309

merged 4 commits into from
Aug 16, 2024

Conversation

kremnik
Copy link
Contributor

@kremnik kremnik commented Aug 16, 2024

What has been done

With this PR:

  1. The calculation of distances between faces has been updated to optimize memory consumption;
  2. Duplicate code for obtaining face embeddings has been moved into a single function.

How to test

make lint && make test

)
except ValueError as err:
raise ValueError("Exception while processing img2_path") from err
def extract_faces_from_img(img_path, index=1):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1- this function finds embeddings and facial areas. we should give the function a proper name.
2- please add a docstring to this function
3- types of this function are missing. img_path: Union[str, np.ndarray] and index: int. Besides, should we really set a default value to index?
4- return type of this function is missing. it should return Tuple[List[List[float]], List[dict]]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that since the function is internal and auxiliary, it wasn't necessary to format it according to the function formatting rules. I'll fix it without any problem.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, it is not necessary. Still, I strongly recommend to have type hinting.

distance = float(distances[min_index]) # best distance
facial_areas = facial_areas[min_index]
distance = float(min_distance)
facial_areas = (no_facial_area, no_facial_area) if None in (min_idx, min_idy) else \
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if img1_facial_areas[min_idx] is None and img2_facial_areas[min_idy] is not None?

In previous design, we were setting no_facial_area's values to 1st item, and img2_facial_areas[min_idy]'s value to 2nd item.

In your design, no_facial_area's values are not set, instead you are setting None. Am I right?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the following code snippet will resolve that issue

facial_areas = (
	no_facial_area if min_idx is None else img1_facial_areas[min_idx] or no_facial_area,
	no_facial_area if min_idy is None else img2_facial_areas[min_idy] or no_facial_area,
)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I understand it, img1_facial_areas[min_idx] and img2_facial_areas[min_idy] will never be None, because if a face is not found, the area of the entire image is still returned. Therefore, the code from the previous design, img1_facial_areas[idx] or no_facial_area, will never return no_facial_area.

That's why I thought that if we don't find faces in at least one of the photos, we shouldn't display anything at all.

The code you suggested really solves the problem, thank you!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we don't need or no_facial_area in the end of statements? Because no_facial_area if min_idx is None else img1_facial_areas[min_idx] will return Truthy anyway.

facial_areas = (
	no_facial_area if min_idx is None else img1_facial_areas[min_idx],
	no_facial_area if min_idy is None else img2_facial_areas[min_idy],
)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, img1_facial_areas[idx] can be None from this line

https://github.com/serengil/deepface/blob/master/deepface/modules/verification.py#L166

Copy link
Owner

@serengil serengil Aug 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the problem occurs when min_idx is 0 but img1_facial_areas[0] is None. We still need to return the dictionary, but the code snippet you recommended returns None.

This happens when you feed an embedding to img_path

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are right. I didn't mention, that img1_facial_areas[idx] can return None. Sorry, my bad.

What do you think, maybe, it is better to do something like this?

img_facial_areas = [no_facial_area]

instead of

img_facial_areas = [None]

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, this will also work

i hope this is the only point facial area can be none - https://github.com/serengil/deepface/blob/master/deepface/modules/verification.py#L166

@serengil
Copy link
Owner

Very good spot btw, I don't like that repeating code and have been planning to fix it. You acted faster than me. Cheers.

@serengil
Copy link
Owner

Linting failed

************* Module deepface.modules.verification
deepface/modules/verification.py:114:0: C0301: Line too long (107/100) (line-too-long)
pylint: Command line or configuration file:1: UserWarning: 'Exception' is not a proper value for the 'overgeneral-exceptions' option. Use fully qualified name (maybe 'builtins.Exception' ?) instead. This will cease to be checked at runtime in 3.1.0.
deepface/modules/verification.py:120:0: C0301: Line too long (101/100) (line-too-long)

-----------------------------------
Your code has been rated at 9.99/10

@serengil
Copy link
Owner

serengil commented Aug 16, 2024

Would you please add an unit test for facial areas checking to https://github.com/serengil/deepface/blob/master/tests/test_verify.py#L123 ?

assert result["facial_areas"]["img1"] is not None
assert result["facial_areas"]["img2"] is not None

assert isinstance(result["facial_areas"]["img1"], dict)
assert isinstance(result["facial_areas"]["img2"], dict)

assert "x" in result["facial_areas"]["img1"].keys()
assert "y" in result["facial_areas"]["img1"].keys()
assert "w" in result["facial_areas"]["img1"].keys()
assert "h" in result["facial_areas"]["img1"].keys()
assert "left_eye" in result["facial_areas"]["img1"].keys()
assert "right_eye" in result["facial_areas"]["img1"].keys()

assert "x" in result["facial_areas"]["img2"].keys()
assert "y" in result["facial_areas"]["img2"].keys()
assert "w" in result["facial_areas"]["img2"].keys()
assert "h" in result["facial_areas"]["img2"].keys()
assert "left_eye" in result["facial_areas"]["img2"].keys()
assert "right_eye" in result["facial_areas"]["img2"].keys()


if silent is False:
logger.warn(
"You passed 1st image as pre-calculated embeddings."
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1st image term should not be static. Would you please get it from index arg?

if len(img_path) != dims:
raise ValueError(
f"embeddings of {model_name} should have {dims} dimensions,"
f" but it has {len(img_path)} dimensions input"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shall we mention the index here as well?

@serengil
Copy link
Owner

LGTM, I added a couple of minor comments but I can add them later. Cheers!

@serengil serengil merged commit 9768abc into serengil:master Aug 16, 2024
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants