-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvisualize_results.py
More file actions
294 lines (240 loc) · 9.17 KB
/
visualize_results.py
File metadata and controls
294 lines (240 loc) · 9.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
"""
Visualization Script for CursorTracker
This script generates visualization images with bounding boxes drawn on frames
and creates an annotated video showing the tracked cursor.
Usage:
python visualize_results.py --video_name video1 --base_dir /path/to/data
python visualize_results.py --video_name video1 --base_dir /path/to/data --result_num 1
"""
import os
import sys
import argparse
import cv2
import numpy as np
import imageio
from tqdm import tqdm
from PIL import Image, ImageDraw, ImageFont
def get_args():
"""Parse command line arguments."""
parser = argparse.ArgumentParser(
description='Visualize cursor tracking results with bounding boxes.'
)
parser.add_argument(
'-v', '--video_name',
type=str,
required=True,
help='Name of video directory (under base_dir)'
)
parser.add_argument(
'--base_dir',
type=str,
default='./data/',
help='Base directory containing video data (default: ./data/)'
)
parser.add_argument(
'--result_num',
type=int,
default=None,
help='Result folder number (e.g., 1 for our_results_1). If not specified, uses latest.'
)
parser.add_argument(
'--bbox_color',
type=str,
default='0,255,0',
help='Bounding box color in BGR format (default: 0,255,0 = green)'
)
parser.add_argument(
'--bbox_thickness',
type=int,
default=2,
help='Bounding box line thickness (default: 2)'
)
parser.add_argument(
'--fps',
type=int,
default=30,
help='Output video FPS (default: 30)'
)
parser.add_argument(
'--quality',
type=int,
default=9,
help='Output video quality 0-10, 10=best (default: 9)'
)
return parser.parse_args()
def load_tracking_results(results_file):
"""
Load tracking results from file.
Args:
results_file: Path to tracking results file
Returns:
Dictionary mapping frame numbers to bounding boxes (x1, y1, x2, y2)
"""
if not os.path.exists(results_file):
raise FileNotFoundError(f"Results file not found: {results_file}")
results = {}
with open(results_file, 'r') as f:
for line in f:
parts = line.strip().split(',')
if len(parts) >= 5:
frame_num = parts[0]
x1, y1, x2, y2 = int(parts[1]), int(parts[2]), int(parts[3]), int(parts[4])
results[frame_num] = (x1, y1, x2, y2)
return results
def draw_bounding_box(image, bbox, color=(0, 255, 0), thickness=2, show_coords=True):
"""
Draw bounding box on image.
Args:
image: Input image (numpy array)
bbox: Bounding box tuple (x1, y1, x2, y2)
color: Box color in BGR format
thickness: Line thickness
show_coords: Whether to show coordinates as text
Returns:
Image with bounding box drawn
"""
x1, y1, x2, y2 = bbox
# Skip if bbox is at origin (no detection)
if x1 == 0 and y1 == 0 and x2 == 0 and y2 == 0:
return image
# Draw rectangle
cv2.rectangle(image, (x1, y1), (x2, y2), color, thickness)
# Add text with coordinates if requested
if show_coords:
text = f"({x1},{y1})"
font = cv2.FONT_HERSHEY_SIMPLEX
font_scale = 0.4
font_thickness = 1
# Get text size to draw background
(text_width, text_height), baseline = cv2.getTextSize(text, font, font_scale, font_thickness)
# Draw text background
cv2.rectangle(image,
(x1, y1 - text_height - baseline - 5),
(x1 + text_width, y1),
color, -1)
# Draw text
cv2.putText(image, text, (x1, y1 - baseline - 2),
font, font_scale, (0, 0, 0), font_thickness)
return image
def generate_visualizations(video_name, base_dir, result_num=None,
bbox_color=(0, 255, 0), bbox_thickness=2,
fps=30, quality=9):
"""
Generate visualization images and video.
Args:
video_name: Name of video directory
base_dir: Base directory containing video data
result_num: Result folder number (None = use latest)
bbox_color: Bounding box color in BGR
bbox_thickness: Box line thickness
fps: Output video FPS
quality: Video quality (0-10, 10=best)
"""
# Set up directories
video_dir = os.path.join(base_dir, video_name)
image_folder = os.path.join(video_dir, "images")
# Find results folder
if result_num is None:
# Find latest results folder
results_folders = [f for f in os.listdir(video_dir) if f.startswith("our_results_")]
if not results_folders:
raise FileNotFoundError(f"No results folders found in {video_dir}")
results_folders.sort(key=lambda x: int(x.split("_")[-1]))
results_folder_name = results_folders[-1]
result_num = int(results_folder_name.split("_")[-1])
else:
results_folder_name = f"our_results_{result_num}"
results_folder = os.path.join(video_dir, results_folder_name)
results_file = os.path.join(results_folder, "our_results.txt")
# Create output directories
viz_folder = os.path.join(results_folder, "visualizations")
os.makedirs(viz_folder, exist_ok=True)
print(f"\nVisualization Configuration:")
print(f" Video name: {video_name}")
print(f" Base directory: {base_dir}")
print(f" Results folder: {results_folder_name}")
print(f" Bounding box color: {bbox_color}")
print(f" Bounding box thickness: {bbox_thickness}")
print(f" Output FPS: {fps}")
print(f" Output quality: {quality}/10\n")
# Verify directories exist
if not os.path.exists(image_folder):
raise FileNotFoundError(f"Images folder not found: {image_folder}")
if not os.path.exists(results_folder):
raise FileNotFoundError(f"Results folder not found: {results_folder}")
# Load tracking results
print(f"Loading tracking results from: {results_file}")
tracking_results = load_tracking_results(results_file)
print(f" Loaded {len(tracking_results)} frame results")
# Get sorted list of image files
image_files = sorted([f for f in os.listdir(image_folder) if f.endswith('.png')],
key=lambda x: int(x.split('.')[0]))
if len(image_files) == 0:
raise ValueError(f"No PNG images found in {image_folder}")
print(f" Found {len(image_files)} frames to process\n")
# Process frames
print("Generating visualization images...")
video_frames = []
for image_file in tqdm(image_files, desc="Processing frames"):
frame_num = image_file.split('.')[0]
image_path = os.path.join(image_folder, image_file)
# Read image
image = cv2.imread(image_path)
if image is None:
print(f"Warning: Could not read {image_path}")
continue
# Draw bounding box if available
if frame_num in tracking_results:
bbox = tracking_results[frame_num]
image = draw_bounding_box(image, bbox, bbox_color, bbox_thickness)
# Save visualization image
viz_filename = f"viz_{image_file}"
viz_path = os.path.join(viz_folder, viz_filename)
cv2.imwrite(viz_path, image)
# Add to video frames
video_frames.append(image)
# Create video
if len(video_frames) > 0:
print(f"\nCreating annotated video...")
video_path = os.path.join(results_folder, f"tracked_video_{results_folder_name}.mp4")
# Get frame dimensions
height, width = video_frames[0].shape[:2]
# Create video writer
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(video_path, fourcc, fps, (width, height))
for frame in tqdm(video_frames, desc="Writing video"):
out.write(frame)
out.release()
print(f"\n✓ Visualization complete!")
print(f" Visualization images: {viz_folder}/")
print(f" Annotated video: {video_path}")
print(f" Total frames: {len(video_frames)}")
# Calculate statistics
detected_frames = sum(1 for frame_num in tracking_results.values()
if not (frame_num == (0, 0, 0, 0)))
total_frames = len(image_files)
detection_rate = (detected_frames / total_frames * 100) if total_frames > 0 else 0
print(f"\nTracking Statistics:")
print(f" Frames with detections: {detected_frames}/{total_frames} ({detection_rate:.1f}%)")
else:
print("\nError: No frames were processed successfully")
def main():
"""Main entry point."""
args = get_args()
# Parse bbox color
bbox_color = tuple(map(int, args.bbox_color.split(',')))
try:
generate_visualizations(
video_name=args.video_name,
base_dir=args.base_dir,
result_num=args.result_num,
bbox_color=bbox_color,
bbox_thickness=args.bbox_thickness,
fps=args.fps,
quality=args.quality
)
except Exception as e:
print(f"\nError: {e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()