sreenathsree1578 commited on
Commit
b04bf65
·
verified ·
1 Parent(s): 5f14ef7

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +108 -56
src/streamlit_app.py CHANGED
@@ -11,16 +11,16 @@ from typing import Tuple, List, Dict, Any
11
  import h5py
12
  from huggingface_hub import hf_hub_download
13
  import urllib.request
14
- import traceback
15
  import logging
16
 
17
  # Set up logging
18
  logging.basicConfig(level=logging.INFO)
19
  logger = logging.getLogger(__name__)
20
 
21
- # Force OpenCV to use headless backend
 
 
22
  os.environ["OPENCV_HEADLESS"] = "1"
23
- cv2.ocl.setUseOpenCL(False)
24
 
25
  # Set TensorFlow to use CPU only
26
  try:
@@ -168,11 +168,12 @@ st.markdown("""
168
  # Global variables for model and processor
169
  model = None
170
  face_cascade = None
 
171
  model_input_size = (128, 128) # From model config
172
  class_names = ['Mask', 'No Mask'] # From model config
173
  model_loaded = False
174
  face_detector_loaded = False
175
- use_fallback_detector = False
176
 
177
  def download_haarcascade():
178
  """Download the Haar cascade file if it doesn't exist."""
@@ -190,6 +191,25 @@ def download_haarcascade():
190
  return False
191
  return True
192
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  def load_model() -> Any:
194
  """Load the Keras face mask detection model from Hugging Face with enhanced error handling."""
195
  global model, model_loaded
@@ -244,14 +264,16 @@ def load_model() -> Any:
244
  return model
245
 
246
  def load_face_detector():
247
- """Load OpenCV's Haar cascade for face detection."""
248
- global face_cascade, face_detector_loaded, use_fallback_detector
249
- if face_cascade is None:
250
- # First download the Haar cascade file if needed
 
 
251
  if not download_haarcascade():
252
- face_detector_loaded = False
253
- use_fallback_detector = True
254
- return False
255
 
256
  try:
257
  # Load the pre-trained Haar cascade classifier from local file
@@ -259,51 +281,36 @@ def load_face_detector():
259
 
260
  # Check if the cascade was loaded successfully
261
  if face_cascade.empty():
262
- face_detector_loaded = False
263
- use_fallback_detector = True
264
- return False
265
 
266
  face_detector_loaded = True
267
- use_fallback_detector = False
268
  return True
269
  except Exception as e:
270
- logger.error(f"Error loading face detector: {e}")
271
- face_detector_loaded = False
272
- use_fallback_detector = True
273
- return False
274
- return True
275
-
276
- def detect_faces_fallback(image: np.ndarray) -> List[Tuple[int, int, int, int]]:
277
- """Fallback face detection using simple image processing."""
278
- # Convert to grayscale
279
- gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
280
-
281
- # Apply Gaussian blur to reduce noise
282
- blurred = cv2.GaussianBlur(gray, (5, 5), 0)
283
-
284
- # Apply thresholding to get a binary image
285
- _, thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
286
 
287
- # Find contours in the binary image
288
- contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
289
-
290
- # Filter contours based on size and aspect ratio to find potential faces
291
- faces = []
292
- for contour in contours:
293
- # Get bounding rectangle
294
- x, y, w, h = cv2.boundingRect(contour)
295
-
296
- # Filter based on size and aspect ratio
297
- if w > 30 and h > 30 and 0.7 < w/h < 1.3:
298
- faces.append((x, y, w, h))
299
 
300
- return faces
 
 
 
 
 
 
 
 
 
301
 
302
- def detect_faces(image: np.ndarray) -> List[Tuple[int, int, int, int]]:
303
- """Detect faces in the image using Haar cascade or fallback method."""
304
- if use_fallback_detector or not face_detector_loaded:
305
- return detect_faces_fallback(image)
306
-
307
  # Convert to grayscale for face detection
308
  gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
309
 
@@ -319,6 +326,42 @@ def detect_faces(image: np.ndarray) -> List[Tuple[int, int, int, int]]:
319
  # Convert to list of tuples (x, y, w, h)
320
  return [(x, y, w, h) for (x, y, w, h) in faces]
321
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
  def preprocess_image(image: np.ndarray) -> np.ndarray:
323
  """Preprocess image for model inference."""
324
  # Resize to model input size
@@ -500,8 +543,8 @@ def main():
500
  load_face_detector()
501
 
502
  # Check if models loaded successfully
503
- if not model_loaded:
504
- st.error("Failed to load the model. Please check the files and try again.")
505
 
506
  # Additional debugging information
507
  st.markdown("---")
@@ -510,7 +553,7 @@ def main():
510
  st.write("**Current Directory:**", os.getcwd())
511
  st.write("**Files in Directory:**")
512
  for file in os.listdir():
513
- if file.endswith(('.h5', '.keras', '.xml')):
514
  st.write(f"- {file}")
515
 
516
  # Show system information
@@ -544,6 +587,15 @@ def main():
544
  st.write(f"\n**Haar Cascade File Information:**")
545
  st.write(f"- File exists: No")
546
 
 
 
 
 
 
 
 
 
 
547
  return
548
 
549
  # Sidebar
@@ -670,10 +722,10 @@ def main():
670
  # Show face detector status
671
  st.markdown("---")
672
  st.markdown('<h3 class="sidebar-title">🔍 Face Detector Status</h3>', unsafe_allow_html=True)
673
- if use_fallback_detector:
674
- st.warning("Using fallback face detection method. Accuracy may be reduced.")
675
  else:
676
- st.success("Using Haar cascade face detection.")
677
 
678
  # System information at the bottom
679
  st.markdown("---")
@@ -688,7 +740,7 @@ def main():
688
  """.format(
689
  tf_version=tf.__version__,
690
  model_name="mask_detection_model.h5",
691
- detector_status="Fallback" if use_fallback_detector else ("Loaded" if face_detector_loaded else "Failed to load")
692
  ), unsafe_allow_html=True)
693
 
694
  # Footer
 
11
  import h5py
12
  from huggingface_hub import hf_hub_download
13
  import urllib.request
 
14
  import logging
15
 
16
  # Set up logging
17
  logging.basicConfig(level=logging.INFO)
18
  logger = logging.getLogger(__name__)
19
 
20
+ # Set environment variables for headless operation
21
+ os.environ["DISPLAY"] = ":0"
22
+ os.environ["QT_QPA_PLATFORM"] = "offscreen"
23
  os.environ["OPENCV_HEADLESS"] = "1"
 
24
 
25
  # Set TensorFlow to use CPU only
26
  try:
 
168
  # Global variables for model and processor
169
  model = None
170
  face_cascade = None
171
+ dnn_net = None
172
  model_input_size = (128, 128) # From model config
173
  class_names = ['Mask', 'No Mask'] # From model config
174
  model_loaded = False
175
  face_detector_loaded = False
176
+ use_dnn_detector = False
177
 
178
  def download_haarcascade():
179
  """Download the Haar cascade file if it doesn't exist."""
 
191
  return False
192
  return True
193
 
194
+ def download_dnn_model():
195
+ """Download the DNN face detection model files."""
196
+ model_files = {
197
+ "deploy.prototxt": "https://raw.githubusercontent.com/opencv/opencv/master/samples/dnn/face_detector/deploy.prototxt",
198
+ "res10_300x300_ssd_iter_140000.caffemodel": "https://raw.githubusercontent.com/opencv/opencv_3rdparty/dnn_samples_face_detector_20170830/res10_300x300_ssd_iter_140000.caffemodel"
199
+ }
200
+
201
+ all_downloaded = True
202
+ for filename, url in model_files.items():
203
+ if not os.path.exists(filename):
204
+ try:
205
+ with st.spinner(f"Downloading {filename}..."):
206
+ urllib.request.urlretrieve(url, filename)
207
+ st.success(f"{filename} downloaded successfully!")
208
+ except Exception as e:
209
+ st.error(f"Failed to download {filename}: {str(e)}")
210
+ all_downloaded = False
211
+ return all_downloaded
212
+
213
  def load_model() -> Any:
214
  """Load the Keras face mask detection model from Hugging Face with enhanced error handling."""
215
  global model, model_loaded
 
264
  return model
265
 
266
  def load_face_detector():
267
+ """Load OpenCV's Haar cascade or DNN face detector."""
268
+ global face_cascade, dnn_net, face_detector_loaded, use_dnn_detector
269
+
270
+ # First try to load Haar cascade
271
+ if not use_dnn_detector:
272
+ # Download the Haar cascade file if needed
273
  if not download_haarcascade():
274
+ logger.info("Haar cascade download failed, trying DNN detector")
275
+ use_dnn_detector = True
276
+ return load_face_detector()
277
 
278
  try:
279
  # Load the pre-trained Haar cascade classifier from local file
 
281
 
282
  # Check if the cascade was loaded successfully
283
  if face_cascade.empty():
284
+ logger.info("Haar cascade is empty, trying DNN detector")
285
+ use_dnn_detector = True
286
+ return load_face_detector()
287
 
288
  face_detector_loaded = True
289
+ use_dnn_detector = False
290
  return True
291
  except Exception as e:
292
+ logger.error(f"Error loading Haar cascade: {e}")
293
+ use_dnn_detector = True
294
+ return load_face_detector()
 
 
 
 
 
 
 
 
 
 
 
 
 
295
 
296
+ # If we're here, we need to use the DNN detector
297
+ if not download_dnn_model():
298
+ face_detector_loaded = False
299
+ return False
 
 
 
 
 
 
 
 
300
 
301
+ try:
302
+ # Load the DNN model
303
+ dnn_net = cv2.dnn.readNetFromCaffe("deploy.prototxt", "res10_300x300_ssd_iter_140000.caffemodel")
304
+ face_detector_loaded = True
305
+ use_dnn_detector = True
306
+ return True
307
+ except Exception as e:
308
+ logger.error(f"Error loading DNN model: {e}")
309
+ face_detector_loaded = False
310
+ return False
311
 
312
+ def detect_faces_haar(image: np.ndarray) -> List[Tuple[int, int, int, int]]:
313
+ """Detect faces using Haar cascade."""
 
 
 
314
  # Convert to grayscale for face detection
315
  gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
316
 
 
326
  # Convert to list of tuples (x, y, w, h)
327
  return [(x, y, w, h) for (x, y, w, h) in faces]
328
 
329
+ def detect_faces_dnn(image: np.ndarray) -> List[Tuple[int, int, int, int]]:
330
+ """Detect faces using DNN model."""
331
+ # Get image dimensions
332
+ (h, w) = image.shape[:2]
333
+
334
+ # Create a blob from the image
335
+ blob = cv2.dnn.blobFromImage(cv2.resize(image, (300, 300)), 1.0, (300, 300), (104.0, 177.0, 123.0))
336
+
337
+ # Pass the blob through the network and get the detections
338
+ dnn_net.setInput(blob)
339
+ detections = dnn_net.forward()
340
+
341
+ faces = []
342
+ # Loop over the detections
343
+ for i in range(0, detections.shape[2]):
344
+ # Extract the confidence (i.e., probability) associated with the prediction
345
+ confidence = detections[0, 0, i, 2]
346
+
347
+ # Filter out weak detections by ensuring the confidence is greater than a minimum threshold
348
+ if confidence > 0.5:
349
+ # Compute the (x, y)-coordinates of the bounding box for the object
350
+ box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
351
+ (startX, startY, endX, endY) = box.astype("int")
352
+
353
+ # Add to faces list
354
+ faces.append((startX, startY, endX - startX, endY - startY))
355
+
356
+ return faces
357
+
358
+ def detect_faces(image: np.ndarray) -> List[Tuple[int, int, int, int]]:
359
+ """Detect faces in the image using Haar cascade or DNN method."""
360
+ if use_dnn_detector:
361
+ return detect_faces_dnn(image)
362
+ else:
363
+ return detect_faces_haar(image)
364
+
365
  def preprocess_image(image: np.ndarray) -> np.ndarray:
366
  """Preprocess image for model inference."""
367
  # Resize to model input size
 
543
  load_face_detector()
544
 
545
  # Check if models loaded successfully
546
+ if not model_loaded or not face_detector_loaded:
547
+ st.error("Failed to load the model or face detector. Please check the files and try again.")
548
 
549
  # Additional debugging information
550
  st.markdown("---")
 
553
  st.write("**Current Directory:**", os.getcwd())
554
  st.write("**Files in Directory:**")
555
  for file in os.listdir():
556
+ if file.endswith(('.h5', '.keras', '.xml', '.prototxt', '.caffemodel')):
557
  st.write(f"- {file}")
558
 
559
  # Show system information
 
587
  st.write(f"\n**Haar Cascade File Information:**")
588
  st.write(f"- File exists: No")
589
 
590
+ # Check DNN model files
591
+ dnn_files = ["deploy.prototxt", "res10_300x300_ssd_iter_140000.caffemodel"]
592
+ st.write(f"\n**DNN Model Files Information:**")
593
+ for file in dnn_files:
594
+ if os.path.exists(file):
595
+ st.write(f"- {file}: Exists ({os.path.getsize(file) / (1024*1024):.2f} MB)")
596
+ else:
597
+ st.write(f"- {file}: Not found")
598
+
599
  return
600
 
601
  # Sidebar
 
722
  # Show face detector status
723
  st.markdown("---")
724
  st.markdown('<h3 class="sidebar-title">🔍 Face Detector Status</h3>', unsafe_allow_html=True)
725
+ if use_dnn_detector:
726
+ st.success("Using DNN face detection (more accurate)")
727
  else:
728
+ st.success("Using Haar cascade face detection (faster)")
729
 
730
  # System information at the bottom
731
  st.markdown("---")
 
740
  """.format(
741
  tf_version=tf.__version__,
742
  model_name="mask_detection_model.h5",
743
+ detector_status="DNN" if use_dnn_detector else ("Haar Cascade" if face_detector_loaded else "Failed to load")
744
  ), unsafe_allow_html=True)
745
 
746
  # Footer