-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathsequence_verification.py
More file actions
194 lines (176 loc) · 8.14 KB
/
Copy pathsequence_verification.py
File metadata and controls
194 lines (176 loc) · 8.14 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
import argparse
import os
import sys
import time
from pathlib import Path
import numpy as np
import torch
import torch.backends.cudnn as cudnn
from colorama import Fore, Style
from random_word import RandomWords
from ultralytics.yolo.utils.ops import scale_boxes
from tools.arguments import parse_config
from tools.utils import ProgBar, disp_pred, initialize_digit_model, initialize_network, wait_for_input
from tools.visualizer import Visualizer
from typing import Tuple, Union, List, Optional, Dict
RANDOM_NAME = RandomWords()
FILE = Path(__file__).resolve()
ROOT = FILE.parents[0]
if str(ROOT) not in sys.path:
sys.path.append(str(ROOT))
ROOT = Path(os.path.relpath(ROOT, Path.cwd()))
os.environ["PYTORCH_ENABLE_MPS_FALLBACK"] = "1"
EPS = 1e-8
class SequenceVerification:
def __init__(self, args: argparse.Namespace = None):
self.args = args
self.init = True
self.log_time = False
if self.args is None:
self.args, self.data = parse_config()
# Setup the model, object tracker, transmitter, time logger, and logger.
self.model, self.names_object, self.device, self.live, self.object_tracker, self.transmitter, self.time_logger, self.logger, self.dd, self.names_digit = self.setup(self.args, self.data)
self.logger.info(f"Inference run stored @ ./logs/{self.args.name_run}")
self.logger.info(f"Streaming data to: YoloV8 using {self.args.weights}")
self.start_stream = time.monotonic()
if self.args.visualize:
self.vis_obj = Visualizer(names=self.names_object,
rescale=False,
line_thickness=self.args.line_thickness,
hide_labels=self.args.hide_labels,
hide_conf=self.args.hide_conf,
image_name="Object Detector")
if self.args.track_digits:
self.vis_dig = Visualizer(names=self.names_digit,
rescale=True,
line_thickness=self.args.line_thickness,
hide_labels=self.args.hide_labels,
hide_conf=self.args.hide_conf,
image_name="Digit Detector")
if self.args.prog_bar:
self.pbar = ProgBar(self.live.is_live, self.args.time)
def setup(self, args: argparse.Namespace, data: dict) -> Tuple:
"""
Set up the model, object tracker, transmitter, time logger, and logger.
Args:
args (argparse.Namespace): The command-line arguments.
data (dict): The data configuration.
Returns:
tuple: The model, object names, device, live stream, object tracker, transmitter, time logger, and logger.
"""
cudnn.benchmark = True
model, names_object, device, live, object_tracker, transmitter, time_logger, logger = initialize_network(args, data)
if args.track_digits:
dd, names_digit = initialize_digit_model(args, data, logger=logger)
else:
dd = None
return model, names_object, device, live, object_tracker, transmitter, time_logger, logger, dd, names_digit
def process_image(self, img0: np.ndarray, img: torch.Tensor) -> np.ndarray:
"""
Preprocess the image and run the inference.
Args:
img0 (numpy.ndarray): The original image.
img (torch.Tensor): The preprocessed image.
Returns:
numpy.ndarray: The predictions.
"""
if self.log_time:
self.time_logger.start("Pre Processing")
img = img.half() if self.args.half else img.float()
if self.log_time:
self.time_logger.stop("Pre Processing")
if self.log_time:
self.time_logger.start("Infrence")
results = self.model.predict(img,
augment=self.args.augment,
verbose=False,
nms=True,
conf=self.args.conf_thres,
iou=self.args.iou_thres,
imgsz=img.shape[2:])[0].cpu().numpy()
pred = results.boxes.data
pred[:, :4] = scale_boxes(img.shape[2:], pred[:, :4], img0.shape[:-1]).round()
if self.log_time:
self.time_logger.stop("Infrence")
return pred
def visualize(self, pred: np.ndarray, img0: np.ndarray, img: torch.Tensor) -> None:
"""
Visualize the predictions.
Args:
pred (numpy.ndarray): The predictions.
img0 (numpy.ndarray): The original image.
img (torch.Tensor): The preprocessed image.
"""
if self.args.disp_pred:
disp_pred(pred, self.names_object, self.logger)
if self.args.visualize:
if self.log_time:
self.time_logger.start("Visualize")
self.vis_obj.update(pred, img0, img)
if self.log_time:
self.time_logger.stop("Visualize")
def track_objects(self, pred: np.ndarray, img0: np.ndarray, img: torch.Tensor) -> None:
"""
Track objects and digits.
Args:
pred (numpy.ndarray): The predictions.
img0 (numpy.ndarray): The original image.
img (torch.Tensor): The preprocessed image.
"""
if self.args.track:
if self.log_time:
self.time_logger.start("Tracking Frames")
best_frame = self.object_tracker.update(pred, img0, img)
if self.log_time:
self.time_logger.stop("Tracking Frames")
if self.args.track_digits and (best_frame is not None or self.args.force_detect_digits):
if self.log_time:
self.time_logger.start("Tracking Digit")
img0 = best_frame["image"] if best_frame is not None else img0
sequence, valid, result_digit, pred_digit, img = self.dd.detect(
img0=best_frame["image"]) if not self.args.force_detect_digits or best_frame is not None else self.dd.detect(img0)
if self.args.visualize:
self.vis_dig.update(pred_digit, img0, img)
if self.log_time:
self.time_logger.stop("Tracking Digit")
if valid:
self.logger.info(f"Predicted Sequence: {Fore.GREEN}{sequence}{Style.RESET_ALL}\n")
def run(self) -> None:
"""
The main function to run the object detection.
"""
for i, (path, img0, img, _) in enumerate(self.live):
if not self.live.mode == "stream" and self.args.verbose:
self.logger.info(f"Image {i}/{len(self.live)}: {path}")
img0 = img0[0] if self.args.webcam else img0
if self.log_time:
self.time_logger.start("Internal Pipeline")
if self.args.prog_bar and not self.init:
self.pbar.step()
pred = self.process_image(img0, img)
self.visualize(pred, img0, img)
self.track_objects(pred, img0, img)
if self.args.disp_pred or self.args.verbose:
print("\n")
if self.init:
self.init = False
if self.log_time:
self.time_logger.stop("Internal Pipeline")
self.log_time = self.args.log_time
if (time.monotonic() - self.start_stream) > self.args.time and self.args.time != -1:
if self.args.prog_bar:
self.pbar.n = self.pbar.total
self.pbar.close()
break
if self.args.wait:
time.sleep(0.25)
wait_for_input(live=self.live, args=self.args)
if self.args.transmit:
self.transmitter.stop_transmit_udp()
self.transmitter.stop_transmit_ml()
if self.log_time:
self.time_logger.summarize()
self.logger.info("Stream Done")
if __name__ == '__main__':
obj_detection = SequenceVerification()
obj_detection.run()