c-luis-e commited on
Commit
eda81ca
Β·
verified Β·
1 Parent(s): 1e16ba1

Update verifier.py

Browse files
Files changed (1) hide show
  1. verifier.py +76 -11
verifier.py CHANGED
@@ -7,14 +7,30 @@ warnings.filterwarnings('ignore')
7
 
8
  class AIFRKTPVerification:
9
  def __init__(self):
 
 
 
10
  print("πŸš€ Initializing AIFR KTP Verification System...")
 
11
  self.app = FaceAnalysis(name='buffalo_l',
12
  root='/tmp',
13
  providers=['CPUExecutionProvider'])
14
  self.app.prepare(ctx_id=0, det_size=(640, 640))
15
- self.thresholds = {'normal': 0.45}
 
 
 
 
 
 
16
 
17
  def preprocess_ktp_image(self, image):
 
 
 
 
 
 
18
  lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
19
  l, a, b = cv2.split(lab)
20
  a = cv2.normalize(a, None, 0, 255, cv2.NORM_MINMAX)
@@ -27,38 +43,87 @@ class AIFRKTPVerification:
27
  return corrected
28
 
29
  def extract_age_invariant_features(self, image):
 
 
 
30
  faces = self.app.get(image)
31
  if len(faces) == 0:
32
  print("⚠️ No face detected!")
33
  return None, None
 
34
  face = faces[0]
35
- return face.normed_embedding, face.kps
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
- def calculate_similarity(self, embed1, embed2):
38
- return 1 - cosine(embed1, embed2), 1 - cosine(embed1, embed2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
  def verify_with_images(self, ktp_image, selfie_image):
 
 
 
 
41
  print("\nπŸ”§ Preprocessing images for API call...")
42
  ktp_processed = self.preprocess_ktp_image(ktp_image)
43
  selfie_processed = cv2.normalize(selfie_image, None, 0, 255, cv2.NORM_MINMAX)
44
 
45
  print("🧠 Extracting age-invariant features...")
46
- ktp_embedding, _ = self.extract_age_invariant_features(ktp_processed)
47
- selfie_embedding, _ = self.extract_age_invariant_features(selfie_processed)
48
 
49
  if ktp_embedding is None or selfie_embedding is None:
50
  return {'error': 'Could not detect a face in one or both images.'}
51
 
52
  print("πŸ“Š Calculating similarity...")
53
- similarity, deep_similarity = self.calculate_similarity(ktp_embedding, selfie_embedding)
 
 
54
 
55
  normal_threshold = self.thresholds['normal']
56
  verified = bool(similarity > normal_threshold)
57
 
58
- print(f"βœ… Verification complete. Score: {similarity:.4f}")
59
  return {
60
  'verified': verified,
61
- 'similarity_score': float(similarity),
62
- 'deep_feature_similarity': float(deep_similarity),
63
  'threshold': normal_threshold
64
- }
 
7
 
8
  class AIFRKTPVerification:
9
  def __init__(self):
10
+ """
11
+ Initialize Age-Invariant Face Recognition system specifically for KTP verification
12
+ """
13
  print("πŸš€ Initializing AIFR KTP Verification System...")
14
+ # Initialize InsightFace with ArcFace model (best for age-invariant features)
15
  self.app = FaceAnalysis(name='buffalo_l',
16
  root='/tmp',
17
  providers=['CPUExecutionProvider'])
18
  self.app.prepare(ctx_id=0, det_size=(640, 640))
19
+ # Thresholds specifically calibrated for ID-to-selfie comparison
20
+ self.thresholds = {
21
+ 'strict': 0.35,
22
+ 'normal': 0.45,
23
+ 'relaxed': 0.55,
24
+ 'very_relaxed': 0.65
25
+ }
26
 
27
  def preprocess_ktp_image(self, image):
28
+ """
29
+ Special preprocessing for Indonesian KTP photos
30
+ - Remove red/orange tint
31
+ - Enhance contrast
32
+ - Normalize lighting
33
+ """
34
  lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
35
  l, a, b = cv2.split(lab)
36
  a = cv2.normalize(a, None, 0, 255, cv2.NORM_MINMAX)
 
43
  return corrected
44
 
45
  def extract_age_invariant_features(self, image):
46
+ """
47
+ Extracts both deep embedding and geometric features from the face.
48
+ """
49
  faces = self.app.get(image)
50
  if len(faces) == 0:
51
  print("⚠️ No face detected!")
52
  return None, None
53
+
54
  face = faces[0]
55
+ embedding = face.normed_embedding # 512-dimensional embedding
56
+ landmarks = face.kps # Keypoints for geometric features
57
+
58
+ geometric_features = None
59
+ if landmarks is not None and len(landmarks) >= 5:
60
+ try:
61
+ # Eye distance ratio (doesn't change much with age)
62
+ eye_distance = np.linalg.norm(landmarks[0] - landmarks[1])
63
+ # Nose to eye center distance
64
+ eye_center = (landmarks[0] + landmarks[1]) / 2
65
+ nose_distance = np.linalg.norm(landmarks[2] - eye_center)
66
+ # Face width estimation (using jawline points if available)
67
+ face_width = np.linalg.norm(landmarks[3] - landmarks[4])
68
+
69
+ # Create a stable geometric feature vector
70
+ if face_width > 0 and nose_distance > 0:
71
+ geometric_features = np.array([
72
+ eye_distance / face_width,
73
+ nose_distance / face_width,
74
+ eye_distance / nose_distance
75
+ ])
76
+ except Exception as e:
77
+ print(f"Could not calculate geometric features: {e}")
78
+ geometric_features = None
79
 
80
+ return embedding, geometric_features
81
+
82
+ def calculate_similarity(self, embed1, embed2, geom1=None, geom2=None):
83
+ """
84
+ Calculates similarity using a weighted average of deep and geometric features.
85
+ """
86
+ # Deep feature similarity (main metric)
87
+ deep_similarity = 1 - cosine(embed1, embed2)
88
+
89
+ # Geometric similarity (supplementary)
90
+ if geom1 is not None and geom2 is not None:
91
+ geom_similarity = 1 - cosine(geom1, geom2)
92
+ # Weighted combination (80% deep, 20% geometric)
93
+ final_similarity = 0.8 * deep_similarity + 0.2 * geom_similarity
94
+ else:
95
+ final_similarity = deep_similarity
96
+
97
+ return final_similarity, deep_similarity
98
 
99
  def verify_with_images(self, ktp_image, selfie_image):
100
+ """
101
+ Main verification function that accepts image objects instead of file paths.
102
+ This is the method the API will call.
103
+ """
104
  print("\nπŸ”§ Preprocessing images for API call...")
105
  ktp_processed = self.preprocess_ktp_image(ktp_image)
106
  selfie_processed = cv2.normalize(selfie_image, None, 0, 255, cv2.NORM_MINMAX)
107
 
108
  print("🧠 Extracting age-invariant features...")
109
+ ktp_embedding, ktp_geom = self.extract_age_invariant_features(ktp_processed)
110
+ selfie_embedding, selfie_geom = self.extract_age_invariant_features(selfie_processed)
111
 
112
  if ktp_embedding is None or selfie_embedding is None:
113
  return {'error': 'Could not detect a face in one or both images.'}
114
 
115
  print("πŸ“Š Calculating similarity...")
116
+ similarity, deep_similarity = self.calculate_similarity(
117
+ ktp_embedding, selfie_embedding, ktp_geom, selfie_geom
118
+ )
119
 
120
  normal_threshold = self.thresholds['normal']
121
  verified = bool(similarity > normal_threshold)
122
 
123
+ print(f"βœ… Verification complete. Weighted Score: {similarity:.4f}")
124
  return {
125
  'verified': verified,
126
+ 'similarity_score': float(similarity), # This is the weighted score
127
+ 'deep_feature_similarity': float(deep_similarity), # This is the pure AI score
128
  'threshold': normal_threshold
129
+ }