yougandar commited on
Commit
e3c7de3
·
verified ·
1 Parent(s): 8d2078f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +90 -26
app.py CHANGED
@@ -1,39 +1,103 @@
 
 
 
 
1
  import gradio as gr
2
  import cv2
3
- import os
4
- from detect_people import detect_people
5
- from table_occupancy import check_seating
 
6
  from face_utils import recognize_faces
7
- from db import get_table_status, log_customer_visit, get_alerts
8
- from datetime import datetime
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
  def process_frame(image):
11
- # 1. Detect people
12
- people_count = detect_people(image)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
- # 2. Check seating
15
- seated = check_seating(image)
16
 
17
- # 3. Face recognition
18
- faces = recognize_faces(image, db_path="faces_db")
19
 
20
- # 4. Log to DB (only if real faces found)
21
- timestamp = datetime.utcnow().isoformat()
22
- for f in faces:
23
- if f != "Unknown" and not f.startswith("Error"):
24
- log_customer_visit(f, timestamp, table_id=1)
25
 
26
- # 5. Alerts from DB
27
- alerts = get_alerts()
 
28
 
29
- return f"People: {people_count}, Seated: {seated}, Faces: {faces}, Alerts: {alerts}"
 
30
 
31
- demo = gr.Interface(
32
- fn=process_frame,
33
- inputs=gr.Image(type="filepath"),
34
- outputs="text",
35
- title="Restaurant Monitor"
36
- )
37
 
38
  if __name__ == "__main__":
39
- demo.launch()
 
 
1
+ import os
2
+ import time
3
+ from datetime import datetime
4
+
5
  import gradio as gr
6
  import cv2
7
+ import numpy as np
8
+
9
+ from detect_people import detect_people_yolo
10
+ from table_occupancy import estimate_table_occupancy
11
  from face_utils import recognize_faces
12
+ from db import get_table_status, log_customer_visit, get_alerts, db_enabled
13
+
14
+ # ---------- Tunables via env ----------
15
+ CONF_THRESH = float(os.getenv("PEOPLE_CONF_THRESH", "0.55"))
16
+ NMS_THRESH = float(os.getenv("PEOPLE_NMS_THRESH", "0.45"))
17
+ MAX_SIDE = int(os.getenv("PEOPLE_MAX_SIDE", "1280")) # resize safeguard
18
+ FACES_DIR = os.getenv("FACES_DIR", "faces_db") # faces gallery path
19
+ TOPK = int(os.getenv("FACE_TOPK", "3")) # max matches to show
20
+ ENABLE_FACES = os.getenv("ENABLE_FACES", "1") == "1"
21
+ # --------------------------------------
22
+
23
+ def _safe_resize(frame, max_side=1280):
24
+ h, w = frame.shape[:2]
25
+ m = max(h, w)
26
+ if m <= max_side:
27
+ return frame
28
+ scale = max_side / m
29
+ return cv2.resize(frame, (int(w*scale), int(h*scale)))
30
 
31
  def process_frame(image):
32
+ """
33
+ image: np.ndarray (H, W, 3) from gr.Image
34
+ Returns: (annotated_frame, text_status)
35
+ """
36
+ if image is None:
37
+ return None, "No frame."
38
+
39
+ frame = _safe_resize(image, MAX_SIDE)
40
+
41
+ # 1) People detection (OpenCV DNN YOLOv4-tiny)
42
+ people, boxes, confs, annotated = detect_people_yolo(
43
+ frame, conf_thresh=CONF_THRESH, nms_thresh=NMS_THRESH, draw=True
44
+ )
45
+ people_count = len(people)
46
+
47
+ # 2) Table occupancy (simple heuristic; customize as needed)
48
+ seated = estimate_table_occupancy(people_count)
49
+
50
+ # 3) Face recognition (optional & robust)
51
+ face_text = "Disabled"
52
+ if ENABLE_FACES:
53
+ try:
54
+ matches = recognize_faces(frame, FACES_DIR, topk=TOPK)
55
+ if isinstance(matches, str):
56
+ face_text = matches # a friendly warning string
57
+ else:
58
+ # pretty print topk names with avg distance
59
+ if len(matches) == 0:
60
+ face_text = "No known faces"
61
+ else:
62
+ face_text = ", ".join(
63
+ [f"{m['name']} ({m['score']:.2f})" for m in matches[:TOPK]]
64
+ )
65
+ except Exception as e:
66
+ face_text = f"Error: {e}"
67
+
68
+ # 4) DB (optional / won’t crash if missing)
69
+ db_text = "DB disabled"
70
+ if db_enabled():
71
+ try:
72
+ # log a single event to show it works (you can wire to your business logic)
73
+ log_customer_visit(face_text if isinstance(face_text, str) else "faces", datetime.utcnow(), table_id=1)
74
+ alerts = get_alerts()
75
+ if alerts:
76
+ db_text = f"Alerts: {alerts}"
77
+ else:
78
+ db_text = "Alerts: none"
79
+ except Exception as e:
80
+ db_text = f"DB error: {e}"
81
 
82
+ status = f"People: {people_count}, Seated: {bool(seated)}, Face Match: {face_text}, {db_text}"
83
+ return annotated[:, :, ::-1], status # convert BGR->RGB for display
84
 
85
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
86
+ gr.Markdown("## CCTV Backend – People Count, Table Occupancy & Face Match (CPU-only)")
87
 
88
+ with gr.Row():
89
+ inp = gr.Image(type="numpy", label="Frame (image or snapshot)")
 
 
 
90
 
91
+ with gr.Row():
92
+ out_img = gr.Image(type="numpy", label="Detections", interactive=False)
93
+ out_txt = gr.Textbox(label="Status", interactive=False)
94
 
95
+ btn = gr.Button("Process")
96
+ btn.click(process_frame, inputs=[inp], outputs=[out_img, out_txt])
97
 
98
+ # Also auto-run when user drops an image
99
+ inp.change(process_frame, inputs=[inp], outputs=[out_img, out_txt])
 
 
 
 
100
 
101
  if __name__ == "__main__":
102
+ # Gradio SSR sometimes logs warnings; keep defaults minimal for Spaces
103
+ demo.launch(server_name="0.0.0.0", server_port=7860)