idvpackage 3.0.8__py3-none-any.whl → 3.0.10__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/ocr.py CHANGED
@@ -191,6 +191,7 @@ class IdentityVerification:
191
191
 
192
192
  return enhanced_contrast
193
193
 
194
+
194
195
  def check_document_quality(self, data):
195
196
  video_quality = {"error": ""}
196
197
  temp_video_file = tempfile.NamedTemporaryFile(delete=False)
@@ -232,8 +233,8 @@ class IdentityVerification:
232
233
  selfie_bright_result,
233
234
  ) = self.get_blurred_and_glared_for_doc(selfie_result)
234
235
  if (
235
- selfie_blurry_result == "consider"
236
- or selfie_bright_result == "consider"
236
+ selfie_blurry_result == "consider"
237
+ or selfie_bright_result == "consider"
237
238
  ):
238
239
  video_quality["error"] = "face_not_clear_in_video"
239
240
  else:
@@ -255,12 +256,22 @@ class IdentityVerification:
255
256
 
256
257
  def extract_selfie_from_video(self, video_capture):
257
258
  """Extract the best quality selfie from video with speed optimizations for frontal faces."""
258
- video_dict = {"error": ""}
259
+ video_dict = {'error': ''}
259
260
 
260
261
  try:
262
+ # Get rotation metadata from video
263
+ try:
264
+ rotation = int(video_capture.get(cv2.CAP_PROP_ORIENTATION_META))
265
+ except Exception as e:
266
+ logging.info(f"Defaulting to Rotation=0, Exception Thrown while getting rotation metadata from video.{e}")
267
+ rotation=0
268
+ logging.info(f"Video rotation metadata: {rotation}°")
269
+
270
+
271
+
261
272
  total_frames = int(video_capture.get(cv2.CAP_PROP_FRAME_COUNT))
262
273
  if total_frames <= 0:
263
- video_dict["error"] = "invalid_video_frame_count"
274
+ video_dict['error'] = 'invalid_video_frame_count'
264
275
  return video_dict
265
276
 
266
277
  # Check only 6 frames - 2 at start, 2 in the middle, 2 at the end
@@ -270,7 +281,7 @@ class IdentityVerification:
270
281
  int(total_frames * 0.45),
271
282
  int(total_frames * 0.55),
272
283
  int(total_frames * 0.85),
273
- int(total_frames * 0.95),
284
+ int(total_frames * 0.95)
274
285
  ]
275
286
 
276
287
  best_face = None
@@ -293,6 +304,14 @@ class IdentityVerification:
293
304
  if not ret or frame is None or frame.size == 0:
294
305
  continue
295
306
 
307
+ # Apply rotation correction based on video metadata
308
+ if rotation == 90:
309
+ frame = cv2.rotate(frame, cv2.ROTATE_90_CLOCKWISE)
310
+ elif rotation == 180:
311
+ frame = cv2.rotate(frame, cv2.ROTATE_180)
312
+ elif rotation == 270:
313
+ frame = cv2.rotate(frame, cv2.ROTATE_90_COUNTERCLOCKWISE)
314
+
296
315
  try:
297
316
  scale = 0.7
298
317
  small_frame = cv2.resize(frame, (0, 0), fx=scale, fy=scale)
@@ -311,10 +330,8 @@ class IdentityVerification:
311
330
  frame_best_score = -1
312
331
 
313
332
  for face in faces:
314
- vertices = [
315
- (int(vertex.x / scale), int(vertex.y / scale))
316
- for vertex in face.bounding_poly.vertices
317
- ]
333
+ vertices = [(int(vertex.x / scale), int(vertex.y / scale))
334
+ for vertex in face.bounding_poly.vertices]
318
335
 
319
336
  left = min(v[0] for v in vertices)
320
337
  upper = min(v[1] for v in vertices)
@@ -322,18 +339,13 @@ class IdentityVerification:
322
339
  lower = max(v[1] for v in vertices)
323
340
 
324
341
  # Validate face coordinates
325
- if not (
326
- 0 <= left < right <= frame.shape[1]
327
- and 0 <= upper < lower <= frame.shape[0]
328
- ):
342
+ if not (0 <= left < right <= frame.shape[1] and 0 <= upper < lower <= frame.shape[0]):
329
343
  continue
330
344
 
331
345
  # Calculate face metrics
332
346
  face_width = right - left
333
347
  face_height = lower - upper
334
- face_area = (face_width * face_height) / (
335
- frame.shape[0] * frame.shape[1]
336
- )
348
+ face_area = (face_width * face_height) / (frame.shape[0] * frame.shape[1])
337
349
 
338
350
  # Reject small faces
339
351
  if face_area < 0.05:
@@ -345,23 +357,19 @@ class IdentityVerification:
345
357
  frame_center_x = frame.shape[1] / 2
346
358
  frame_center_y = frame.shape[0] / 2
347
359
 
348
- center_dist_x = abs(face_center_x - frame_center_x) / (
349
- frame.shape[1] / 2
350
- )
351
- center_dist_y = abs(face_center_y - frame_center_y) / (
352
- frame.shape[0] / 2
353
- )
360
+ center_dist_x = abs(face_center_x - frame_center_x) / (frame.shape[1] / 2)
361
+ center_dist_y = abs(face_center_y - frame_center_y) / (frame.shape[0] / 2)
354
362
  center_score = 1.0 - (center_dist_x + center_dist_y) / 2
355
363
 
356
364
  # For frontal faces, left and right eye/ear should be roughly symmetric
357
365
  if len(face.landmarks) > 0:
358
366
  # Head rotation detection
359
367
  roll, pan, tilt = 0, 0, 0
360
- if hasattr(face, "roll_angle"):
368
+ if hasattr(face, 'roll_angle'):
361
369
  roll = abs(face.roll_angle)
362
- if hasattr(face, "pan_angle"):
370
+ if hasattr(face, 'pan_angle'):
363
371
  pan = abs(face.pan_angle)
364
- if hasattr(face, "tilt_angle"):
372
+ if hasattr(face, 'tilt_angle'):
365
373
  tilt = abs(face.tilt_angle)
366
374
 
367
375
  head_angle_penalty = (roll + pan + tilt) / 180.0
@@ -369,9 +377,7 @@ class IdentityVerification:
369
377
  # Symmetry detection from face bounding box
370
378
  left_half = face_center_x - left
371
379
  right_half = right - face_center_x
372
- width_ratio = min(left_half, right_half) / max(
373
- left_half, right_half
374
- )
380
+ width_ratio = min(left_half, right_half) / max(left_half, right_half)
375
381
 
376
382
  # Frontal-face score: higher for more frontal faces
377
383
  # Perfect frontal face would be 1.0
@@ -380,17 +386,15 @@ class IdentityVerification:
380
386
  # No landmarks, estimate from bounding box
381
387
  left_half = face_center_x - left
382
388
  right_half = right - face_center_x
383
- frontal_score = min(left_half, right_half) / max(
384
- left_half, right_half
385
- )
389
+ frontal_score = min(left_half, right_half) / max(left_half, right_half)
386
390
 
387
391
  # Combined score weights different factors
388
392
  # More weight for frontal-ness and face confidence
389
393
  score = (
390
- face.detection_confidence * 0.3
391
- + face_area * 0.2
392
- + center_score * 0.2
393
- + frontal_score * 0.3
394
+ face.detection_confidence * 0.3 +
395
+ face_area * 0.2 +
396
+ center_score * 0.2 +
397
+ frontal_score * 0.3
394
398
  )
395
399
 
396
400
  # Heavy bonus for very frontal faces (nearly symmetric)
@@ -410,33 +414,29 @@ class IdentityVerification:
410
414
  left_with_margin = max(0, left - margin_x)
411
415
  upper_with_margin = max(0, upper - margin_y_top)
412
416
  right_with_margin = min(frame.shape[1], right + margin_x)
413
- lower_with_margin = min(
414
- frame.shape[0], lower + margin_y_bottom
415
- )
417
+ lower_with_margin = min(frame.shape[0], lower + margin_y_bottom)
416
418
 
417
419
  # Store the best face info
418
420
  frame_best_score = score
419
421
  frame_best_face = {
420
- "face": face,
421
- "left": left_with_margin,
422
- "upper": upper_with_margin,
423
- "right": right_with_margin,
424
- "lower": lower_with_margin,
425
- "frontal_score": frontal_score,
426
- "center_score": center_score,
427
- "confidence": face.detection_confidence,
428
- "frame": target_frame,
422
+ 'face': face,
423
+ 'left': left_with_margin,
424
+ 'upper': upper_with_margin,
425
+ 'right': right_with_margin,
426
+ 'lower': lower_with_margin,
427
+ 'frontal_score': frontal_score,
428
+ 'center_score': center_score,
429
+ 'confidence': face.detection_confidence,
430
+ 'frame': target_frame
429
431
  }
430
432
 
431
433
  if frame_best_face is not None:
432
- frame_results.append(
433
- {
434
- "frame": target_frame,
435
- "face": frame_best_face,
436
- "score": frame_best_score,
437
- "frame_data": frame.copy(),
438
- }
439
- )
434
+ frame_results.append({
435
+ 'frame': target_frame,
436
+ 'face': frame_best_face,
437
+ 'score': frame_best_score,
438
+ 'frame_data': frame.copy()
439
+ })
440
440
 
441
441
  if frame_best_score > best_score:
442
442
  best_score = frame_best_score
@@ -450,30 +450,28 @@ class IdentityVerification:
450
450
  # Process results
451
451
  if len(frame_results) > 0:
452
452
  # Sort faces by score
453
- frame_results.sort(key=lambda x: x["score"], reverse=True)
453
+ frame_results.sort(key=lambda x: x['score'], reverse=True)
454
454
 
455
- for i, result in enumerate(frame_results[: min(3, len(frame_results))]):
456
- face_info = result["face"]
457
- print(
458
- f"Rank {i + 1}: Frame {face_info['frame']}, "
459
- f"Score: {result['score']:.2f}, "
460
- f"Frontal: {face_info['frontal_score']:.2f}, "
461
- f"Center: {face_info['center_score']:.2f}"
462
- )
455
+ for i, result in enumerate(frame_results[:min(3, len(frame_results))]):
456
+ face_info = result['face']
457
+ print(f"Rank {i+1}: Frame {face_info['frame']}, "
458
+ f"Score: {result['score']:.2f}, "
459
+ f"Frontal: {face_info['frontal_score']:.2f}, "
460
+ f"Center: {face_info['center_score']:.2f}")
463
461
 
464
462
  # Use the best frame
465
463
  best_result = frame_results[0]
466
- best_face = best_result["face"]
467
- best_frame = best_result["frame_data"]
464
+ best_face = best_result['face']
465
+ best_frame = best_result['frame_data']
468
466
 
469
467
  print(f"Selected frame {best_face['frame']} as best selfie")
470
468
 
471
469
  if best_face and best_frame is not None:
472
470
  try:
473
- left = best_face["left"]
474
- upper = best_face["upper"]
475
- right = best_face["right"]
476
- lower = best_face["lower"]
471
+ left = best_face['left']
472
+ upper = best_face['upper']
473
+ right = best_face['right']
474
+ lower = best_face['lower']
477
475
 
478
476
  # Convert to RGB and crop
479
477
  rgb_frame = cv2.cvtColor(best_frame, cv2.COLOR_BGR2RGB)
@@ -481,23 +479,24 @@ class IdentityVerification:
481
479
 
482
480
  # Validate cropped face
483
481
  if cropped_face is None or cropped_face.size == 0:
484
- video_dict["error"] = "invalid_cropped_face"
482
+ video_dict['error'] = 'invalid_cropped_face'
485
483
  return video_dict
486
484
 
487
485
  print(f"Face shape: {cropped_face.shape}")
488
486
  return cropped_face
489
487
 
490
488
  except Exception as e:
491
- video_dict["error"] = "error_processing_detected_face"
489
+ video_dict['error'] = 'error_processing_detected_face'
492
490
  return video_dict
493
491
  else:
494
- video_dict["error"] = "no_suitable_face_detected_in_video"
492
+ video_dict['error'] = 'no_suitable_face_detected_in_video'
495
493
  return video_dict
496
494
 
497
495
  except Exception as e:
498
- video_dict["error"] = "video_processing_error"
496
+ video_dict['error'] = 'video_processing_error'
499
497
  return video_dict
500
498
 
499
+
501
500
  def is_colored(self, base64_image):
502
501
  img = self.image_conversion(base64_image)
503
502
  img = np.array(img)
@@ -1013,12 +1012,7 @@ class IdentityVerification:
1013
1012
  ):
1014
1013
  st = time.time()
1015
1014
  document_data = {}
1016
- # side=auto only in testing mode.
1017
- # if document_type != 'passport' and country == 'IRQ':
1018
- # document_data = self.agent_extraction(image, country, side)
1019
- # logging.info(
1020
- # f"--------------Time taken for Front ID Extraction in IDV package: {time.time() - st} seconds\n")
1021
- # return document_data
1015
+
1022
1016
  logging.info(f"Starting extraction for document_type: {document_type}, country: {country}, side: {side}, nationality: {nationality}, \n step data: {step_data}")
1023
1017
 
1024
1018
  if country == "IRQ":
@@ -1459,94 +1453,6 @@ class IdentityVerification:
1459
1453
 
1460
1454
  return front_data
1461
1455
 
1462
- if country == "SAU":
1463
- from idvpackage.ocr_utils import (
1464
- detect_photo_on_screen,
1465
- detect_screenshot,
1466
- document_on_printed_paper,
1467
- )
1468
- from idvpackage.sau_id_extraction import extract_id_details
1469
-
1470
- front_data = {"error": "", "doc_type": "national_identity_card"}
1471
-
1472
- try:
1473
- processed_front_id = self.image_conversion(front_id)
1474
- front_id_text = self.get_ocr_results(processed_front_id)
1475
- front_id_text = front_id_text[0].description
1476
- front_id_text_list = front_id_text.split("\n")
1477
-
1478
- img = self.image_conversion(front_id)
1479
- image = np.array(img)
1480
- pil_image = Image.fromarray(image)
1481
-
1482
- doc_on_pp_result = document_on_printed_paper(image)
1483
-
1484
- with io.BytesIO() as output:
1485
- pil_image.save(output, format="PNG")
1486
- image_data = output.getvalue()
1487
- logo_result = "clear"
1488
- screenshot_result = detect_screenshot(self.client, front_id)
1489
- photo_on_screen_result = detect_photo_on_screen(self.client, front_id)
1490
-
1491
- front_blurred, front_glare = self.get_blurred_and_glared_for_doc(image)
1492
-
1493
- front_face_locations, front_face_encodings = (
1494
- self.load_and_process_image_fr(front_id)
1495
- )
1496
-
1497
- front_face_locations_str = json.dumps(
1498
- [tuple(face_loc) for face_loc in front_face_locations]
1499
- )
1500
- front_face_encodings_str = json.dumps(
1501
- [face_enc.tolist() for face_enc in front_face_encodings]
1502
- )
1503
-
1504
- front_data_fields = extract_id_details(front_id_text_list)
1505
- valid_nationality_result = self.check_nationality_in_iso_list(
1506
- front_data_fields.get("nationality")
1507
- )
1508
-
1509
- front_data = {
1510
- "valid_nationality": valid_nationality_result,
1511
- "front_extracted_data": front_id_text,
1512
- "front_coloured": True,
1513
- "front_doc_on_pp": doc_on_pp_result,
1514
- "front_logo_result": logo_result,
1515
- "front_screenshot_result": screenshot_result,
1516
- "front_photo_on_screen_result": photo_on_screen_result,
1517
- "front_blurred": front_blurred,
1518
- "front_glare": front_glare,
1519
- "front_face_locations": front_face_locations_str,
1520
- "front_face_encodings": front_face_encodings_str,
1521
- }
1522
-
1523
- front_data.update(front_data_fields)
1524
-
1525
- non_optional_keys = [
1526
- "front_face_locations",
1527
- "front_face_encodings",
1528
- "id_number",
1529
- "name",
1530
- "dob",
1531
- "expiry_date",
1532
- "gender",
1533
- "nationality",
1534
- ]
1535
- empty_string_keys = [
1536
- key
1537
- for key, value in front_data.items()
1538
- if key in non_optional_keys and value == ""
1539
- ]
1540
-
1541
- if empty_string_keys:
1542
- front_data["error"] = "covered_photo"
1543
-
1544
- except Exception as e:
1545
- front_data["error"] = "bad_image"
1546
- front_data["error_details"] = e
1547
-
1548
- return front_data
1549
-
1550
1456
  if country == "IRQ":
1551
1457
  logging.info("-------------Working on IRQ \n")
1552
1458
  from idvpackage.ocr_utils import (
@@ -2244,16 +2150,6 @@ class IdentityVerification:
2244
2150
  print(f"-------------->> Something went wrong error trace:: {e}")
2245
2151
  front_data["error_details"] = e
2246
2152
 
2247
- # try:
2248
- # list_1 = front_data['name_ar'].split(" ")
2249
- # filtered_names = [name for name in list_1 if len(name) > 1]
2250
- # front_data['first_name_ar'] = filtered_names[0]
2251
- # front_data['last_name_ar'] = filtered_names[3]
2252
- # front_data['middle_name_ar'] = filtered_names[1]+' '+filtered_names[2]
2253
- # except Exception as e:
2254
- # front_data['first_name_ar'] = ''
2255
- # front_data['last_name_ar'] = ''
2256
- # front_data['middle_name_ar'] = ''
2257
2153
 
2258
2154
  try:
2259
2155
  list_1 = front_data["name_ar"].split(" ")
@@ -2996,7 +2892,6 @@ class IdentityVerification:
2996
2892
  return back_data
2997
2893
 
2998
2894
  if country == "QAT":
2999
- # from idvpackage.qatar_id_extraction import qatar_back_id_extraction
3000
2895
  from idvpackage.qatar_id_extraction import get_response_from_openai_qat
3001
2896
 
3002
2897
  back_data = {"error": "", "doc_type": "national_identity_card"}
@@ -3011,28 +2906,6 @@ class IdentityVerification:
3011
2906
  )
3012
2907
  compressed_image_data = compressed_image.getvalue()
3013
2908
 
3014
- # id_infos = self.get_ocr_results(compressed_image_data, country="QAT")
3015
-
3016
- # text = id_infos[0].description
3017
- # print(f'Original text: {text}')
3018
-
3019
- # translated_id_text = self.translator.translate(text, from_lang='ar', to_lang='en').text
3020
- # pattern4 = r"(Director General of the General Department|Directorate of Passports|Passport number|Serial)"
3021
- # k = re.search(pattern4, text, re.IGNORECASE)
3022
- # print('this is translated_id_text',translated_id_text)
3023
- # if not k:
3024
- # back_data["error"] = "not_back_id"
3025
-
3026
- # return back_data
3027
-
3028
- # original_text = text
3029
-
3030
- # print('this is original text:',original_text)
3031
-
3032
- ## TODO: template matching for Qatar ID's
3033
- # image_data = base64.b64decode(back_id)
3034
-
3035
- # back_extraction_result = qatar_back_id_extraction(original_text)
3036
2909
  back_extraction_result = get_response_from_openai_qat(compressed_image_data, "back", country, self.openai_key)
3037
2910
  back_data.update(back_extraction_result)
3038
2911
 
@@ -3052,30 +2925,19 @@ class IdentityVerification:
3052
2925
 
3053
2926
  back_data.update(back_data_update)
3054
2927
 
3055
- # non_optional_keys = ["card_number"]
3056
- # empty_string_keys = [key for key, value in back_data.items() if key in non_optional_keys and value == '']
3057
-
3058
- # if empty_string_keys:
3059
- # back_data['error'] = 'covered_photo'
3060
-
2928
+
3061
2929
  except Exception as e:
3062
2930
  back_data["error"] = "bad_image"
3063
2931
  back_data["error_details"] = e
3064
2932
 
3065
- # back_data['error_details'] = e
3066
- # else:
3067
- # back_data['error'] = 'bad_image'
3068
-
3069
2933
  return back_data
3070
2934
 
3071
2935
  if country == "LBN":
3072
2936
  from idvpackage.ocr_utils import (
3073
- detect_logo,
3074
2937
  detect_photo_on_screen,
3075
2938
  detect_screenshot,
3076
2939
  document_on_printed_paper,
3077
2940
  )
3078
- # from idvpackage.lebanon_id_extraction import lebanon_back_id_extraction
3079
2941
  from idvpackage.lebanon_id_extraction import lebanon_id_extraction_from_text
3080
2942
  from idvpackage.blur_detection import is_image_blur
3081
2943
 
@@ -3118,16 +2980,7 @@ class IdentityVerification:
3118
2980
  back_data["error"] = "blur_photo"
3119
2981
  return back_data
3120
2982
 
3121
- ## TODO: template matching for Lebanon ID's
3122
- # image_data = base64.b64decode(back_id)
3123
- # template_result = detect_logo(self.client, image_data, country, compare_type='template', side='back')
3124
- # if template_result == 'consider':
3125
- # back_data["error"] = "not_back_id"
3126
- # return back_data
3127
-
3128
- ## TODO: tampering result for Lebanon ID's
3129
- # tampered_result_back = calculate_error_difference(np.array(Image.open(io.BytesIO(base64.decodebytes(bytes(back_id, "utf-8"))))))
3130
-
2983
+
3131
2984
  st = time.time()
3132
2985
  back_extraction_result = lebanon_id_extraction_from_text(back_id_text_desc, compressed_image_data, "back", self.openai_key)
3133
2986
 
@@ -3208,80 +3061,29 @@ class IdentityVerification:
3208
3061
 
3209
3062
  if country == "SDN":
3210
3063
  from idvpackage.ocr_utils import (
3211
- detect_logo,
3212
3064
  detect_photo_on_screen,
3213
3065
  detect_screenshot,
3214
3066
  document_on_printed_paper,
3215
3067
  )
3216
- from idvpackage.sudan_id_extraction import sdn_back_id_extraction
3217
3068
  from idvpackage.blur_detection import is_image_blur
3218
3069
 
3219
3070
  back_data = {"error": "", "doc_type": "national_identity_card"}
3220
3071
 
3221
- logging.info(f"Starting Sudan ID back side processing with step_data:{step_data}")
3072
+ logging.info(f"Starting Sudan ID back side processing with step_data:{step_data.keys() if step_data else 'None'}")
3222
3073
  try:
3223
3074
  st = time.time()
3224
3075
  processed_back_id = self.image_conversion(back_id)
3225
3076
  logging.info(
3226
3077
  f"----------------Time taken for image conversion back: {time.time() - st} seconds\n"
3227
3078
  )
3228
-
3229
3079
  st = time.time()
3230
3080
  compressed_image = BytesIO()
3231
3081
  processed_back_id.save(
3232
3082
  compressed_image, format="JPEG", quality=90, optimize=True
3233
3083
  )
3234
3084
  compressed_image_data = compressed_image.getvalue()
3235
- # id_infos = self.get_ocr_results(compressed_image_data, country="SDN")
3236
- # text = id_infos[0].description
3237
- # logging.info(
3238
- # f"----------------Time taken for vision back: {time.time() - st} seconds\n"
3239
- # )
3240
-
3241
- # try:
3242
- # translated_id_text = self.translator.translate(
3243
- # text, src="ar", dest="en"
3244
- # ).text
3245
- # except:
3246
- # logging.info(
3247
- # f"\n--------------Fallback for translation keyword matching"
3248
- # )
3249
- # from deep_translator import GoogleTranslator
3250
-
3251
- # translated_id_text = GoogleTranslator("ar", "en").translate(text)
3252
- # logging.info(
3253
- # f"----------------Time taken for ar-en translation back: {time.time() - st} seconds\n"
3254
- # )
3255
-
3256
- # pattern4 = r"(IDSDN|Name)"
3257
- # k = re.search(pattern4, translated_id_text, re.IGNORECASE)
3258
-
3259
- # if not k:
3260
- # back_data["error"] = "not_back_id"
3261
- # return back_data
3262
-
3263
-
3264
-
3265
-
3266
3085
  image = np.array(processed_back_id)
3267
- # blur_test = is_image_blur(image)
3268
- # if blur_test == True:
3269
- # print(f"Back ID Document is blurry, marking as covered photo")
3270
- # back_data['error'] = 'covered_photo'
3271
- # return back_data
3272
-
3273
- ## TODO: template matching for Lebanon ID's
3274
- # image_data = base64.b64decode(back_id)
3275
- # template_result = detect_logo(self.client, image_data, country, compare_type='template', side='back')
3276
- # if template_result == 'consider':
3277
- # back_data["error"] = "not_back_id"
3278
- # return back_data
3279
-
3280
- ## TODO: tampering result for Lebanon ID's
3281
- # tampered_result_back = calculate_error_difference(np.array(Image.open(io.BytesIO(base64.decodebytes(bytes(back_id, "utf-8"))))))
3282
-
3283
3086
  st = time.time()
3284
- # back_extraction_result = sdn_back_id_extraction(text)
3285
3087
  from idvpackage.sudan_passport_extraction import get_response_from_openai_sdn
3286
3088
  back_extraction_result = get_response_from_openai_sdn(compressed_image_data, "back", self.openai_key)
3287
3089
 
@@ -3309,14 +3111,6 @@ class IdentityVerification:
3309
3111
  back_data.update(back_extraction_result)
3310
3112
  back_data['issuing_country'] = 'SDN'
3311
3113
 
3312
-
3313
- # back_data['']
3314
-
3315
- # issue and expiry date should be same as mrz
3316
- # issue and expiry date should have 5 years of difference
3317
- # issue and expiry date from mrz should have 5 years of difference
3318
- # date of birth from front should match date of birth from back
3319
- # date of birth from front should match date of birth from mrz
3320
3114
  from idvpackage.ocr_utils import normalize_date_generic
3321
3115
 
3322
3116
  dob_front_str = step_data.get("dob", "") if step_data else ""
@@ -3423,27 +3217,6 @@ class IdentityVerification:
3423
3217
  back_data['error'] = "front_back_mismatch"
3424
3218
  return back_data
3425
3219
 
3426
- # name_mrz = []
3427
- # try:
3428
- # for word in back_data.get("mrz3", "").split("<"):
3429
- # if word and word.isalpha():
3430
- # name_mrz.append(word)
3431
-
3432
- # back_data['name_mrz'] = " ".join(name_mrz)
3433
- # name = back_data.get("full_name_generic", "")
3434
- # try:
3435
- # name = name.split(" ")
3436
- # except:
3437
- # name = []
3438
- # from idvpackage.ocr_utils import get_name_match_mrz
3439
- # back_data['name_match_mrz'] = get_name_match_mrz(name, name_mrz)
3440
-
3441
- # logging.info(f"name_match_mrz: {back_data['name_match_mrz']}")
3442
- # except Exception as e:
3443
- # back_data['name_match_mrz'] = False
3444
- # back_data['name_mrz'] = ''
3445
- # logging.info(f"Error in comparing name between extracted name and MRZ for SDN ID {e}")
3446
- # pass
3447
3220
  from idvpackage.ocr_utils import get_name_match_mrz
3448
3221
  back_data['nationality'] = 'SDN'
3449
3222
  back_data['is_name_match_mrz'], back_data['name_mrz'] = get_name_match_mrz(back_data, "nationality_identity_card")
@@ -3759,11 +3532,7 @@ class IdentityVerification:
3759
3532
  detect_screenshot,
3760
3533
  document_on_printed_paper,
3761
3534
  )
3762
- # from idvpackage.lebanon_passport_extraction import (
3763
- # lebanon_passport_extraction,
3764
- # verify_lbn_pss_chain,
3765
- # )
3766
-
3535
+
3767
3536
  from idvpackage.lebanon_id_extraction import get_response_from_openai_lbn
3768
3537
  from idvpackage.common import load_and_process_image_deepface
3769
3538
  from idvpackage.blur_detection import is_image_blur
@@ -3853,31 +3622,7 @@ class IdentityVerification:
3853
3622
  logging.info(f"validation_results: {json.dumps(validation_results, ensure_ascii=False, indent=2)}")
3854
3623
  passport_data.update(validation_results)
3855
3624
 
3856
- #extract name from mrz1
3857
- # mrz1 = passport_details.get('mrz1', '')
3858
- # logging.info(f"MRZ1 extracted: {mrz1}")
3859
- # if mrz1:
3860
- # try:
3861
- # mrz1 = mrz1[5:]
3862
- # logging.info(f"Processed MRZ1: {mrz1}")
3863
- # name_mrz = []
3864
- # for word in mrz1.split("<"):
3865
- # if word and word.isalpha():
3866
- # name_mrz.append(word)
3867
-
3868
- # passport_data['name_mrz'] = " ".join(name_mrz)
3869
- # logging.info(f"Name from MRZ1 parts: {name_mrz}")
3870
-
3871
- # name = passport_data.get("last_name", "") + " " + passport_data.get("first_name", "")
3872
- # name = name.split(" ")
3873
- # from idvpackage.ocr_utils import get_name_match_mrz
3874
- # passport_data['is_name_match_mrz'] = get_name_match_mrz(name, name_mrz)
3875
- # logging.info(f"is_name_match_mrz: {passport_data['is_name_match_mrz']}")
3876
-
3877
- # except Exception as e:
3878
- # logging.info(f"Error in processing Name from MRZ1: {e}")
3879
- # passport_data['is_name_match_mrz'] = False
3880
- # pass
3625
+
3881
3626
  from idvpackage.ocr_utils import get_name_match_mrz
3882
3627
  passport_data['is_name_match_mrz'], passport_data['name_mrz'] = get_name_match_mrz(passport_data, "passport")
3883
3628
 
@@ -3885,8 +3630,7 @@ class IdentityVerification:
3885
3630
  image = np.array(processed_passport)
3886
3631
 
3887
3632
  st = time.time()
3888
- ## TODO: doc_on_pp and detect_photo_on_screen for LBN
3889
- # doc_on_pp_result = document_on_printed_paper(image)
3633
+
3890
3634
  doc_on_pp_result = "clear"
3891
3635
  screenshot_result = detect_screenshot(self.client, passport)
3892
3636
  # photo_on_screen_result = detect_photo_on_screen(self.client, passport)
@@ -3959,24 +3703,6 @@ class IdentityVerification:
3959
3703
  logging.info(f"Empty keys found: {empty_string_keys}")
3960
3704
 
3961
3705
 
3962
- # if passport_data["mrz1"] == "":
3963
- # passport_data["error"] = "cropped_mrz"
3964
- # passport_data["error_details"] = "MRZ1 is null"
3965
-
3966
- # mrz2_pattern = r"^[A-Za-z]{2}\d{7}.*"
3967
-
3968
- # # Check if the extracted text matches the pattern
3969
- # if not (re.match(mrz2_pattern, passport_data["mrz2"])):
3970
- # passport_data["error"] = "invalid mrz"
3971
- # passport_data["error_details"] = "MRZ not present in picture"
3972
-
3973
- # if len(passport_data["mrz2"]) < 43:
3974
- # passport_data["error"] = "cropped_mrz"
3975
- # passport_data["error_details"] = "MRZ not present in picture"
3976
-
3977
- # if not (re.match(mrz2_pattern, passport_data["id_number"])):
3978
- # passport_data["error"] = "id_number_not_found"
3979
- # passport_data["error_details"] = "ID Number not identified."
3980
3706
 
3981
3707
  except Exception as e:
3982
3708
  passport_data["error"] = "bad_image"
@@ -4009,29 +3735,13 @@ class IdentityVerification:
4009
3735
 
4010
3736
  st = time.time()
4011
3737
  compressed_image = BytesIO()
4012
- # TODO
4013
3738
 
4014
- # processed_passport=self.preprocess_image(processed_passport, sharpness=2.0, contrast=1.5, radius=3, percent=180, threshold=5)
4015
- # Enhance image sharpness and contrast.
3739
+
4016
3740
  processed_passport.save(
4017
3741
  compressed_image, format="JPEG", quality=95, optimize=True
4018
3742
  )
4019
3743
  compressed_image_data = compressed_image.getvalue()
4020
- # id_infos = self.get_ocr_results(compressed_image_data, country="SDN")
4021
- # passport_text = id_infos[0].description
4022
- # logging.info(
4023
- # f"----------------Time taken for vision passport: {time.time() - st} seconds\n"
4024
- # )
4025
-
4026
- # pattern4 = r"(Republic of Sudan|Republic of the Sudan|PCSDN|SDN)"
4027
- # k = re.search(pattern4, passport_text, re.IGNORECASE)
4028
-
4029
- # if k:
4030
- # print(f"Keyword feature matches: {k.group()}\n")
4031
-
4032
- # if not k:
4033
- # passport_data["error"] = "not_passport"
4034
- # return passport_data
3744
+
4035
3745
 
4036
3746
  image = np.array(processed_passport)
4037
3747
  if country == "SDN":
@@ -4087,31 +3797,7 @@ class IdentityVerification:
4087
3797
 
4088
3798
  passport_data.update(passport_details)
4089
3799
 
4090
- # mrz1 = passport_data.get('mrz1', '')
4091
-
4092
- # logging.info(f"MRZ1 extracted: {mrz1}")
4093
- # if mrz1:
4094
- # try:
4095
- # mrz1 = mrz1[5:]
4096
- # logging.info(f"Processed MRZ1: {mrz1}")
4097
- # name_mrz = []
4098
- # for word in mrz1.split("<"):
4099
- # if word and word.isalpha():
4100
- # name_mrz.append(word)
4101
-
4102
- # passport_data['name_mrz'] = " ".join(name_mrz)
4103
- # logging.info(f"Name from MRZ1 parts: {name_mrz}")
4104
-
4105
- # name = passport_data.get("full_name_generic", "")
4106
- # name = name.split(" ")
4107
- # from idvpackage.ocr_utils import get_name_match_mrz
4108
- # passport_data['name_match_mrz'] = get_name_match_mrz(name, name_mrz)
4109
- # logging.info(f"name_match_mrz: {passport_data['name_match_mrz']}")
4110
-
4111
- # except Exception as e:
4112
- # logging.info(f"Error in processing Name from MRZ1: {e}")
4113
- # passport_data['name_match_mrz'] = False
4114
- # pass
3800
+
4115
3801
 
4116
3802
 
4117
3803
  from idvpackage.ocr_utils import validation_checks_passport
@@ -4123,63 +3809,7 @@ class IdentityVerification:
4123
3809
  from idvpackage.ocr_utils import get_name_match_mrz
4124
3810
  passport_data['is_name_match_mrz'], passport_data['name_mrz'] = get_name_match_mrz(passport_data, "passport")
4125
3811
 
4126
- # check difference between issue_date and expiry_date should be 10 years
4127
- # check difference between issue_date and expiry_date_mrz should be 10 years
4128
- # check passport_number and passport_number_mrz are same
4129
- # check dob and dob_mrz are same
4130
- # check gender and gender_mrz are same
4131
-
4132
- # checking difference between issue_date and expiry_date for 10 years validity
4133
- # issue_date_str = passport_data.get("issue_date",'')
4134
- # expiry_date_str = passport_data.get("expiry_date",'')
4135
- # expiry_date_mrz_str = passport_data.get("expiry_date_mrz",'')
4136
- # dob_str = passport_data.get("dob",'')
4137
- # dob_mrz_str = passport_data.get("dob_mrz",'')
4138
- # passport_number = passport_data.get("passport_number",'')
4139
- # passport_number_mrz = passport_data.get("passport_number_mrz",'')
4140
-
4141
- # logging.info(f"issue_date_str: {issue_date_str}, expiry_date_str: {expiry_date_str}, expiry_date_mrz_str: {expiry_date_mrz_str}")
4142
- # if issue_date_str and expiry_date_str:
4143
- # try:
4144
- # issue_date_obj = datetime.strptime(issue_date_str, "%d/%m/%Y")
4145
- # expiry_date_obj = datetime.strptime(expiry_date_str, "%d/%m/%Y")
4146
- # logging.info(f"issue_date_obj: {issue_date_obj}, expiry_date_obj: {expiry_date_obj}, difference is : {(expiry_date_obj - issue_date_obj).days}")
4147
-
4148
- # difference_in_days_obj = (expiry_date_obj - issue_date_obj).days
4149
- # passport_data["valid_id_duration"] = difference_in_days_obj in [ 3650, 3651, 3652, 3653]
4150
- # except:
4151
- # logging.info("Error in parsing issue_date or expiry_date from SDN Passport")
4152
- # passport_data["valid_id_duration"] = False
4153
- # pass
4154
3812
 
4155
- # if issue_date_str and expiry_date_mrz_str:
4156
- # try:
4157
-
4158
- # expiry_date_mrz_obj = datetime.strptime(expiry_date_mrz_str, "%d/%m/%Y")
4159
-
4160
- # logging.info(f"issue_date_obj: {issue_date_obj}, expiry_date_mrz_obj: {expiry_date_mrz_obj}, difference is : {(expiry_date_mrz_obj - issue_date_obj).days}")
4161
- # difference_in_days_obj = (expiry_date_mrz_obj - issue_date_obj).days
4162
- # passport_data["valid_id_mrz_duration"] = difference_in_days_obj in [ 3650, 3651, 3652, 3653]
4163
- # except:
4164
- # logging.info("Error in parsing issue_date or expiry_date from SDN Passport")
4165
- # passport_data["valid_id_mrz_duration"] = False
4166
- # pass
4167
-
4168
- # if passport_number and passport_number_mrz:
4169
- # passport_data["is_passport_number_mrz_match"] = passport_number == passport_number_mrz
4170
- # else:
4171
- # passport_data["is_passport_number_mrz_match"] = False
4172
-
4173
- # if dob_str and dob_mrz_str:
4174
- # passport_data["is_dob_mrz_match"] = dob_str == dob_mrz_str
4175
- # else:
4176
- # passport_data["is_dob_mrz_match"] = False
4177
-
4178
- # if passport_data['gender'] and passport_data['gender_mrz']:
4179
- # passport_data["is_gender_mrz_match"] = passport_data['gender'] == passport_data['gender_mrz']
4180
- # else:
4181
- # passport_data["is_gender_mrz_match"] = False
4182
-
4183
3813
  if passport_data.get("issue_date"):
4184
3814
  passport_data["issuance_date"] = passport_details["issue_date"]
4185
3815
 
@@ -4189,11 +3819,9 @@ class IdentityVerification:
4189
3819
  image = np.array(processed_passport)
4190
3820
 
4191
3821
  st = time.time()
4192
- ## TODO: doc_on_pp and detect_photo_on_screen for LBN
4193
- # doc_on_pp_result = document_on_printed_paper(image)
3822
+
4194
3823
  doc_on_pp_result = "clear"
4195
3824
  screenshot_result = detect_screenshot(self.client, passport)
4196
- # photo_on_screen_result = detect_photo_on_screen(self.client, passport)
4197
3825
  photo_on_screen_result = "clear"
4198
3826
  blurred, glare = self.get_blurred_and_glared_for_doc(image)
4199
3827
  valid_nationality_result = self.check_nationality_in_iso_list(