usiddiquee commited on
Commit
1d1c8d9
·
1 Parent(s): b72d0b5
Files changed (1) hide show
  1. app.py +165 -116
app.py CHANGED
@@ -6,12 +6,15 @@ import shutil
6
  from pathlib import Path
7
  import sys
8
  import importlib.util
9
- from concurrent.futures import ThreadPoolExecutor
10
 
11
  # Ensure models directory exists
12
  MODELS_DIR = Path("models")
13
  os.makedirs(MODELS_DIR, exist_ok=True)
14
 
 
 
 
 
15
  def ensure_dependencies():
16
  """Ensure all required dependencies are installed."""
17
  required_packages = [
@@ -44,125 +47,151 @@ def apply_patches():
44
  else:
45
  print("⚠️ tracker_patch.py not found, skipping patches")
46
 
47
- def run_single_tracker(video_file, yolo_model, reid_model, tracking_method, conf_threshold, temp_dir):
48
- """Run object tracking with a single tracking method."""
49
  try:
50
- # Prepare input
51
- input_path = os.path.join(temp_dir, "input_video.mp4")
52
- if not os.path.exists(input_path):
 
53
  shutil.copy(video_file, input_path)
54
-
55
- # Prepare output directory for this tracker
56
- output_dir = os.path.join(temp_dir, f"output_{tracking_method}")
57
- os.makedirs(output_dir, exist_ok=True)
58
-
59
- # Build command
60
- cmd = [
61
- "python", "tracking/track.py",
62
- "--yolo-model", str(MODELS_DIR / yolo_model),
63
- "--reid-model", str(MODELS_DIR / reid_model),
64
- "--tracking-method", tracking_method,
65
- "--source", input_path,
66
- "--conf", str(conf_threshold),
67
- "--save",
68
- "--project", output_dir,
69
- "--name", tracking_method,
70
- "--exist-ok"
71
- ]
72
-
73
- # Special handling for OcSort
74
- if tracking_method == "ocsort":
75
- cmd.append("--per-class")
76
-
77
- # Execute tracking
78
- process = subprocess.run(
79
- cmd,
80
- capture_output=True,
81
- text=True
82
- )
83
-
84
- # Check for errors
85
- if process.returncode != 0:
86
- error_message = process.stderr or process.stdout
87
- return None, f"Error in {tracking_method}: {error_message}"
88
-
89
- # Find output video
90
- output_files = []
91
- for root, _, files in os.walk(output_dir):
92
- for file in files:
93
- if file.lower().endswith((".mp4", ".avi", ".mov")):
94
- output_files.append(os.path.join(root, file))
95
-
96
- if not output_files:
97
- return None, f"No output video generated for {tracking_method}"
98
 
99
- return output_files[0], f"{tracking_method} completed successfully!"
100
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  except Exception as e:
102
- return None, f"Error in {tracking_method}: {str(e)}"
 
 
103
 
104
- def run_all_trackers(video_path, yolo_model, reid_model, conf_threshold):
105
- """Run all tracking methods and return results."""
106
- tracking_methods = ["bytetrack", "botsort", "ocsort", "strongsort"]
107
- results = {}
108
- status_messages = []
109
-
110
  # Validate inputs
111
  if not video_path:
112
- return None, None, None, None, "Please upload a video file"
113
 
114
- # Create temporary workspace
115
- temp_dir = tempfile.mkdtemp()
116
 
117
- try:
118
- for method in tracking_methods:
119
- # Run tracking for this method
120
- output_path, status = run_single_tracker(
121
- video_path,
122
- yolo_model,
123
- reid_model,
124
- method,
125
- conf_threshold,
126
- temp_dir
127
- )
128
-
129
- results[method] = output_path
130
- status_messages.append(status)
131
-
132
- combined_status = "\n".join(status_messages)
133
- return results.get("bytetrack"), results.get("botsort"), results.get("ocsort"), results.get("strongsort"), combined_status
134
-
135
- except Exception as e:
136
- shutil.rmtree(temp_dir, ignore_errors=True)
137
- return None, None, None, None, f"Error: {str(e)}"
138
-
139
- # Define the Gradio interface
140
- def process_video(video_path, yolo_model, reid_model, conf_threshold):
141
- # Run all tracking methods
142
- bytetrack_output, botsort_output, ocsort_output, strongsort_output, status = run_all_trackers(
143
  video_path,
144
  yolo_model,
145
  reid_model,
 
146
  conf_threshold
147
  )
148
 
149
- return bytetrack_output, botsort_output, ocsort_output, strongsort_output, status
 
 
 
 
 
 
 
150
 
151
- # Available models
152
  yolo_models = ["yolov8n.pt", "yolov8s.pt", "yolov8m.pt"]
153
  reid_models = ["osnet_x0_25_msmt17.pt"]
 
154
 
155
  # Ensure dependencies and apply patches at startup
156
  ensure_dependencies()
157
  apply_patches()
158
 
159
  # Create the Gradio interface
160
- with gr.Blocks(title="YOLO Multi-Tracker Comparison") as app:
161
- gr.Markdown("# 🚀 YOLO Multi-Tracker Comparison")
162
- gr.Markdown("Upload a video file to see tracking results from all four trackers side by side.")
163
 
164
  with gr.Row():
165
- with gr.Column(scale=1):
166
  input_video = gr.Video(label="Input Video", sources=["upload"])
167
 
168
  with gr.Group():
@@ -176,6 +205,11 @@ with gr.Blocks(title="YOLO Multi-Tracker Comparison") as app:
176
  value="osnet_x0_25_msmt17.pt",
177
  label="ReID Model"
178
  )
 
 
 
 
 
179
  conf_threshold = gr.Slider(
180
  minimum=0.1,
181
  maximum=0.9,
@@ -184,33 +218,48 @@ with gr.Blocks(title="YOLO Multi-Tracker Comparison") as app:
184
  label="Confidence Threshold"
185
  )
186
 
187
- process_btn = gr.Button("Process Video with All Trackers", variant="primary")
188
- status_text = gr.Textbox(label="Status", value="Ready to process video", lines=5)
189
-
190
- gr.Markdown("## Tracking Results")
191
- with gr.Row():
192
- with gr.Column():
193
- gr.Markdown("### ByteTrack")
194
- bytetrack_video = gr.Video(label="ByteTrack Result", autoplay=False)
195
-
196
- with gr.Column():
197
- gr.Markdown("### BOT-SORT")
198
- botsort_video = gr.Video(label="BOT-SORT Result", autoplay=False)
199
-
200
- with gr.Row():
201
- with gr.Column():
202
- gr.Markdown("### OC-SORT")
203
- ocsort_video = gr.Video(label="OC-SORT Result", autoplay=False)
204
-
205
  with gr.Column():
206
- gr.Markdown("### StrongSORT")
207
- strongsort_video = gr.Video(label="StrongSORT Result", autoplay=False)
208
 
209
  process_btn.click(
210
  fn=process_video,
211
- inputs=[input_video, yolo_model, reid_model, conf_threshold],
212
- outputs=[bytetrack_video, botsort_video, ocsort_video, strongsort_video, status_text]
213
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
 
215
  # Launch the app
216
  if __name__ == "__main__":
 
6
  from pathlib import Path
7
  import sys
8
  import importlib.util
 
9
 
10
  # Ensure models directory exists
11
  MODELS_DIR = Path("models")
12
  os.makedirs(MODELS_DIR, exist_ok=True)
13
 
14
+ # Create permanent output directory
15
+ OUTPUT_DIR = Path("outputs")
16
+ os.makedirs(OUTPUT_DIR, exist_ok=True)
17
+
18
  def ensure_dependencies():
19
  """Ensure all required dependencies are installed."""
20
  required_packages = [
 
47
  else:
48
  print("⚠️ tracker_patch.py not found, skipping patches")
49
 
50
+ def run_tracking(video_file, yolo_model, reid_model, tracking_method, conf_threshold):
51
+ """Run object tracking on the uploaded video."""
52
  try:
53
+ # Create temporary workspace
54
+ with tempfile.TemporaryDirectory() as temp_dir:
55
+ # Prepare input
56
+ input_path = os.path.join(temp_dir, "input_video.mp4")
57
  shutil.copy(video_file, input_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
+ # Prepare output directory
60
+ output_dir = os.path.join(temp_dir, "output")
61
+ os.makedirs(output_dir, exist_ok=True)
62
+
63
+ # Build command
64
+ cmd = [
65
+ "python", "tracking/track.py",
66
+ "--yolo-model", str(MODELS_DIR / yolo_model),
67
+ "--reid-model", str(MODELS_DIR / reid_model),
68
+ "--tracking-method", tracking_method,
69
+ "--source", input_path,
70
+ "--conf", str(conf_threshold),
71
+ "--save",
72
+ "--project", output_dir,
73
+ "--name", "track",
74
+ "--exist-ok"
75
+ ]
76
+
77
+ # Special handling for OcSort
78
+ if tracking_method == "ocsort":
79
+ cmd.append("--per-class")
80
+
81
+ # Execute tracking with error handling
82
+ print(f"Executing command: {' '.join(cmd)}")
83
+ process = subprocess.run(
84
+ cmd,
85
+ capture_output=True,
86
+ text=True
87
+ )
88
+
89
+ # Check for errors in output
90
+ if process.returncode != 0:
91
+ error_message = process.stderr or process.stdout
92
+ print(f"Process failed with return code {process.returncode}")
93
+ print(f"Error: {error_message}")
94
+ return None, f"Error in tracking process: {error_message}"
95
+
96
+ print(f"Process completed with return code {process.returncode}")
97
+
98
+ # Find output video
99
+ output_files = []
100
+ for root, _, files in os.walk(output_dir):
101
+ for file in files:
102
+ if file.lower().endswith((".mp4", ".avi", ".mov")):
103
+ output_files.append(os.path.join(root, file))
104
+
105
+ print(f"Found output files: {output_files}")
106
+
107
+ if not output_files:
108
+ print("No output video files found")
109
+ return None, "No output video was generated. Check if tracking was successful."
110
+
111
+ output_file = output_files[0]
112
+ print(f"Selected output file: {output_file}")
113
+
114
+ # Verify file exists and has size
115
+ if os.path.exists(output_file):
116
+ file_size = os.path.getsize(output_file)
117
+ print(f"Output file exists with size: {file_size} bytes")
118
+
119
+ if file_size == 0:
120
+ return None, "Output video was generated but has zero size."
121
+
122
+ # Copy to permanent location with unique name
123
+ permanent_path = os.path.join(OUTPUT_DIR, f"output_{os.path.basename(video_file)}")
124
+ shutil.copy(output_file, permanent_path)
125
+ print(f"Copied output to permanent location: {permanent_path}")
126
+
127
+ # Ensure the file is in MP4 format for better compatibility with Gradio
128
+ if not permanent_path.lower().endswith('.mp4'):
129
+ mp4_path = os.path.splitext(permanent_path)[0] + '.mp4'
130
+ try:
131
+ print(f"Converting to MP4 format: {mp4_path}")
132
+ subprocess.run([
133
+ 'ffmpeg', '-i', permanent_path,
134
+ '-c:v', 'libx264', '-preset', 'fast',
135
+ '-c:a', 'aac', mp4_path
136
+ ], check=True, capture_output=True)
137
+ os.remove(permanent_path) # Remove the original file
138
+ permanent_path = mp4_path
139
+ except Exception as e:
140
+ print(f"Failed to convert to MP4: {str(e)}")
141
+ # Continue with original file if conversion fails
142
+
143
+ return permanent_path, "Processing completed successfully!"
144
+ else:
145
+ print(f"Output file not found at {output_file}")
146
+ return None, "Output file was referenced but doesn't exist on disk."
147
+
148
  except Exception as e:
149
+ import traceback
150
+ traceback.print_exc()
151
+ return None, f"Error: {str(e)}"
152
 
153
+ # Define the Gradio interface
154
+ def process_video(video_path, yolo_model, reid_model, tracking_method, conf_threshold):
 
 
 
 
155
  # Validate inputs
156
  if not video_path:
157
+ return None, "Please upload a video file"
158
 
159
+ print(f"Processing video: {video_path}")
160
+ print(f"Parameters: model={yolo_model}, reid={reid_model}, tracker={tracking_method}, conf={conf_threshold}")
161
 
162
+ output_path, status = run_tracking(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  video_path,
164
  yolo_model,
165
  reid_model,
166
+ tracking_method,
167
  conf_threshold
168
  )
169
 
170
+ if output_path:
171
+ print(f"Returning output path: {output_path}")
172
+ # Make sure the path is absolute for Gradio
173
+ abs_path = os.path.abspath(output_path)
174
+ return abs_path, status
175
+ else:
176
+ print(f"No output path available. Status: {status}")
177
+ return None, status
178
 
179
+ # Available models and tracking methods
180
  yolo_models = ["yolov8n.pt", "yolov8s.pt", "yolov8m.pt"]
181
  reid_models = ["osnet_x0_25_msmt17.pt"]
182
+ tracking_methods = ["bytetrack", "botsort", "ocsort", "strongsort"]
183
 
184
  # Ensure dependencies and apply patches at startup
185
  ensure_dependencies()
186
  apply_patches()
187
 
188
  # Create the Gradio interface
189
+ with gr.Blocks(title="YOLO Object Tracking") as app:
190
+ gr.Markdown("# 🚀 YOLO Object Tracking")
191
+ gr.Markdown("Upload a video file to detect and track objects. Processing may take a few minutes depending on video length.")
192
 
193
  with gr.Row():
194
+ with gr.Column():
195
  input_video = gr.Video(label="Input Video", sources=["upload"])
196
 
197
  with gr.Group():
 
205
  value="osnet_x0_25_msmt17.pt",
206
  label="ReID Model"
207
  )
208
+ tracking_method = gr.Dropdown(
209
+ choices=tracking_methods,
210
+ value="bytetrack",
211
+ label="Tracking Method"
212
+ )
213
  conf_threshold = gr.Slider(
214
  minimum=0.1,
215
  maximum=0.9,
 
218
  label="Confidence Threshold"
219
  )
220
 
221
+ process_btn = gr.Button("Process Video", variant="primary")
222
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
  with gr.Column():
224
+ output_video = gr.Video(label="Output Video with Tracking")
225
+ status_text = gr.Textbox(label="Status", value="Ready to process video")
226
 
227
  process_btn.click(
228
  fn=process_video,
229
+ inputs=[input_video, yolo_model, reid_model, tracking_method, conf_threshold],
230
+ outputs=[output_video, status_text]
231
  )
232
+
233
+ # Add a debug section
234
+ with gr.Accordion("Debug Information", open=False):
235
+ debug_text = gr.Textbox(label="Debug Log", lines=10, interactive=False)
236
+
237
+ def check_environment():
238
+ info = []
239
+ # Check Python version
240
+ info.append(f"Python version: {sys.version}")
241
+ # Check Gradio version
242
+ info.append(f"Gradio version: {gr.__version__}")
243
+ # Check for ffmpeg
244
+ try:
245
+ ffmpeg_version = subprocess.run(["ffmpeg", "-version"], capture_output=True, text=True)
246
+ info.append("ffmpeg: Installed")
247
+ except:
248
+ info.append("ffmpeg: Not found")
249
+ # Check tracking directory
250
+ if os.path.exists("tracking"):
251
+ info.append("tracking directory: Found")
252
+ else:
253
+ info.append("tracking directory: Not found")
254
+ # Check models
255
+ info.append("Models:")
256
+ for model in os.listdir(MODELS_DIR) if os.path.exists(MODELS_DIR) else []:
257
+ info.append(f" - {model}")
258
+
259
+ return "\n".join(info)
260
+
261
+ check_btn = gr.Button("Check Environment")
262
+ check_btn.click(fn=check_environment, outputs=debug_text)
263
 
264
  # Launch the app
265
  if __name__ == "__main__":