idvpackage 3.0.10__py3-none-any.whl → 3.0.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- idvpackage/common.py +0 -2
- idvpackage/ocr.py +71 -52
- {idvpackage-3.0.10.dist-info → idvpackage-3.0.11.dist-info}/METADATA +1 -1
- {idvpackage-3.0.10.dist-info → idvpackage-3.0.11.dist-info}/RECORD +7 -7
- {idvpackage-3.0.10.dist-info → idvpackage-3.0.11.dist-info}/WHEEL +0 -0
- {idvpackage-3.0.10.dist-info → idvpackage-3.0.11.dist-info}/licenses/LICENSE +0 -0
- {idvpackage-3.0.10.dist-info → idvpackage-3.0.11.dist-info}/top_level.txt +0 -0
idvpackage/common.py
CHANGED
|
@@ -909,8 +909,6 @@ def load_and_process_image_deepface(image_input, country=None):
|
|
|
909
909
|
# Keep best fallback (just in case)
|
|
910
910
|
|
|
911
911
|
|
|
912
|
-
if country == "QAT":
|
|
913
|
-
return 0, 0
|
|
914
912
|
|
|
915
913
|
if best_face_objs is None or best_confidence < CONFIDENCE_THRESHOLD:
|
|
916
914
|
print(f"No valid face found (threshold={CONFIDENCE_THRESHOLD})")
|
idvpackage/ocr.py
CHANGED
|
@@ -206,27 +206,12 @@ class IdentityVerification:
|
|
|
206
206
|
video_capture = cv2.VideoCapture(temp_video_file.name)
|
|
207
207
|
|
|
208
208
|
if video_capture.isOpened():
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
for _ in range(frame_count):
|
|
212
|
-
ret, frame = video_capture.read()
|
|
213
|
-
# if ret:
|
|
214
|
-
# frame_count_vid+=1
|
|
215
|
-
# if frame_count_vid % 10 == 0:
|
|
216
|
-
_, buffer = cv2.imencode(".jpg", frame)
|
|
217
|
-
image_data = buffer.tobytes()
|
|
218
|
-
|
|
219
|
-
image = vision_v1.Image(content=image_data)
|
|
220
|
-
|
|
221
|
-
response = self.client.face_detection(image=image)
|
|
222
|
-
if len(response.face_annotations) >= 1:
|
|
223
|
-
break
|
|
224
|
-
|
|
225
|
-
video_capture.set(cv2.CAP_PROP_POS_FRAMES, 0)
|
|
209
|
+
video_capture.set(cv2.CAP_PROP_POS_FRAMES, 0)
|
|
226
210
|
|
|
227
211
|
selfie_result = self.extract_selfie_from_video(video_capture)
|
|
228
212
|
if isinstance(selfie_result, dict):
|
|
229
213
|
video_quality["error"] = selfie_result["error"]
|
|
214
|
+
|
|
230
215
|
else:
|
|
231
216
|
(
|
|
232
217
|
selfie_blurry_result,
|
|
@@ -241,22 +226,38 @@ class IdentityVerification:
|
|
|
241
226
|
video_quality["selfie"] = selfie_result
|
|
242
227
|
video_quality["shape"] = selfie_result.shape
|
|
243
228
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
229
|
+
return video_quality
|
|
230
|
+
|
|
231
|
+
except Exception as e:
|
|
232
|
+
logging.exception("check_document_quality failed")
|
|
233
|
+
video_quality["error"] = "face_not_clear_in_video"
|
|
234
|
+
return video_quality
|
|
235
|
+
|
|
249
236
|
finally:
|
|
250
|
-
|
|
251
|
-
if
|
|
252
|
-
|
|
253
|
-
|
|
237
|
+
|
|
238
|
+
if video_capture is not None:
|
|
239
|
+
try:
|
|
240
|
+
video_capture.release()
|
|
241
|
+
except Exception:
|
|
242
|
+
pass
|
|
243
|
+
del video_capture
|
|
254
244
|
|
|
255
|
-
|
|
245
|
+
# Remove temp file
|
|
246
|
+
if temp_video_file_path and os.path.exists(temp_video_file_path):
|
|
247
|
+
try:
|
|
248
|
+
os.remove(temp_video_file_path)
|
|
249
|
+
except Exception:
|
|
250
|
+
logging.warning("Failed to delete temp file %s", temp_video_file_path)
|
|
251
|
+
|
|
252
|
+
# Force cleanup of OpenCV / numpy memory
|
|
253
|
+
import gc
|
|
254
|
+
gc.collect()
|
|
255
|
+
|
|
256
256
|
|
|
257
257
|
def extract_selfie_from_video(self, video_capture):
|
|
258
258
|
"""Extract the best quality selfie from video with speed optimizations for frontal faces."""
|
|
259
259
|
video_dict = {'error': ''}
|
|
260
|
+
|
|
260
261
|
|
|
261
262
|
try:
|
|
262
263
|
# Get rotation metadata from video
|
|
@@ -286,12 +287,12 @@ class IdentityVerification:
|
|
|
286
287
|
|
|
287
288
|
best_face = None
|
|
288
289
|
best_score = -1
|
|
289
|
-
best_frame = None
|
|
290
290
|
best_frame_position = None
|
|
291
|
-
|
|
291
|
+
best_frame = None
|
|
292
292
|
|
|
293
|
-
|
|
294
|
-
|
|
293
|
+
logging.info(f"Analyzing video with {total_frames} frames")
|
|
294
|
+
logging.info(f"Checking {len(frame_positions)} strategic frames")
|
|
295
|
+
logging.info(f"Frame positions to analyze: {frame_positions}")
|
|
295
296
|
|
|
296
297
|
for target_frame in frame_positions:
|
|
297
298
|
if target_frame >= total_frames:
|
|
@@ -299,6 +300,7 @@ class IdentityVerification:
|
|
|
299
300
|
if target_frame < 0:
|
|
300
301
|
target_frame = 0
|
|
301
302
|
|
|
303
|
+
logging.info(f"Processing frame {target_frame}")
|
|
302
304
|
video_capture.set(cv2.CAP_PROP_POS_FRAMES, target_frame)
|
|
303
305
|
ret, frame = video_capture.read()
|
|
304
306
|
if not ret or frame is None or frame.size == 0:
|
|
@@ -319,8 +321,17 @@ class IdentityVerification:
|
|
|
319
321
|
encode_params = [cv2.IMWRITE_JPEG_QUALITY, 90]
|
|
320
322
|
_, buffer = cv2.imencode(".jpg", small_frame, encode_params)
|
|
321
323
|
|
|
322
|
-
image = vision_v1.Image(content=buffer.tobytes())
|
|
324
|
+
# image = vision_v1.Image(content=buffer.tobytes())
|
|
325
|
+
# response = self.client.face_detection(image=image, max_results=2)
|
|
326
|
+
# faces = response.face_annotations
|
|
327
|
+
|
|
328
|
+
image_bytes = buffer.tobytes()
|
|
329
|
+
del buffer
|
|
330
|
+
|
|
331
|
+
image = vision_v1.Image(content=image_bytes)
|
|
323
332
|
response = self.client.face_detection(image=image, max_results=2)
|
|
333
|
+
del image_bytes
|
|
334
|
+
|
|
324
335
|
faces = response.face_annotations
|
|
325
336
|
|
|
326
337
|
if not faces:
|
|
@@ -431,40 +442,46 @@ class IdentityVerification:
|
|
|
431
442
|
}
|
|
432
443
|
|
|
433
444
|
if frame_best_face is not None:
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
# frame_results.append({
|
|
448
|
+
# 'frame': target_frame,
|
|
449
|
+
# 'face': frame_best_face,
|
|
450
|
+
# 'score': frame_best_score,
|
|
451
|
+
# 'frame_data': frame.copy()
|
|
452
|
+
# })
|
|
453
|
+
logging.info(f"Frame {target_frame}: Best face score {frame_best_score:.2f} "
|
|
454
|
+
f"(Frontal: {frame_best_face['frontal_score']:.2f}, "
|
|
455
|
+
f"Center: {frame_best_face['center_score']:.2f}, "
|
|
456
|
+
f"Confidence: {frame_best_face['confidence']:.2f})")
|
|
440
457
|
|
|
441
458
|
if frame_best_score > best_score:
|
|
459
|
+
logging.info(f"New best face found at frame {target_frame} with score {frame_best_score:.2f}")
|
|
442
460
|
best_score = frame_best_score
|
|
443
461
|
best_face = frame_best_face
|
|
444
462
|
best_frame = frame.copy()
|
|
445
463
|
best_frame_position = target_frame
|
|
446
464
|
|
|
447
465
|
except Exception as e:
|
|
466
|
+
logging.info(f"Error processing frame {target_frame}: {e}")
|
|
448
467
|
continue
|
|
449
468
|
|
|
450
|
-
# Process results
|
|
451
|
-
if len(frame_results) > 0:
|
|
452
|
-
|
|
453
|
-
|
|
469
|
+
# # Process results
|
|
470
|
+
# if len(frame_results) > 0:
|
|
471
|
+
# # Sort faces by score
|
|
472
|
+
# frame_results.sort(key=lambda x: x['score'], reverse=True)
|
|
454
473
|
|
|
455
|
-
for i, result in enumerate(frame_results[:min(3, len(frame_results))]):
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
474
|
+
# for i, result in enumerate(frame_results[:min(3, len(frame_results))]):
|
|
475
|
+
# face_info = result['face']
|
|
476
|
+
# print(f"Rank {i+1}: Frame {face_info['frame']}, "
|
|
477
|
+
# f"Score: {result['score']:.2f}, "
|
|
478
|
+
# f"Frontal: {face_info['frontal_score']:.2f}, "
|
|
479
|
+
# f"Center: {face_info['center_score']:.2f}")
|
|
461
480
|
|
|
462
481
|
# Use the best frame
|
|
463
|
-
|
|
464
|
-
best_face = best_result['face']
|
|
465
|
-
best_frame = best_result['frame_data']
|
|
482
|
+
# best_frame = frame_best_face['frame']
|
|
466
483
|
|
|
467
|
-
print(f"Selected frame {best_face['frame']} as best selfie")
|
|
484
|
+
# print(f"Selected frame {best_face['frame']} as best selfie")
|
|
468
485
|
|
|
469
486
|
if best_face and best_frame is not None:
|
|
470
487
|
try:
|
|
@@ -493,9 +510,11 @@ class IdentityVerification:
|
|
|
493
510
|
return video_dict
|
|
494
511
|
|
|
495
512
|
except Exception as e:
|
|
513
|
+
logging.info(f"Exception in extract_selfie_from_video: {e}")
|
|
496
514
|
video_dict['error'] = 'video_processing_error'
|
|
497
515
|
return video_dict
|
|
498
516
|
|
|
517
|
+
|
|
499
518
|
|
|
500
519
|
def is_colored(self, base64_image):
|
|
501
520
|
img = self.image_conversion(base64_image)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: idvpackage
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.11
|
|
4
4
|
Summary: This repository contains a Python program designed to execute Optical Character Recognition (OCR) and Facial Recognition on images.
|
|
5
5
|
Home-page: https://github.com/NymCard-Payments/project_idv_package
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
idvpackage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
idvpackage/blur_detection.py,sha256=CtLqTtg2azE4YCM8AT1jYJq6QxGoniMO0VkQYIcMtRI,1883
|
|
3
|
-
idvpackage/common.py,sha256=
|
|
3
|
+
idvpackage/common.py,sha256=xKnzPpPoXvYMIpJh4Afly6hoO__Ba13nUHODIScoCwI,46965
|
|
4
4
|
idvpackage/constants.py,sha256=XvQy5ORGsXoQGcXcvUBC17vpFMzgzleS9S_mDN72G4c,7212
|
|
5
5
|
idvpackage/ekyc.py,sha256=I7J2NTerBBnlxzgKkq5KVwgNtlAuEBeL3u_KgA1p2V8,2986
|
|
6
6
|
idvpackage/genai_utils.py,sha256=u3n_dP53P6NJaCGu1d221S8DW1g9MoSq56SNh7VQeJQ,9273
|
|
@@ -12,7 +12,7 @@ idvpackage/lazy_imports.py,sha256=Bg5BPL2KYTztKu4gGgwt4-gFP9Mo2vZWs_UJ4zrL5Hw,11
|
|
|
12
12
|
idvpackage/lebanon_id_extraction.py,sha256=eqWSpfb83RRk5TEhJNOuiPLt-wCLY5L4TvrpkOckSPs,21192
|
|
13
13
|
idvpackage/lebanon_passport_extraction.py,sha256=AEOMRcFx1vVRjI2MeFRWdPHVj-jXSC5WZdpYEsQwn7U,7057
|
|
14
14
|
idvpackage/liveness_spoofing_v2.py,sha256=6rp7R4n66ogiiQO7d0ZQzUQ7dIKGXWfD6OjXxq_DSg8,8822
|
|
15
|
-
idvpackage/ocr.py,sha256
|
|
15
|
+
idvpackage/ocr.py,sha256=MYQBcJ7yWk5HQGCyAD_KRJWp8w2xVMlJxaSYAXbs8B8,203315
|
|
16
16
|
idvpackage/ocr_utils.py,sha256=NmeGj7rhOzjg9sb_TSFcBBl8fJn4-INuHSvmijsLpiM,89845
|
|
17
17
|
idvpackage/pse_passport_extraction.py,sha256=pI5eG9yxeh_q88IISP1QkEj8BqcsXmhCa48VS0N7El8,20369
|
|
18
18
|
idvpackage/qatar_id_extraction.py,sha256=zIgKBLSTc-rKDy2b4CqM25JtLxQ9bvlyXeH-NZPh6_E,56718
|
|
@@ -35,8 +35,8 @@ idvpackage/spoof_resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
|
35
35
|
idvpackage/spoof_resources/functional.py,sha256=164aGMvBDHU6HWRyDBr-2EUPeJ4rc4cXl10NJyGB7eE,20138
|
|
36
36
|
idvpackage/spoof_resources/generate_patches.py,sha256=ANvJ5rDl-SXARchS8JwOxuKLhUuabbxLwvz4zsYbADE,1722
|
|
37
37
|
idvpackage/spoof_resources/transform.py,sha256=3Ft9S6g6N0SU24f3feHXquh5qRc85JFt2gNKnCYQwjo,11311
|
|
38
|
-
idvpackage-3.0.
|
|
39
|
-
idvpackage-3.0.
|
|
40
|
-
idvpackage-3.0.
|
|
41
|
-
idvpackage-3.0.
|
|
42
|
-
idvpackage-3.0.
|
|
38
|
+
idvpackage-3.0.11.dist-info/licenses/LICENSE,sha256=JTmNGOPPvG2XBgkW2R2xwzJeR_OEjaFKeePN1jGYVt8,1068
|
|
39
|
+
idvpackage-3.0.11.dist-info/METADATA,sha256=xyf8tPQb68CZ1duGyrjcyHKvKFwaVv_acXOIzpwLKug,4800
|
|
40
|
+
idvpackage-3.0.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
41
|
+
idvpackage-3.0.11.dist-info/top_level.txt,sha256=8jL1PsYvKBIWWLGe8jEm7kU5yZ5sld_OCaz0Dzvi6qY,11
|
|
42
|
+
idvpackage-3.0.11.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|