Sanshruth commited on
Commit
ac55573
·
verified ·
1 Parent(s): a8054b3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +111 -169
app.py CHANGED
@@ -1,179 +1,126 @@
1
- # Maximize performance settings
2
  import multiprocessing
3
  import cv2
4
 
5
- # Configure OpenCV for multi-core processing
6
  cv2.setNumThreads(multiprocessing.cpu_count())
7
 
8
  ##############
9
- import torch
10
  import gradio as gr
11
  import numpy as np
12
  from PIL import Image, ImageDraw
13
  from ultralytics import YOLO
14
  import logging
15
- import time
16
 
17
- # Configure logging
18
  logging.basicConfig(level=logging.INFO)
19
  logger = logging.getLogger(__name__)
20
 
21
- # Global variables for line coordinates
22
- line_params = None
23
- model = None
24
-
25
- def initialize_yolov11():
26
- """Initialize YOLOv11 model with error handling"""
27
- global model
28
- try:
29
- model = YOLO('yolov11n.pt') # Make sure this model file exists
30
- if torch.cuda.is_available():
31
- model.to('cuda')
32
- logger.info("YOLOv11 initialized with CUDA acceleration")
33
- else:
34
- logger.info("YOLOv11 initialized with CPU")
35
- return True
36
- except Exception as e:
37
- logger.error(f"Model initialization failed: {str(e)}")
38
- return False
39
 
40
  def extract_first_frame(stream_url):
41
- """Robust frame extraction with retries"""
42
- for _ in range(3): # Retry up to 3 times
43
- cap = cv2.VideoCapture(stream_url)
44
- if cap.isOpened():
45
- ret, frame = cap.read()
46
- cap.release()
47
- if ret:
48
- return cv2.cvtColor(frame, cv2.COLOR_BGR2RGB), "First frame extracted"
49
- time.sleep(1) # Wait before retry
50
- return None, "Error: Failed to capture initial frame"
 
 
51
 
52
  def update_line(image, evt: gr.SelectData):
53
- """Optimized line drawing with validation"""
54
- global line_params
55
-
56
- if not hasattr(image, 'points'):
57
- image.points = []
58
 
59
- if len(image.points) < 2:
60
- image.points.append((evt.index[0], evt.index[1]))
61
- draw = ImageDraw.Draw(image)
62
- color = "blue" if len(image.points) == 1 else "green"
63
- draw.ellipse([evt.index[0]-5, evt.index[1]-5, evt.index[0]+5, evt.index[1]+5],
64
- fill=color, outline=color)
65
-
66
- if len(image.points) == 2:
67
- x1, y1 = image.points[0]
68
- x2, y2 = image.points[1]
69
  draw = ImageDraw.Draw(image)
70
- draw.line([(x1,y1), (x2,y2)], fill="red", width=2)
71
-
72
- # Store line parameters
73
- if x2 - x1 != 0:
74
- slope = (y2 - y1) / (x2 - x1)
75
- intercept = y1 - slope * x1
76
- else:
77
- slope = float('inf')
78
- intercept = x1
79
- line_params = (slope, intercept, (x1,y1), (x2,y2))
80
-
81
- status = f"Points: {len(image.points)}/2" if len(image.points) < 2 else "Line set!"
82
- return image, status
 
 
 
 
 
 
 
83
 
84
- def line_intersection(box, line):
85
- """Fast line-box intersection using vector math"""
86
- (m, b, (x1,y1), (x2,y2)) = line
87
- box_x1, box_y1, box_x2, box_y2 = box
88
-
89
- # Convert line to parametric form
90
- dx = x2 - x1
91
- dy = y2 - y1
92
-
93
- # Check box edges
94
- t0 = 0.0
95
- t1 = 1.0
96
-
97
- for edge in [0, 1]: # Check both x and y axes
98
- if edge == 0: # X-axis boundaries
99
- dir = dx
100
- p = box_x1 - x1
101
- q = box_x2 - x1
102
- else: # Y-axis boundaries
103
- dir = dy
104
- p = box_y1 - y1
105
- q = box_y2 - y1
106
-
107
- if dir == 0:
108
- if p > 0 or q < 0: return False
109
- continue
110
-
111
- t_near = p / dir
112
- t_far = q / dir
113
- if t_near > t_far: t_near, t_far = t_far, t_near
114
-
115
- t0 = max(t0, t_near)
116
- t1 = min(t1, t_far)
117
-
118
- if t0 > t1: return False
119
 
120
- return t0 <= 1 and t1 >= 0
121
 
122
- def process_stream(conf_thresh, classes, stream_url):
123
- """Optimized video processing pipeline"""
124
- if not model:
125
- yield None, "Model not initialized"
126
- return
127
-
128
  if not line_params:
129
- yield None, "No detection line set"
130
- return
131
 
132
- cap = cv2.VideoCapture(stream_url)
133
- if not cap.isOpened():
134
- yield None, "Failed to open video stream"
135
- return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
- tracker = {} # {track_id: last_seen}
 
 
 
138
  crossed = set()
139
- frame_skip = 2 # Process every 2nd frame
140
- count = 0
141
 
142
- while True:
143
  ret, frame = cap.read()
144
  if not ret:
145
  break
146
 
147
- count += 1
148
- if count % frame_skip != 0:
149
- continue
150
 
151
- # Detection
152
- results = model.track(
153
- frame,
154
- persist=True,
155
- conf=conf_thresh,
156
- classes=classes,
157
- verbose=False,
158
- device='cuda' if torch.cuda.is_available() else 'cpu'
159
- )
160
-
161
- # Processing
162
  if results[0].boxes.id is not None:
163
  boxes = results[0].boxes.xyxy.cpu().numpy()
164
- ids = results[0].boxes.id.int().cpu().numpy()
165
- scores = results[0].boxes.conf.cpu().numpy()
166
- labels = results[0].boxes.cls.cpu().numpy()
167
 
168
- for box, track_id, score, label in zip(boxes, ids, scores, labels):
169
- if line_intersection(box, line_params) and track_id not in crossed:
170
- crossed.add(track_id)
171
- if len(crossed) > 1000:
172
- crossed.clear()
173
 
174
- # Annotation
175
  annotated = results[0].plot()
176
- cv2.line(annotated, line_params[2], line_params[3], (0,255,0), 2)
 
177
  cv2.putText(annotated, f"Count: {len(crossed)}", (10,30),
178
  cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2)
179
 
@@ -183,48 +130,43 @@ def process_stream(conf_thresh, classes, stream_url):
183
 
184
  # Gradio Interface
185
  with gr.Blocks() as app:
186
- gr.Markdown("# CCTV Smart Monitor - YOLOv11")
187
 
188
- # Initialization
189
- if not initialize_yolov11():
190
- gr.Markdown("**Error**: Failed to initialize YOLOv11 model")
191
 
192
- # Stream URL input
193
- stream_url = gr.Textbox(
194
- label="RTSP Stream URL",
195
- value="rtsp://example.com/stream",
196
- visible=True
197
- )
198
-
199
- # Frame setup
200
- with gr.Row():
201
- frame = gr.Image(label="Setup Frame", interactive=True)
202
- line_status = gr.Textbox(label="Line Status", interactive=False)
203
 
204
  # Controls
205
- with gr.Row():
206
- class_selector = gr.CheckboxGroup(
207
- choices=model.names.values() if model else [],
208
- label="Detection Classes"
209
- )
210
- confidence = gr.Slider(0.1, 1.0, value=0.4, label="Confidence Threshold")
211
 
212
  # Output
213
- output_video = gr.Image(label="Live Analysis", streaming=True)
214
- error_box = gr.Textbox(label="System Messages", interactive=False)
215
 
216
  # Interactions
217
- frame.select(
 
 
 
 
 
 
218
  update_line,
219
- inputs=frame,
220
- outputs=[frame, line_status]
221
  )
222
 
223
- gr.Button("Start Analysis").click(
224
- process_stream,
225
- inputs=[confidence, class_selector, stream_url],
226
- outputs=[output_video, error_box]
227
  )
228
 
229
- if __name__ == "__main__":
230
- app.launch(debug=True, enable_queue=True)
 
1
+ # Maximize CPU usage
2
  import multiprocessing
3
  import cv2
4
 
5
+ # Set OpenCV to use all available cores
6
  cv2.setNumThreads(multiprocessing.cpu_count())
7
 
8
  ##############
 
9
  import gradio as gr
10
  import numpy as np
11
  from PIL import Image, ImageDraw
12
  from ultralytics import YOLO
13
  import logging
 
14
 
15
+ # Set up logging
16
  logging.basicConfig(level=logging.INFO)
17
  logger = logging.getLogger(__name__)
18
 
19
+ # Global variables
20
+ start_point = end_point = line_params = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
  def extract_first_frame(stream_url):
23
+ """Extracts first frame from IP camera"""
24
+ cap = cv2.VideoCapture(stream_url)
25
+ if not cap.isOpened():
26
+ return None, "Error: Could not open stream."
27
+
28
+ ret, frame = cap.read()
29
+ cap.release()
30
+
31
+ if not ret:
32
+ return None, "Error: Could not read frame."
33
+
34
+ return Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)), "First frame extracted."
35
 
36
  def update_line(image, evt: gr.SelectData):
37
+ """Handles line drawing interactions"""
38
+ global start_point, end_point, line_params
 
 
 
39
 
40
+ if not start_point:
41
+ start_point = (evt.index[0], evt.index[1])
 
 
 
 
 
 
 
 
42
  draw = ImageDraw.Draw(image)
43
+ draw.ellipse((start_point[0]-5, start_point[1]-5, start_point[0]+5, start_point[1]+5),
44
+ fill="blue", outline="blue")
45
+ return image, f"Start: {start_point}"
46
+
47
+ end_point = (evt.index[0], evt.index[1])
48
+ draw = ImageDraw.Draw(image)
49
+ draw.line([start_point, end_point], fill="red", width=2)
50
+ draw.ellipse((end_point[0]-5, end_point[1]-5, end_point[0]+5, end_point[1]+5),
51
+ fill="green", outline="green")
52
+
53
+ # Calculate line parameters
54
+ if start_point[0] != end_point[0]:
55
+ slope = (end_point[1] - start_point[1]) / (end_point[0] - start_point[0])
56
+ intercept = start_point[1] - slope * start_point[0]
57
+ line_params = (slope, intercept, start_point, end_point)
58
+ else:
59
+ line_params = (float('inf'), start_point[0], start_point, end_point)
60
+
61
+ start_point = None
62
+ return image, f"Line: {line_params[2]} to {line_params[3]}"
63
 
64
+ def intersect(A, B, C, D):
65
+ """Check line segment intersection"""
66
+ def ccw(A, B, C):
67
+ return (C[1]-A[1])*(B[0]-A[0]) > (B[1]-A[1])*(C[0]-A[0])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
+ return ccw(A,C,D) != ccw(B,C,D) and ccw(A,B,C) != ccw(A,B,D)
70
 
71
+ def is_crossing(box, line_params):
72
+ """Check if box crosses line"""
 
 
 
 
73
  if not line_params:
74
+ return False
 
75
 
76
+ (x1, y1), (x2, y2) = line_params[2], line_params[3]
77
+ box_edges = [
78
+ ((box[0], box[1]), (box[2], box[1])),
79
+ ((box[2], box[1]), (box[2], box[3])),
80
+ ((box[2], box[3]), (box[0], box[3])),
81
+ ((box[0], box[3]), (box[0], box[1]))
82
+ ]
83
+
84
+ intersections = 0
85
+ for edge in box_edges:
86
+ if intersect((x1,y1), (x2,y2), edge[0], edge[1]):
87
+ intersections += 1
88
+ if intersections >= 2:
89
+ return True
90
+ return False
91
+
92
+ def process_video(conf=0.5, classes=None, stream_url=None):
93
+ """Main processing function"""
94
+ global line_params
95
 
96
+ # Initialize YOLOv11
97
+ model = YOLO('yolo11n.pt')
98
+
99
+ cap = cv2.VideoCapture(stream_url)
100
  crossed = set()
 
 
101
 
102
+ while cap.isOpened():
103
  ret, frame = cap.read()
104
  if not ret:
105
  break
106
 
107
+ # Run inference
108
+ results = model.track(frame, persist=True, conf=conf, classes=classes)
 
109
 
110
+ # Process results
 
 
 
 
 
 
 
 
 
 
111
  if results[0].boxes.id is not None:
112
  boxes = results[0].boxes.xyxy.cpu().numpy()
113
+ ids = results[0].boxes.id.cpu().numpy().astype(int)
114
+ clss = results[0].boxes.cls.cpu().numpy().astype(int)
 
115
 
116
+ for box, tid, cls in zip(boxes, ids, clss):
117
+ if is_crossing(box, line_params) and tid not in crossed:
118
+ crossed.add(tid)
 
 
119
 
120
+ # Draw overlays
121
  annotated = results[0].plot()
122
+ if line_params:
123
+ cv2.line(annotated, line_params[2], line_params[3], (0,255,0), 2)
124
  cv2.putText(annotated, f"Count: {len(crossed)}", (10,30),
125
  cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2)
126
 
 
130
 
131
  # Gradio Interface
132
  with gr.Blocks() as app:
133
+ gr.Markdown("# CCTV Object Counter - YOLOv11")
134
 
135
+ # Stream setup
136
+ url = gr.Textbox(label="Stream URL", value="https://example.com/stream.m3u8")
137
+ frame_btn = gr.Button("Get First Frame")
138
 
139
+ # Image components
140
+ img = gr.Image(label="Draw Detection Line", interactive=True)
141
+ line_info = gr.Textbox(label="Line Coordinates")
 
 
 
 
 
 
 
 
142
 
143
  # Controls
144
+ classes = gr.CheckboxGroup(label="Classes", choices=[
145
+ "person", "car", "truck", "motorcycle"
146
+ ], value=["person"])
147
+ conf = gr.Slider(0.1, 1.0, value=0.4, label="Confidence Threshold")
 
 
148
 
149
  # Output
150
+ video_out = gr.Image(label="Live View", streaming=True)
151
+ status = gr.Textbox(label="Status")
152
 
153
  # Interactions
154
+ frame_btn.click(
155
+ extract_first_frame,
156
+ inputs=url,
157
+ outputs=[img, status]
158
+ )
159
+
160
+ img.select(
161
  update_line,
162
+ inputs=img,
163
+ outputs=[img, line_info]
164
  )
165
 
166
+ gr.Button("Start Counting").click(
167
+ process_video,
168
+ inputs=[conf, classes, url],
169
+ outputs=[video_out, status]
170
  )
171
 
172
+ app.launch()