shimaa22 commited on
Commit
ee9ebff
·
verified ·
1 Parent(s): baf5377

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -112
app.py CHANGED
@@ -10,86 +10,42 @@ model = YOLO("best.pt")
10
  class_names = model.names
11
  tracker = DeepSort(max_age=30)
12
 
13
-
14
  def analyze_articulated_motion(frame, prev_frame, bbox):
15
  x1, y1, x2, y2 = map(int, bbox)
16
-
17
  x1, y1 = max(0, x1), max(0, y1)
18
  x2, y2 = min(frame.shape[1], x2), min(frame.shape[0], y2)
19
 
20
  h, w = y2 - y1, x2 - x1
21
- if h < 20 or w < 20:
22
- return False, "none"
23
-
24
- mid_y = y1 + int(h * 0.4)
25
- upper_curr = cv2.cvtColor(frame[y1:mid_y, x1:x2], cv2.COLOR_BGR2GRAY)
26
- upper_prev = cv2.cvtColor(prev_frame[y1:mid_y, x1:x2], cv2.COLOR_BGR2GRAY)
27
- lower_curr = cv2.cvtColor(frame[mid_y:y2, x1:x2], cv2.COLOR_BGR2GRAY)
28
- lower_prev = cv2.cvtColor(prev_frame[mid_y:y2, x1:x2], cv2.COLOR_BGR2GRAY)
29
-
30
- def get_motion_score(img1, img2):
31
- diff = cv2.absdiff(img1, img2)
32
- _, thresh = cv2.threshold(diff, 15, 255, cv2.THRESH_BINARY)
33
- return np.mean(thresh)
34
 
35
- upper_score = get_motion_score(upper_curr, upper_prev)
36
- lower_score = get_motion_score(lower_curr, lower_prev)
37
-
38
- sensitivity = 0.5
39
 
40
- if upper_score > sensitivity:
41
- if lower_score < (sensitivity * 1.5):
 
 
 
 
 
 
 
42
  return True, "arm_only"
43
- else:
44
- return True, "full_body"
45
- elif lower_score > sensitivity:
46
- return True, "full_body"
47
-
48
  return False, "none"
49
 
50
-
51
- def get_activity(history, is_active, motion_source):
52
- if not is_active:
53
- return "WAITING"
54
-
55
- if len(history) < 5:
56
- return "DIGGING"
57
-
58
- dx = history[-1][0] - history[0][0]
59
- dy = history[-1][1] - history[0][1]
60
-
61
- if motion_source == "arm_only":
62
- if dy > 3: return "DIGGING"
63
- if dy < -3: return "DUMPING"
64
- return "DIGGING"
65
-
66
- if abs(dx) > abs(dy) * 1.5:
67
- return "SWINGING/LOADING"
68
- if dy > 5:
69
- return "DIGGING"
70
- if dy < -5:
71
- return "DUMPING"
72
-
73
- return "WORKING"
74
-
75
- def process_video(video_file, selected_classes):
76
  cap = cv2.VideoCapture(video_file)
77
  fps = cap.get(cv2.CAP_PROP_FPS) or 24
78
- width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
79
- height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
80
-
81
  output_video_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4").name
82
  fourcc = cv2.VideoWriter_fourcc(*"mp4v")
83
  out = cv2.VideoWriter(output_video_path, fourcc, fps, (640, 360))
84
 
85
  frame_id = 0
86
  prev_frame = None
87
-
88
- track_memory = {}
89
- track_stats = {}
90
- frame_results = []
91
-
92
- selected_ids = [k for k, v in class_names.items() if v in selected_classes]
93
 
94
  while True:
95
  ret, frame = cap.read()
@@ -97,15 +53,18 @@ def process_video(video_file, selected_classes):
97
 
98
  frame_id += 1
99
  frame_resized = cv2.resize(frame, (640, 360))
100
- results = model(frame_resized, verbose=False)[0]
101
 
 
102
  detections = []
 
103
  for box in results.boxes:
104
  cls_id = int(box.cls[0])
105
- if cls_id in selected_ids:
 
 
106
  x1, y1, x2, y2 = box.xyxy[0].tolist()
107
  conf = float(box.conf[0])
108
- detections.append(([x1, y1, x2 - x1, y2 - y1], conf, cls_id))
109
 
110
  tracks = tracker.update_tracks(detections, frame=frame_resized)
111
 
@@ -114,52 +73,47 @@ def process_video(video_file, selected_classes):
114
 
115
  track_id = t.track_id
116
  bbox = t.to_ltrb()
117
- cx, cy = (bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2
118
-
119
- if track_id not in track_memory:
120
- track_memory[track_id] = []
121
- track_stats[track_id] = {"active_frames": 0, "total_frames": 0}
122
-
123
- track_memory[track_id].append((cx, cy))
124
- if len(track_memory[track_id]) > 20: track_memory[track_id].pop(0)
125
-
126
  is_active = False
127
  motion_src = "none"
128
  if prev_frame is not None:
129
  is_active, motion_src = analyze_articulated_motion(frame_resized, prev_frame, bbox)
130
-
131
- current_act = get_activity(track_memory[track_id], is_active, motion_src)
132
 
133
- track_stats[track_id]["total_frames"] += 1
134
- if current_act != "WAITING":
135
- track_stats[track_id]["active_frames"] += 1
 
 
136
 
137
  color = (0, 255, 0) if is_active else (0, 0, 255)
138
  ix1, iy1, ix2, iy2 = map(int, bbox)
139
  cv2.rectangle(frame_resized, (ix1, iy1), (ix2, iy2), color, 2)
140
- cv2.putText(frame_resized, f"ID:{track_id} {current_act}", (ix1, iy1-10),
141
- cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
142
-
143
- total_sec = track_stats[track_id]["total_frames"] / fps
144
- active_sec = track_stats[track_id]["active_frames"] / fps
145
- util_pct = (active_sec / total_sec) * 100 if total_sec > 0 else 0
146
-
147
- entry = {
148
- "frame_id": frame_id,
149
- "equipment_id": f"EX-{track_id}",
150
- "timestamp": f"{frame_id/fps:.3f}",
151
- "utilization": {
152
- "current_state": "ACTIVE" if is_active else "INACTIVE",
153
- "current_activity": current_act,
154
- "motion_source": motion_src
155
- },
156
- "time_analytics": {
157
- "total_tracked_seconds": round(total_sec, 1),
158
- "total_active_seconds": round(active_sec, 1),
159
- "utilization_percent": round(util_pct, 1)
160
- }
161
- }
162
- track_stats[track_id]["last_entry"] = entry
 
 
 
163
 
164
  out.write(frame_resized)
165
  prev_frame = frame_resized.copy()
@@ -167,27 +121,21 @@ def process_video(video_file, selected_classes):
167
  cap.release()
168
  out.release()
169
 
170
- final_json_data = [stats["last_entry"] for stats in track_stats.values() if "last_entry" in stats]
171
-
172
  json_path = tempfile.NamedTemporaryFile(delete=False, suffix=".json").name
173
  with open(json_path, "w") as f:
174
  json.dump(final_json_data, f, indent=2)
175
 
176
  return output_video_path, json.dumps(final_json_data, indent=2), json_path
177
 
178
-
179
  demo = gr.Interface(
180
  fn=process_video,
181
- inputs=[
182
- gr.Video(label="Upload Construction Video"),
183
- gr.CheckboxGroup(choices=["excavator", "dump truck", "loader"], label="Equipment to Track", value=["excavator"])
184
- ],
185
  outputs=[
186
- gr.Video(label="Detection Feed"),
187
- gr.Textbox(label="Real-time Analytics (JSON)", lines=15),
188
- gr.File(label="Download Full Report")
189
  ],
190
- title="Equipment Utilization Prototype"
191
  )
192
 
193
  if __name__ == "__main__":
 
10
  class_names = model.names
11
  tracker = DeepSort(max_age=30)
12
 
 
13
  def analyze_articulated_motion(frame, prev_frame, bbox):
14
  x1, y1, x2, y2 = map(int, bbox)
 
15
  x1, y1 = max(0, x1), max(0, y1)
16
  x2, y2 = min(frame.shape[1], x2), min(frame.shape[0], y2)
17
 
18
  h, w = y2 - y1, x2 - x1
19
+ if h < 10 or w < 10: return False, "none"
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
+ mid_y = y1 + int(h * 0.5)
 
 
 
22
 
23
+ try:
24
+ roi_curr = cv2.cvtColor(frame[y1:mid_y, x1:x2], cv2.COLOR_BGR2GRAY)
25
+ roi_prev = cv2.cvtColor(prev_frame[y1:mid_y, x1:x2], cv2.COLOR_BGR2GRAY)
26
+
27
+ diff = cv2.absdiff(roi_curr, roi_prev)
28
+ _, thresh = cv2.threshold(diff, 12, 255, cv2.THRESH_BINARY)
29
+ motion_score = np.mean(thresh)
30
+
31
+ if motion_score > 0.15:
32
  return True, "arm_only"
33
+ except:
34
+ pass
 
 
 
35
  return False, "none"
36
 
37
+ def process_video(video_file):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  cap = cv2.VideoCapture(video_file)
39
  fps = cap.get(cv2.CAP_PROP_FPS) or 24
40
+
 
 
41
  output_video_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4").name
42
  fourcc = cv2.VideoWriter_fourcc(*"mp4v")
43
  out = cv2.VideoWriter(output_video_path, fourcc, fps, (640, 360))
44
 
45
  frame_id = 0
46
  prev_frame = None
47
+ track_stats = {}
48
+ final_json_data = []
 
 
 
 
49
 
50
  while True:
51
  ret, frame = cap.read()
 
53
 
54
  frame_id += 1
55
  frame_resized = cv2.resize(frame, (640, 360))
 
56
 
57
+ results = model(frame_resized, verbose=False)[0]
58
  detections = []
59
+
60
  for box in results.boxes:
61
  cls_id = int(box.cls[0])
62
+ label = class_names[cls_id]
63
+
64
+ if label == "C_E":
65
  x1, y1, x2, y2 = box.xyxy[0].tolist()
66
  conf = float(box.conf[0])
67
+ detections.append(([x1, y1, x2 - x1, y2 - y1], conf, "excavator"))
68
 
69
  tracks = tracker.update_tracks(detections, frame=frame_resized)
70
 
 
73
 
74
  track_id = t.track_id
75
  bbox = t.to_ltrb()
76
+
 
 
 
 
 
 
 
 
77
  is_active = False
78
  motion_src = "none"
79
  if prev_frame is not None:
80
  is_active, motion_src = analyze_articulated_motion(frame_resized, prev_frame, bbox)
 
 
81
 
82
+ if track_id not in track_stats:
83
+ track_stats[track_id] = {"active_f": 0, "total_f": 0}
84
+
85
+ track_stats[track_id]["total_f"] += 1
86
+ if is_active: track_stats[track_id]["active_f"] += 1
87
 
88
  color = (0, 255, 0) if is_active else (0, 0, 255)
89
  ix1, iy1, ix2, iy2 = map(int, bbox)
90
  cv2.rectangle(frame_resized, (ix1, iy1), (ix2, iy2), color, 2)
91
+ cv2.putText(frame_resized, f"EX-{track_id} | {'ACTIVE' if is_active else 'IDLE'}",
92
+ (ix1, iy1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
93
+
94
+ if frame_id % int(fps) == 0 or frame_id == 1:
95
+ total_sec = track_stats[track_id]["total_f"] / fps
96
+ active_sec = track_stats[track_id]["active_f"] / fps
97
+ idle_sec = total_sec - active_sec
98
+ util_pct = (active_sec / total_sec) * 100 if total_sec > 0 else 0
99
+
100
+ final_json_data.append({
101
+ "frame_id": frame_id,
102
+ "equipment_id": f"EX-{track_id}",
103
+ "equipment_class": "excavator",
104
+ "timestamp": f"00:00:{frame_id/fps:06.3f}",
105
+ "utilization": {
106
+ "current_state": "ACTIVE" if is_active else "INACTIVE",
107
+ "current_activity": "WORKING" if is_active else "WAITING",
108
+ "motion_source": motion_src
109
+ },
110
+ "time_analytics": {
111
+ "total_tracked_seconds": round(total_sec, 1),
112
+ "total_active_seconds": round(active_sec, 1),
113
+ "total_idle_seconds": round(idle_sec, 1),
114
+ "utilization_percent": round(util_pct, 1)
115
+ }
116
+ })
117
 
118
  out.write(frame_resized)
119
  prev_frame = frame_resized.copy()
 
121
  cap.release()
122
  out.release()
123
 
 
 
124
  json_path = tempfile.NamedTemporaryFile(delete=False, suffix=".json").name
125
  with open(json_path, "w") as f:
126
  json.dump(final_json_data, f, indent=2)
127
 
128
  return output_video_path, json.dumps(final_json_data, indent=2), json_path
129
 
 
130
  demo = gr.Interface(
131
  fn=process_video,
132
+ inputs=gr.Video(label="Upload Construction Video"),
 
 
 
133
  outputs=[
134
+ gr.Video(label="Processed Video"),
135
+ gr.Textbox(label="Kafka-ready JSON Payload", lines=20),
136
+ gr.File(label="Download Full JSON Report")
137
  ],
138
+ title=" Equipment Utilization System",
139
  )
140
 
141
  if __name__ == "__main__":