Ajay98 commited on
Commit
13f1448
·
verified ·
1 Parent(s): 395e98b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +122 -111
app.py CHANGED
@@ -1,166 +1,177 @@
1
- from concurrent.futures import ThreadPoolExecutor, as_completed
2
  import os
3
- import time
4
  import json
 
 
 
5
  from google.oauth2 import service_account
6
  from googleapiclient.discovery import build
7
- from googleapiclient.http import MediaIoBaseDownload
8
- import io
9
- import numpy as np
10
 
11
- # Load Google Drive API credentials from the uploaded JSON file
 
 
 
12
  SERVICE_ACCOUNT_FILE = './.env' # Assuming the uploaded JSON file is named '.env'
13
  SCOPES = ['https://www.googleapis.com/auth/drive']
14
 
15
- # Load credentials from the JSON file
16
- with open(SERVICE_ACCOUNT_FILE, 'r') as json_file:
17
- credentials_info = json.load(json_file)
18
-
19
- credentials = service_account.Credentials.from_service_account_info(credentials_info, scopes=SCOPES)
20
- drive_service = build('drive', 'v3', credentials=credentials)
 
 
 
 
 
 
 
 
 
 
 
21
 
22
  # Folder IDs
23
  aadhar_folder_id = '1Qtb5DYzSFE67Mbb5ZgDIqWUtdJaDD2F4'
24
  cphotos_folder_id = '1DGeRqRbCPcfLDdEgP0h5fyX-MF8EQ8AH'
25
  suspects_folder_id = '1N3RMhVD0OygeufLPYod6IYLtqzvlm3Jv'
26
 
27
- MAX_WORKERS = 10
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  def list_files_in_folder(folder_id):
30
- print(f"Listing files in folder ID: {folder_id}")
31
  query = f"'{folder_id}' in parents and trashed=false"
32
  try:
33
  results = drive_service.files().list(q=query, pageSize=1000, fields="files(id, name, mimeType)").execute()
34
  files = results.get('files', [])
35
  if not files:
36
- print(f"No files found in folder ID: {folder_id}. Ensure that the folder has files and the service account has access.")
37
  else:
38
- print(f"Found {len(files)} files in folder ID: {folder_id}.")
39
  return files
40
  except Exception as e:
41
- print(f"Error listing files in folder ID: {folder_id} - {e}")
42
  return []
43
 
44
- # Improved function to batch process images with better face comparison logic
45
- def batch_process_images(aadhar_folder_id, cphotos_folder_id, suspects_folder_id):
46
- start_time = time.time()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
- # Fetch Aadhar and CCTV files
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  aadhar_files = list_files_in_folder(aadhar_folder_id)
50
  cphotos_files = list_files_in_folder(cphotos_folder_id)
51
 
52
- # Extract Aadhar embeddings in parallel
53
  aadhar_embeddings = []
54
- print("Extracting embeddings from Aadhar images...")
55
-
56
- with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
57
- future_to_aadhar = {executor.submit(download_and_extract_embedding_from_memory, file): file for file in aadhar_files}
58
  for future in as_completed(future_to_aadhar):
 
59
  try:
60
- result = future.result()
61
- if result:
62
- file_name, embedding = result
63
- aadhar_embeddings.append(embedding)
 
64
  except Exception as e:
65
- file = future_to_aadhar[future]
66
- print(f"Error processing Aadhar file {file['name']}: {e}")
67
 
68
- # Verify that embeddings were successfully extracted for at least one Aadhar file
69
- if len(aadhar_embeddings) == 0:
70
- print("No valid Aadhar face embeddings found. Exiting.")
71
  return
72
 
73
- # Stack all embeddings for efficient vectorized comparison
74
- aadhar_embeddings = np.vstack(aadhar_embeddings)
75
-
76
- # Process CCTV files and compare with Aadhar embeddings
77
  unmatched_files = []
78
- print("Processing CCTV images and comparing embeddings...")
79
-
80
- with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
81
- future_to_cphoto = {executor.submit(download_and_extract_embedding_from_memory, file): file for file in cphotos_files}
82
  for future in as_completed(future_to_cphoto):
 
83
  try:
84
- result = future.result()
85
- if not result:
86
  continue
87
 
88
- file_name, embedding_cctv = result
 
 
89
 
90
- # Compare CCTV embedding with all Aadhaar embeddings
91
- matched = vectorized_compare_faces_with_embeddings(embedding_cctv, aadhar_embeddings)
92
  if not matched:
93
- unmatched_files.append(file_name)
94
- print(f"Unmatched image queued for upload: {file_name}")
95
  except Exception as e:
96
- file = future_to_cphoto[future]
97
- print(f"Error processing CCTV file {file['name']}: {e}")
98
 
99
- # Upload unmatched files to suspect folder
100
- print("Uploading unmatched images to the suspect folder...")
101
- with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
102
- upload_futures = [executor.submit(upload_file, file_name, suspects_folder_id) for file_name in unmatched_files]
103
  for future in as_completed(upload_futures):
104
  try:
105
  future.result()
106
- print(f"Successfully uploaded unmatched image to suspects folder.")
107
  except Exception as e:
108
- print(f"Error uploading unmatched file: {e}")
109
-
110
- end_time = time.time()
111
- print(f"Total processing time: {end_time - start_time:.2f} seconds.")
112
-
113
- def download_and_extract_embedding_from_memory(file):
114
- """
115
- Download the file in memory and extract its face embedding.
116
- """
117
- file_stream = download_file_in_memory(file['id'])
118
- if file_stream:
119
- embedding = extract_face_embedding_from_stream(file_stream)
120
- if embedding is not None:
121
- return file['name'], embedding
122
- return None
123
-
124
- def download_file_in_memory(file_id):
125
- try:
126
- request = drive_service.files().get_media(fileId=file_id)
127
- file_io = io.BytesIO()
128
- downloader = MediaIoBaseDownload(file_io, request)
129
- done = False
130
- while not done:
131
- _, done = downloader.next_chunk()
132
- file_io.seek(0)
133
- return file_io
134
- except Exception as e:
135
- print(f"Error downloading file ID: {file_id} - {e}")
136
- return None
137
-
138
- def extract_face_embedding_from_stream(file_stream):
139
- try:
140
- image = Image.open(file_stream)
141
- face = mtcnn(image) # Detect and crop the face
142
- if face is not None:
143
- embedding = resnet(face.unsqueeze(0)) # Get the face embedding
144
- return embedding.detach().numpy()
145
- except Exception as e:
146
- print(f"Error extracting face embedding from stream: {e}")
147
- return None
148
-
149
- def vectorized_compare_faces_with_embeddings(embedding_cctv, aadhar_embeddings, threshold=0.75):
150
- """
151
- Compare the given CCTV embedding with a list of Aadhar embeddings in a vectorized manner.
152
- """
153
- similarities = np.dot(aadhar_embeddings, embedding_cctv.T) / (np.linalg.norm(aadhar_embeddings, axis=1) * np.linalg.norm(embedding_cctv))
154
- max_similarity = np.max(similarities)
155
- if max_similarity > threshold:
156
- print(f"Match found: Similarity = {max_similarity:.2f}")
157
- return True
158
- return False
159
 
160
  def main():
161
- print("Script started...")
 
162
  batch_process_images(aadhar_folder_id, cphotos_folder_id, suspects_folder_id)
 
 
163
 
164
  if __name__ == "__main__":
165
- main()
166
-
 
 
1
  import os
 
2
  import json
3
+ import logging
4
+ import time
5
+ from concurrent.futures import ThreadPoolExecutor, as_completed
6
  from google.oauth2 import service_account
7
  from googleapiclient.discovery import build
8
+ from googleapiclient.http import MediaIoBaseDownload, MediaFileUpload
9
+ from PIL import Image
10
+ import torch
11
 
12
+ # Set up logging
13
+ logging.basicConfig(level=logging.DEBUG)
14
+
15
+ # Load Google Drive API credentials
16
  SERVICE_ACCOUNT_FILE = './.env' # Assuming the uploaded JSON file is named '.env'
17
  SCOPES = ['https://www.googleapis.com/auth/drive']
18
 
19
+ try:
20
+ if not os.path.exists(SERVICE_ACCOUNT_FILE):
21
+ logging.error(f"Service account file '{SERVICE_ACCOUNT_FILE}' not found.")
22
+ raise FileNotFoundError(f"Service account file '{SERVICE_ACCOUNT_FILE}' not found.")
23
+
24
+ with open(SERVICE_ACCOUNT_FILE, 'r') as json_file:
25
+ credentials_info = json.load(json_file)
26
+ credentials = service_account.Credentials.from_service_account_info(credentials_info, scopes=SCOPES)
27
+ drive_service = build('drive', 'v3', credentials=credentials)
28
+ logging.debug("Google Drive API credentials loaded successfully.")
29
+ except json.JSONDecodeError as e:
30
+ logging.error(f"Error parsing JSON service account file: {e}")
31
+ except FileNotFoundError as e:
32
+ logging.error(f"Service account file missing: {e}")
33
+ except Exception as e:
34
+ logging.error(f"Unexpected error while loading credentials: {e}")
35
+ raise
36
 
37
  # Folder IDs
38
  aadhar_folder_id = '1Qtb5DYzSFE67Mbb5ZgDIqWUtdJaDD2F4'
39
  cphotos_folder_id = '1DGeRqRbCPcfLDdEgP0h5fyX-MF8EQ8AH'
40
  suspects_folder_id = '1N3RMhVD0OygeufLPYod6IYLtqzvlm3Jv'
41
 
42
+ # Lazy loaded models (initialized only when needed)
43
+ mtcnn = None
44
+ resnet = None
45
+
46
+ def initialize_models():
47
+ global mtcnn, resnet
48
+ if mtcnn is None or resnet is None:
49
+ logging.debug("Loading face detection and recognition models...")
50
+ from facenet_pytorch import MTCNN, InceptionResnetV1
51
+ mtcnn = MTCNN(image_size=160, margin=0, min_face_size=20)
52
+ resnet = InceptionResnetV1(pretrained='vggface2').eval()
53
+ logging.debug("Models loaded successfully.")
54
 
55
  def list_files_in_folder(folder_id):
56
+ logging.debug(f"Listing files in folder ID: {folder_id}")
57
  query = f"'{folder_id}' in parents and trashed=false"
58
  try:
59
  results = drive_service.files().list(q=query, pageSize=1000, fields="files(id, name, mimeType)").execute()
60
  files = results.get('files', [])
61
  if not files:
62
+ logging.warning(f"No files found in folder ID: {folder_id}. Ensure that the folder has files and the service account has access.")
63
  else:
64
+ logging.debug(f"Found {len(files)} files in folder ID: {folder_id}.")
65
  return files
66
  except Exception as e:
67
+ logging.error(f"Error listing files in folder ID: {folder_id} - {e}")
68
  return []
69
 
70
+ def download_file(file_id, file_name):
71
+ logging.debug(f"Attempting to download file: {file_name} (ID: {file_id})")
72
+ if not file_name.lower().endswith(('.jpg', '.jpeg', '.png')):
73
+ file_name += ".jpg"
74
+ try:
75
+ request = drive_service.files().get_media(fileId=file_id)
76
+ file_io = io.BytesIO()
77
+ downloader = MediaIoBaseDownload(file_io, request)
78
+ done = False
79
+ while not done:
80
+ _, done = downloader.next_chunk()
81
+ file_io.seek(0)
82
+ with open(file_name, 'wb') as f:
83
+ f.write(file_io.read())
84
+ logging.debug(f"Successfully downloaded file: {file_name}")
85
+ return file_name
86
+ except Exception as e:
87
+ logging.error(f"Error downloading file ID: {file_id} - {e}")
88
+ return None
89
 
90
+ def extract_face_embedding(image_path):
91
+ try:
92
+ initialize_models() # Load models if not already loaded
93
+ image = Image.open(image_path)
94
+ face = mtcnn(image)
95
+ if face is not None:
96
+ embedding = resnet(face.unsqueeze(0))
97
+ return embedding
98
+ else:
99
+ logging.warning(f"No face detected in image: {image_path}")
100
+ return None
101
+ except Exception as e:
102
+ logging.error(f"Error extracting face embedding for {image_path}. Error: {e}")
103
+ return None
104
+
105
+ def calculate_similarity(embedding1, embedding2):
106
+ return torch.nn.functional.cosine_similarity(embedding1, embedding2).item()
107
+
108
+ def compare_faces_with_embeddings(embedding_cctv, aadhar_embeddings, threshold=0.7):
109
+ for aadhar_name, aadhar_embedding in aadhar_embeddings:
110
+ similarity = calculate_similarity(embedding_cctv, aadhar_embedding)
111
+ if similarity > threshold:
112
+ logging.info(f"Match found: Similarity = {similarity:.2f} with Aadhar file: {aadhar_name}")
113
+ return True
114
+ return False
115
+
116
+ def batch_process_images(aadhar_folder_id, cphotos_folder_id, suspects_folder_id):
117
+ logging.debug("Starting processing of images...")
118
  aadhar_files = list_files_in_folder(aadhar_folder_id)
119
  cphotos_files = list_files_in_folder(cphotos_folder_id)
120
 
 
121
  aadhar_embeddings = []
122
+ with ThreadPoolExecutor() as executor:
123
+ future_to_aadhar = {executor.submit(download_file, file['id'], file['name']): file for file in aadhar_files}
 
 
124
  for future in as_completed(future_to_aadhar):
125
+ file = future_to_aadhar[future]
126
  try:
127
+ file_path = future.result()
128
+ if file_path:
129
+ embedding = extract_face_embedding(file_path)
130
+ if embedding is not None:
131
+ aadhar_embeddings.append((file['name'], embedding))
132
  except Exception as e:
133
+ logging.error(f"Error processing Aadhar file {file['name']}: {e}")
 
134
 
135
+ if not aadhar_embeddings:
136
+ logging.warning("No valid Aadhar face embeddings found. Exiting.")
 
137
  return
138
 
 
 
 
 
139
  unmatched_files = []
140
+ with ThreadPoolExecutor() as executor:
141
+ future_to_cphoto = {executor.submit(download_file, file['id'], file['name']): file for file in cphotos_files}
 
 
142
  for future in as_completed(future_to_cphoto):
143
+ file = future_to_cphoto[future]
144
  try:
145
+ file_path = future.result()
146
+ if not file_path:
147
  continue
148
 
149
+ embedding_cctv = extract_face_embedding(file_path)
150
+ if embedding_cctv is None:
151
+ continue
152
 
153
+ matched = compare_faces_with_embeddings(embedding_cctv, aadhar_embeddings)
 
154
  if not matched:
155
+ unmatched_files.append(file_path)
156
+ logging.info(f"Unmatched image queued for upload: {file['name']}")
157
  except Exception as e:
158
+ logging.error(f"Error processing CCTV file {file['name']}: {e}")
 
159
 
160
+ with ThreadPoolExecutor() as executor:
161
+ upload_futures = [executor.submit(upload_file, file_path, suspects_folder_id) for file_path in unmatched_files]
 
 
162
  for future in as_completed(upload_futures):
163
  try:
164
  future.result()
165
+ logging.info(f"Successfully uploaded unmatched image to suspects folder.")
166
  except Exception as e:
167
+ logging.error(f"Error uploading unmatched file: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
 
169
  def main():
170
+ start_time = time.time()
171
+ logging.debug("Script started...")
172
  batch_process_images(aadhar_folder_id, cphotos_folder_id, suspects_folder_id)
173
+ end_time = time.time()
174
+ logging.debug(f"Script completed in {end_time - start_time:.2f} seconds.")
175
 
176
  if __name__ == "__main__":
177
+ main()