@@ -105,80 +105,6 @@ def verify(
105105 )
106106 dims = model .output_shape
107107
108- # extract faces from img1
109- if isinstance (img1_path , list ):
110- # given image is already pre-calculated embedding
111- if not all (isinstance (dim , float ) for dim in img1_path ):
112- raise ValueError (
113- "When passing img1_path as a list, ensure that all its items are of type float."
114- )
115-
116- if silent is False :
117- logger .warn (
118- "You passed 1st image as pre-calculated embeddings."
119- f"Please ensure that embeddings have been calculated for the { model_name } model."
120- )
121-
122- if len (img1_path ) != dims :
123- raise ValueError (
124- f"embeddings of { model_name } should have { dims } dimensions,"
125- f" but it has { len (img1_path )} dimensions input"
126- )
127-
128- img1_embeddings = [img1_path ]
129- img1_facial_areas = [None ]
130- else :
131- try :
132- img1_embeddings , img1_facial_areas = __extract_faces_and_embeddings (
133- img_path = img1_path ,
134- model_name = model_name ,
135- detector_backend = detector_backend ,
136- enforce_detection = enforce_detection ,
137- align = align ,
138- expand_percentage = expand_percentage ,
139- normalization = normalization ,
140- anti_spoofing = anti_spoofing ,
141- )
142- except ValueError as err :
143- raise ValueError ("Exception while processing img1_path" ) from err
144-
145- # extract faces from img2
146- if isinstance (img2_path , list ):
147- # given image is already pre-calculated embedding
148- if not all (isinstance (dim , float ) for dim in img2_path ):
149- raise ValueError (
150- "When passing img2_path as a list, ensure that all its items are of type float."
151- )
152-
153- if silent is False :
154- logger .warn (
155- "You passed 2nd image as pre-calculated embeddings."
156- f"Please ensure that embeddings have been calculated for the { model_name } model."
157- )
158-
159- if len (img2_path ) != dims :
160- raise ValueError (
161- f"embeddings of { model_name } should have { dims } dimensions,"
162- f" but it has { len (img2_path )} dimensions input"
163- )
164-
165- img2_embeddings = [img2_path ]
166- img2_facial_areas = [None ]
167- else :
168- try :
169- img2_embeddings , img2_facial_areas = __extract_faces_and_embeddings (
170- img_path = img2_path ,
171- model_name = model_name ,
172- detector_backend = detector_backend ,
173- enforce_detection = enforce_detection ,
174- align = align ,
175- expand_percentage = expand_percentage ,
176- normalization = normalization ,
177- anti_spoofing = anti_spoofing ,
178- )
179- except ValueError as err :
180- raise ValueError ("Exception while processing img2_path" ) from err
181-
182108 no_facial_area = {
183109 "x" : None ,
184110 "y" : None ,
@@ -188,21 +114,88 @@ def verify(
188114 "right_eye" : None ,
189115 }
190116
191- distances = []
192- facial_areas = []
117+ def extract_embeddings_and_facial_areas (
118+ img_path : Union [str , np .ndarray , List [float ]],
119+ index : int
120+ ) -> Tuple [List [List [float ]], List [dict ]]:
121+ """
122+ Extracts facial embeddings and corresponding facial areas from an
123+ image or returns pre-calculated embeddings.
124+
125+ Depending on the type of img_path, the function either extracts
126+ facial embeddings from the provided image
127+ (via a path or NumPy array) or verifies that the input is a list of
128+ pre-calculated embeddings and validates them.
129+
130+ Args:
131+ img_path (Union[str, np.ndarray, List[float]]):
132+ - A string representing the file path to an image,
133+ - A NumPy array containing the image data,
134+ - Or a list of pre-calculated embedding values (of type `float`).
135+ index (int): An index value used in error messages and logging
136+ to identify the number of the image.
137+
138+ Returns:
139+ Tuple[List[List[float]], List[dict]]:
140+ - A list containing lists of facial embeddings for each detected face.
141+ - A list of dictionaries where each dictionary contains facial area information.
142+ """
143+ if isinstance (img_path , list ):
144+ # given image is already pre-calculated embedding
145+ if not all (isinstance (dim , float ) for dim in img_path ):
146+ raise ValueError (
147+ f"When passing img{ index } _path as a list,"
148+ " ensure that all its items are of type float."
149+ )
150+
151+ if silent is False :
152+ logger .warn (
153+ "You passed 1st image as pre-calculated embeddings."
154+ "Please ensure that embeddings have been calculated"
155+ f" for the { model_name } model."
156+ )
157+
158+ if len (img_path ) != dims :
159+ raise ValueError (
160+ f"embeddings of { model_name } should have { dims } dimensions,"
161+ f" but it has { len (img_path )} dimensions input"
162+ )
163+
164+ img_embeddings = [img_path ]
165+ img_facial_areas = [no_facial_area ]
166+ else :
167+ try :
168+ img_embeddings , img_facial_areas = __extract_faces_and_embeddings (
169+ img_path = img_path ,
170+ model_name = model_name ,
171+ detector_backend = detector_backend ,
172+ enforce_detection = enforce_detection ,
173+ align = align ,
174+ expand_percentage = expand_percentage ,
175+ normalization = normalization ,
176+ anti_spoofing = anti_spoofing ,
177+ )
178+ except ValueError as err :
179+ raise ValueError (f"Exception while processing img{ index } _path" ) from err
180+ return img_embeddings , img_facial_areas
181+
182+ img1_embeddings , img1_facial_areas = extract_embeddings_and_facial_areas (img1_path , 1 )
183+ img2_embeddings , img2_facial_areas = extract_embeddings_and_facial_areas (img2_path , 2 )
184+
185+ min_distance , min_idx , min_idy = float ("inf" ), None , None
193186 for idx , img1_embedding in enumerate (img1_embeddings ):
194187 for idy , img2_embedding in enumerate (img2_embeddings ):
195188 distance = find_distance (img1_embedding , img2_embedding , distance_metric )
196- distances .append (distance )
197- facial_areas .append (
198- (img1_facial_areas [idx ] or no_facial_area , img2_facial_areas [idy ] or no_facial_area )
199- )
189+ if distance < min_distance :
190+ min_distance , min_idx , min_idy = distance , idx , idy
200191
201192 # find the face pair with minimum distance
202193 threshold = threshold or find_threshold (model_name , distance_metric )
203- min_index = np .argmin (distances )
204- distance = float (distances [min_index ]) # best distance
205- facial_areas = facial_areas [min_index ]
194+ distance = float (min_distance )
195+ facial_areas = (
196+ no_facial_area if min_idx is None else img1_facial_areas [min_idx ],
197+ no_facial_area if min_idy is None else img2_facial_areas [min_idy ],
198+ )
206199
207200 toc = time .time ()
208201
0 commit comments