Abs6187 commited on
Commit
fdf832f
·
verified ·
1 Parent(s): a4c7d4c

Update src/annotator.py

Browse files
Files changed (1) hide show
  1. src/annotator.py +234 -237
src/annotator.py CHANGED
@@ -1,237 +1,234 @@
1
- """
2
- Frame Annotation Module
3
- ========================
4
-
5
- Provides comprehensive video frame annotation capabilities for vehicle detection
6
- visualization including bounding boxes, labels, trajectories, and counting zones.
7
-
8
- Authors:
9
- - Abhay Gupta (0205CC221005)
10
- - Aditi Lakhera (0205CC221011)
11
- - Balraj Patel (0205CC221049)
12
- - Bhumika Patel (0205CC221050)
13
- """
14
-
15
- import numpy as np
16
- import supervision as sv
17
- from typing import List, Optional, Tuple
18
- import logging
19
-
20
- logger = logging.getLogger(__name__)
21
-
22
-
23
- class FrameAnnotator:
24
- """
25
- Comprehensive frame annotation system for vehicle detection visualization.
26
-
27
- This class manages multiple annotation layers including bounding boxes,
28
- labels, object trajectories, counting lines, and detection zones.
29
- """
30
-
31
- def __init__(
32
- self,
33
- video_resolution: Tuple[int, int],
34
- show_boxes: bool = True,
35
- show_labels: bool = True,
36
- show_traces: bool = True,
37
- show_line_zones: bool = True,
38
- trace_length: int = 20,
39
- zone_polygon: Optional[np.ndarray] = None
40
- ):
41
- """
42
- Initialize the frame annotator.
43
-
44
- Args:
45
- video_resolution: Video resolution as (width, height)
46
- show_boxes: Enable bounding box annotations
47
- show_labels: Enable label annotations
48
- show_traces: Enable trajectory trace annotations
49
- show_line_zones: Enable line zone annotations
50
- trace_length: Maximum number of points in trajectory trace
51
- zone_polygon: Optional polygon defining detection zone
52
- """
53
- self.resolution = video_resolution
54
- self.show_boxes = show_boxes
55
- self.show_labels = show_labels
56
- self.show_traces = show_traces
57
- self.show_line_zones = show_line_zones
58
- self.zone_polygon = zone_polygon
59
-
60
- # Calculate optimal annotation parameters based on resolution
61
- self.line_thickness = sv.calculate_optimal_line_thickness(video_resolution)
62
- self.text_scale = sv.calculate_optimal_text_scale(video_resolution)
63
-
64
- logger.info(f"Initializing annotator for {video_resolution[0]}x{video_resolution[1]}")
65
- logger.info(f"Line thickness: {self.line_thickness}, Text scale: {self.text_scale}")
66
-
67
- # Initialize annotation components
68
- self._setup_annotators(trace_length)
69
-
70
- def _setup_annotators(self, trace_length: int) -> None:
71
- """
72
- Set up individual annotation components.
73
-
74
- Args:
75
- trace_length: Maximum trajectory trace length
76
- """
77
- # Bounding box annotator
78
- if self.show_boxes:
79
- self.box_drawer = sv.BoxAnnotator(
80
- thickness=self.line_thickness,
81
- color_lookup=sv.ColorLookup.TRACK
82
- )
83
- logger.debug("Box annotator initialized")
84
- else:
85
- self.box_drawer = None
86
-
87
- # Label annotator
88
- if self.show_labels:
89
- self.label_drawer = sv.LabelAnnotator(
90
- text_thickness=self.line_thickness,
91
- text_scale=self.text_scale,
92
- text_position=sv.Position.BOTTOM_CENTER,
93
- color_lookup=sv.ColorLookup.TRACK
94
- )
95
- logger.debug("Label annotator initialized")
96
- else:
97
- self.label_drawer = None
98
-
99
- # Trajectory trace annotator
100
- if self.show_traces:
101
- self.trace_drawer = sv.TraceAnnotator(
102
- thickness=self.line_thickness,
103
- trace_length=trace_length,
104
- position=sv.Position.BOTTOM_CENTER,
105
- color_lookup=sv.ColorLookup.TRACK
106
- )
107
- logger.debug(f"Trace annotator initialized with length {trace_length}")
108
- else:
109
- self.trace_drawer = None
110
-
111
- # Line zone annotator
112
- if self.show_line_zones:
113
- self.line_zone_drawer = sv.LineZoneAnnotator(
114
- thickness=self.line_thickness,
115
- text_thickness=self.line_thickness,
116
- text_scale=self.text_scale,
117
- color=sv.Color.WHITE,
118
- text_color=sv.Color.BLACK,
119
- display_in_count=True,
120
- display_out_count=True
121
- )
122
- logger.debug("Line zone annotator initialized")
123
- else:
124
- self.line_zone_drawer = None
125
-
126
- # Polygon zone annotator (for detection area visualization)
127
- if self.zone_polygon is not None:
128
- try:
129
- zone = sv.PolygonZone(
130
- polygon=self.zone_polygon,
131
- frame_resolution_wh=self.resolution
132
- )
133
- self.polygon_drawer = sv.PolygonZoneAnnotator(
134
- zone=zone,
135
- color=sv.Color.GREEN,
136
- thickness=self.line_thickness,
137
- display_in_zone_count=False
138
- )
139
- logger.debug("Polygon zone annotator initialized")
140
- except Exception as e:
141
- logger.warning(f"Failed to initialize polygon zone: {e}")
142
- self.polygon_drawer = None
143
- else:
144
- self.polygon_drawer = None
145
-
146
- def draw_annotations(
147
- self,
148
- frame: np.ndarray,
149
- detections: sv.Detections,
150
- labels: Optional[List[str]] = None,
151
- line_zones: Optional[List[sv.LineZone]] = None
152
- ) -> np.ndarray:
153
- """
154
- Apply all enabled annotations to a video frame.
155
-
156
- Args:
157
- frame: Input video frame (BGR format)
158
- detections: Detection results to annotate
159
- labels: Optional list of labels for each detection
160
- line_zones: Optional list of line zones for counting visualization
161
-
162
- Returns:
163
- Annotated frame
164
- """
165
- # Create a copy to avoid modifying original
166
- annotated = frame.copy()
167
-
168
- try:
169
- # Draw polygon zone first (background layer)
170
- if self.polygon_drawer is not None:
171
- annotated = self.polygon_drawer.annotate(annotated)
172
-
173
- # Draw bounding boxes
174
- if self.box_drawer is not None and len(detections) > 0:
175
- annotated = self.box_drawer.annotate(
176
- scene=annotated,
177
- detections=detections
178
- )
179
-
180
- # Draw trajectory traces
181
- if self.trace_drawer is not None and len(detections) > 0:
182
- annotated = self.trace_drawer.annotate(
183
- scene=annotated,
184
- detections=detections
185
- )
186
-
187
- # Draw labels
188
- if self.label_drawer is not None and len(detections) > 0:
189
- annotated = self.label_drawer.annotate(
190
- scene=annotated,
191
- detections=detections,
192
- labels=labels
193
- )
194
-
195
- # Draw line zones
196
- if self.line_zone_drawer is not None and line_zones:
197
- for zone in line_zones:
198
- annotated = self.line_zone_drawer.annotate(
199
- frame=annotated,
200
- line_counter=zone
201
- )
202
-
203
- return annotated
204
-
205
- except Exception as e:
206
- logger.error(f"Error during annotation: {e}")
207
- # Return original frame if annotation fails
208
- return frame
209
-
210
- def update_settings(
211
- self,
212
- show_boxes: Optional[bool] = None,
213
- show_labels: Optional[bool] = None,
214
- show_traces: Optional[bool] = None,
215
- show_line_zones: Optional[bool] = None
216
- ) -> None:
217
- """
218
- Update annotation settings dynamically.
219
-
220
- Args:
221
- show_boxes: Enable/disable bounding boxes
222
- show_labels: Enable/disable labels
223
- show_traces: Enable/disable traces
224
- show_line_zones: Enable/disable line zones
225
- """
226
- if show_boxes is not None:
227
- self.show_boxes = show_boxes
228
- if show_labels is not None:
229
- self.show_labels = show_labels
230
- if show_traces is not None:
231
- self.show_traces = show_traces
232
- if show_line_zones is not None:
233
- self.show_line_zones = show_line_zones
234
-
235
- logger.info(f"Annotation settings updated: boxes={self.show_boxes}, "
236
- f"labels={self.show_labels}, traces={self.show_traces}, "
237
- f"zones={self.show_line_zones}")
 
1
+ """
2
+ Frame Annotation Module
3
+ ========================
4
+
5
+ Provides comprehensive video frame annotation capabilities for vehicle detection
6
+ visualization including bounding boxes, labels, trajectories, and counting zones.
7
+
8
+ Authors:
9
+ - Abhay Gupta (0205CC221005)
10
+ - Aditi Lakhera (0205CC221011)
11
+ - Balraj Patel (0205CC221049)
12
+ - Bhumika Patel (0205CC221050)
13
+ """
14
+
15
+ import numpy as np
16
+ import supervision as sv
17
+ from typing import List, Optional, Tuple
18
+ import logging
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ class FrameAnnotator:
24
+ """
25
+ Comprehensive frame annotation system for vehicle detection visualization.
26
+
27
+ This class manages multiple annotation layers including bounding boxes,
28
+ labels, object trajectories, counting lines, and detection zones.
29
+ """
30
+
31
+ def __init__(
32
+ self,
33
+ video_resolution: Tuple[int, int],
34
+ show_boxes: bool = True,
35
+ show_labels: bool = True,
36
+ show_traces: bool = True,
37
+ show_line_zones: bool = True,
38
+ trace_length: int = 20,
39
+ zone_polygon: Optional[np.ndarray] = None
40
+ ):
41
+ """
42
+ Initialize the frame annotator.
43
+
44
+ Args:
45
+ video_resolution: Video resolution as (width, height)
46
+ show_boxes: Enable bounding box annotations
47
+ show_labels: Enable label annotations
48
+ show_traces: Enable trajectory trace annotations
49
+ show_line_zones: Enable line zone annotations
50
+ trace_length: Maximum number of points in trajectory trace
51
+ zone_polygon: Optional polygon defining detection zone
52
+ """
53
+ self.resolution = video_resolution
54
+ self.show_boxes = show_boxes
55
+ self.show_labels = show_labels
56
+ self.show_traces = show_traces
57
+ self.show_line_zones = show_line_zones
58
+ self.zone_polygon = zone_polygon
59
+
60
+ # Calculate optimal annotation parameters based on resolution
61
+ self.line_thickness = sv.calculate_optimal_line_thickness(video_resolution)
62
+ self.text_scale = sv.calculate_optimal_text_scale(video_resolution)
63
+
64
+ logger.info(f"Initializing annotator for {video_resolution[0]}x{video_resolution[1]}")
65
+ logger.info(f"Line thickness: {self.line_thickness}, Text scale: {self.text_scale}")
66
+
67
+ # Initialize annotation components
68
+ self._setup_annotators(trace_length)
69
+
70
+ def _setup_annotators(self, trace_length: int) -> None:
71
+ """
72
+ Set up individual annotation components.
73
+
74
+ Args:
75
+ trace_length: Maximum trajectory trace length
76
+ """
77
+ # Bounding box annotator
78
+ if self.show_boxes:
79
+ self.box_drawer = sv.BoxAnnotator(
80
+ thickness=self.line_thickness,
81
+ color_lookup=sv.ColorLookup.TRACK
82
+ )
83
+ logger.debug("Box annotator initialized")
84
+ else:
85
+ self.box_drawer = None
86
+
87
+ # Label annotator
88
+ if self.show_labels:
89
+ self.label_drawer = sv.LabelAnnotator(
90
+ text_thickness=self.line_thickness,
91
+ text_scale=self.text_scale,
92
+ text_position=sv.Position.BOTTOM_CENTER,
93
+ color_lookup=sv.ColorLookup.TRACK
94
+ )
95
+ logger.debug("Label annotator initialized")
96
+ else:
97
+ self.label_drawer = None
98
+
99
+ # Trajectory trace annotator
100
+ if self.show_traces:
101
+ self.trace_drawer = sv.TraceAnnotator(
102
+ thickness=self.line_thickness,
103
+ trace_length=trace_length,
104
+ position=sv.Position.BOTTOM_CENTER,
105
+ color_lookup=sv.ColorLookup.TRACK
106
+ )
107
+ logger.debug(f"Trace annotator initialized with length {trace_length}")
108
+ else:
109
+ self.trace_drawer = None
110
+
111
+ # Line zone annotator
112
+ if self.show_line_zones:
113
+ self.line_zone_drawer = sv.LineZoneAnnotator(
114
+ thickness=self.line_thickness,
115
+ text_thickness=self.line_thickness,
116
+ text_scale=self.text_scale,
117
+ color=sv.Color.WHITE,
118
+ text_color=sv.Color.BLACK,
119
+ display_in_count=True,
120
+ display_out_count=True
121
+ )
122
+ logger.debug("Line zone annotator initialized")
123
+ else:
124
+ self.line_zone_drawer = None
125
+
126
+ # Polygon zone annotator (for detection area visualization)
127
+ if self.zone_polygon is not None:
128
+ try:
129
+ zone = sv.PolygonZone(polygon=self.zone_polygon)
130
+ self.polygon_drawer = sv.PolygonZoneAnnotator(
131
+ zone=zone,
132
+ color=sv.Color.GREEN,
133
+ thickness=self.line_thickness,
134
+ display_in_zone_count=False
135
+ )
136
+ logger.debug("Polygon zone annotator initialized")
137
+ except Exception as e:
138
+ logger.warning(f"Failed to initialize polygon zone: {e}")
139
+ self.polygon_drawer = None
140
+ else:
141
+ self.polygon_drawer = None
142
+
143
+ def draw_annotations(
144
+ self,
145
+ frame: np.ndarray,
146
+ detections: sv.Detections,
147
+ labels: Optional[List[str]] = None,
148
+ line_zones: Optional[List[sv.LineZone]] = None
149
+ ) -> np.ndarray:
150
+ """
151
+ Apply all enabled annotations to a video frame.
152
+
153
+ Args:
154
+ frame: Input video frame (BGR format)
155
+ detections: Detection results to annotate
156
+ labels: Optional list of labels for each detection
157
+ line_zones: Optional list of line zones for counting visualization
158
+
159
+ Returns:
160
+ Annotated frame
161
+ """
162
+ # Create a copy to avoid modifying original
163
+ annotated = frame.copy()
164
+
165
+ try:
166
+ # Draw polygon zone first (background layer)
167
+ if self.polygon_drawer is not None:
168
+ annotated = self.polygon_drawer.annotate(annotated)
169
+
170
+ # Draw bounding boxes
171
+ if self.box_drawer is not None and len(detections) > 0:
172
+ annotated = self.box_drawer.annotate(
173
+ scene=annotated,
174
+ detections=detections
175
+ )
176
+
177
+ # Draw trajectory traces
178
+ if self.trace_drawer is not None and len(detections) > 0:
179
+ annotated = self.trace_drawer.annotate(
180
+ scene=annotated,
181
+ detections=detections
182
+ )
183
+
184
+ # Draw labels
185
+ if self.label_drawer is not None and len(detections) > 0:
186
+ annotated = self.label_drawer.annotate(
187
+ scene=annotated,
188
+ detections=detections,
189
+ labels=labels
190
+ )
191
+
192
+ # Draw line zones
193
+ if self.line_zone_drawer is not None and line_zones:
194
+ for zone in line_zones:
195
+ annotated = self.line_zone_drawer.annotate(
196
+ frame=annotated,
197
+ line_counter=zone
198
+ )
199
+
200
+ return annotated
201
+
202
+ except Exception as e:
203
+ logger.error(f"Error during annotation: {e}")
204
+ # Return original frame if annotation fails
205
+ return frame
206
+
207
+ def update_settings(
208
+ self,
209
+ show_boxes: Optional[bool] = None,
210
+ show_labels: Optional[bool] = None,
211
+ show_traces: Optional[bool] = None,
212
+ show_line_zones: Optional[bool] = None
213
+ ) -> None:
214
+ """
215
+ Update annotation settings dynamically.
216
+
217
+ Args:
218
+ show_boxes: Enable/disable bounding boxes
219
+ show_labels: Enable/disable labels
220
+ show_traces: Enable/disable traces
221
+ show_line_zones: Enable/disable line zones
222
+ """
223
+ if show_boxes is not None:
224
+ self.show_boxes = show_boxes
225
+ if show_labels is not None:
226
+ self.show_labels = show_labels
227
+ if show_traces is not None:
228
+ self.show_traces = show_traces
229
+ if show_line_zones is not None:
230
+ self.show_line_zones = show_line_zones
231
+
232
+ logger.info(f"Annotation settings updated: boxes={self.show_boxes}, "
233
+ f"labels={self.show_labels}, traces={self.show_traces}, "
234
+ f"zones={self.show_line_zones}")