Files
yolov8-position/ultralytics/yolo/engine/predictor.py
2023-08-10 12:25:23 +08:00

663 lines
31 KiB
Python

# Ultralytics YOLO 🚀, AGPL-3.0 license
"""
Run prediction on images, videos, directories, globs, YouTube, webcam, streams, etc.
Usage - sources:
$ yolo mode=predict model=yolov8n.pt source=0 # webcam
img.jpg # image
vid.mp4 # video
screen # screenshot
path/ # directory
list.txt # list of images
list.streams # list of streams
'path/*.jpg' # glob
'https://youtu.be/Zgi9g1ksQHc' # YouTube
'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream
Usage - formats:
$ yolo mode=predict model=yolov8n.pt # PyTorch
yolov8n.torchscript # TorchScript
yolov8n.onnx # ONNX Runtime or OpenCV DNN with dnn=True
yolov8n_openvino_model # OpenVINO
yolov8n.engine # TensorRT
yolov8n.mlmodel # CoreML (macOS-only)
yolov8n_saved_model # TensorFlow SavedModel
yolov8n.pb # TensorFlow GraphDef
yolov8n.tflite # TensorFlow Lite
yolov8n_edgetpu.tflite # TensorFlow Edge TPU
yolov8n_paddle_model # PaddlePaddle
"""
import math
import os
import platform
import time
from math import sqrt
from pathlib import Path
from random import random
import cv2
import numpy as np
import torch
from PIL import Image
from ultralytics.nn.autobackend import AutoBackend
from ultralytics.yolo.cfg import get_cfg
from ultralytics.yolo.data import load_inference_source
from ultralytics.yolo.data.augment import LetterBox, classify_transforms
from ultralytics.yolo.utils import DEFAULT_CFG, LOGGER, SETTINGS, callbacks, colorstr, ops
from ultralytics.yolo.utils.checks import check_imgsz, check_imshow
from ultralytics.yolo.utils.files import increment_path
from ultralytics.yolo.utils.torch_utils import select_device, smart_inference_mode
from ultralytics.yolo.engine.ids import check_tings
STREAM_WARNING = """
WARNING ⚠️ stream/video/webcam/dir predict source will accumulate results in RAM unless `stream=True` is passed,
causing potential out-of-memory errors for large sources or long-running streams/videos.
Usage:
results = model(source=..., stream=True) # generator of Results objects
for r in results:
boxes = r.boxes # Boxes object for bbox outputs
masks = r.masks # Masks object for segment masks outputs
probs = r.probs # Class probabilities for classification outputs
"""
class BasePredictor:
"""
BasePredictor
A base class for creating predictors.
Attributes:
args (SimpleNamespace): Configuration for the predictor.
save_dir (Path): Directory to save results.
done_setup (bool): Whether the predictor has finished setup.
model (nn.Module): Model used for prediction.
data (dict): Data configuration.
device (torch.device): Device used for prediction.
dataset (Dataset): Dataset used for prediction.
vid_path (str): Path to video file.
vid_writer (cv2.VideoWriter): Video writer for saving video output.
annotator (Annotator): Annotator used for prediction.
data_path (str): Path to data.
"""
def __init__(self, cfg=DEFAULT_CFG, overrides=None, _callbacks=None):
"""
Initializes the BasePredictor class.
Args:
cfg (str, optional): Path to a configuration file. Defaults to DEFAULT_CFG.
overrides (dict, optional): Configuration overrides. Defaults to None.
"""
# self.real_MovBox = None
self.args = get_cfg(cfg, overrides)
project = self.args.project or Path(SETTINGS['runs_dir']) / self.args.task
name = self.args.name or f'{self.args.mode}'
self.save_dir = increment_path(Path(project) / name, exist_ok=self.args.exist_ok)
if self.args.conf is None:
self.args.conf = 0.25 # default conf=0.25
self.done_warmup = False
if self.args.show:
self.args.show = check_imshow(warn=True)
# Usable if setup is done
self.model = None
self.data = self.args.data # data_dict
self.imgsz = None
self.device = None
self.dataset = None
self.vid_path, self.vid_writer = None, None
self.plotted_img = None
self.data_path = None
self.source_type = None
self.batch = None
self.callbacks = _callbacks or callbacks.get_default_callbacks()
callbacks.add_integration_callbacks(self)
def preprocess(self, im):
"""Prepares input image before inference.
Args:
im (torch.Tensor | List(np.ndarray)): (N, 3, h, w) for tensor, [(h, w, 3) x N] for list.
"""
if not isinstance(im, torch.Tensor):
im = np.stack(self.pre_transform(im)) #size(640,XX)
im = im[..., ::-1].transpose((0, 3, 1, 2)) # BGR to RGB, BHWC to BCHW, (n, 3, h, w)
im = np.ascontiguousarray(im) # contiguous
im = torch.from_numpy(im)
# NOTE: assuming im with (b, 3, h, w) if it's a tensor
img = im.to(self.device)
img = img.half() if self.model.fp16 else img.float() # uint8 to fp16/32
img /= 255 # 0 - 255 to 0.0 - 1.0
return img
def pre_transform(self, im):
"""Pre-tranform input image before inference.
Args:
im (List(np.ndarray)): (N, 3, h, w) for tensor, [(h, w, 3) x N] for list.
Return: A list of transformed imgs.
"""
same_shapes = all(x.shape == im[0].shape for x in im)
auto = same_shapes and self.model.pt
return [LetterBox(self.imgsz, auto=auto, stride=self.model.stride)(image=x) for x in im]
def write_results(self, idx, results, batch):
"""Write inference results to a file or directory."""
p, im, _ = batch
log_string = ''
if len(im.shape) == 3:
im = im[None] # expand for batch dim
self.seen += 1
if self.source_type.webcam or self.source_type.from_img: # batch_size >= 1
log_string += f'{idx}: '
frame = self.dataset.count
else:
frame = getattr(self.dataset, 'frame', 0)
self.data_path = p
self.txt_path = str(self.save_dir / 'labels' / p.stem) + ('' if self.dataset.mode == 'image' else f'_{frame}')
log_string += '%gx%g ' % im.shape[2:] # print string
result = results[idx]
# print('result', result)
log_string += result.verbose()
if self.args.save or self.args.show: # Add bbox to image
plot_args = dict(line_width=self.args.line_width,
boxes=self.args.boxes,
conf=self.args.show_conf,
labels=self.args.show_labels)
if not self.args.retina_masks:
plot_args['im_gpu'] = im[idx]
self.plotted_img = result.plot(**plot_args)
# Write
if self.args.save_txt:
result.save_txt(f'{self.txt_path}.txt', save_conf=self.args.save_conf)
if self.args.save_crop:
result.save_crop(save_dir=self.save_dir / 'crops', file_name=self.data_path.stem)
return log_string
def postprocess(self, preds, img, orig_img):
"""Post-processes predictions for an image and returns them."""
return preds
def boxesMov_output(self, path, img_MovBoxes):
return img_MovBoxes
def __call__(self, source=None, model=None, stream=False):
"""Performs inference on an image or stream."""
self.stream = stream
if stream:
return self.stream_inference(source, model)
else:
# print('*****************',list(self.stream_inference(source, model)))
return list(self.stream_inference(source, model)) # merge list of Result into one
def predict_cli(self, source=None, model=None):
"""Method used for CLI prediction. It uses always generator as outputs as not required by CLI mode."""
gen = self.stream_inference(source, model)
for _ in gen: # running CLI inference without accumulating any outputs (do not modify)
pass
def setup_source(self, source):
"""Sets up source and inference mode."""
self.imgsz = check_imgsz(self.args.imgsz, stride=self.model.stride, min_dim=2) # check image size
self.transforms = getattr(self.model.model, 'transforms', classify_transforms(
self.imgsz[0])) if self.args.task == 'classify' else None
self.dataset = load_inference_source(source=source, imgsz=self.imgsz, vid_stride=self.args.vid_stride)
self.dataset0 = load_inference_source(source=source, imgsz=self.imgsz, vid_stride=self.args.vid_stride)
self.source_type = self.dataset.source_type
if not getattr(self, 'stream', True) and (self.dataset.mode == 'stream' or # streams
len(self.dataset) > 1000 or # images
any(getattr(self.dataset, 'video_flag', [False]))): # videos
LOGGER.warning(STREAM_WARNING)
self.vid_path, self.vid_writer = [None] * self.dataset.bs, [None] * self.dataset.bs
@smart_inference_mode()
def stream_inference(self, source=None, model=None):
"""Streams real-time inference on camera feed and saves results to file."""
if self.args.verbose:
LOGGER.info('')
# Setup model
if not self.model:
self.setup_model(model)
# Setup source every time predict is called
self.setup_source(source if source is not None else self.args.source)
# Check if save_dir/ label file exists
if self.args.save or self.args.save_txt:
(self.save_dir / 'labels' if self.args.save_txt else self.save_dir).mkdir(parents=True, exist_ok=True)
# Warmup model
if not self.done_warmup:
self.model.warmup(imgsz=(1 if self.model.pt or self.model.triton else self.dataset.bs, 3, *self.imgsz))
self.done_warmup = True
self.seen, self.windows, self.batch, self.batch0, profilers = 0, [], None, None, (ops.Profile(), ops.Profile(), ops.Profile())
self.run_callbacks('on_predict_start')
allMovBoxes = []
boxesAll = []
id = 0
img_MovBoxes = []
idx = []
id0 = 0
fgbg = cv2.createBackgroundSubtractorMOG2(history=500, varThreshold=16, detectShadows=True)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
for batch0 in self.dataset0:
path, im0, vid_cap, s = batch0
id0 += 1
# video_len = int(str(s).split(')')[0].split('/')[-1])
# print('video_len', id0, video_len)
img0 = np.array(im0).squeeze()
frame = cv2.resize(img0, (512, 640), interpolation=cv2.INTER_CUBIC)
frame = cv2.medianBlur(frame, ksize=3)
# 计算前景掩码
fgmask = fgbg.apply(frame)
draw1 = cv2.threshold(fgmask, 230, 255, cv2.THRESH_BINARY)[1] # 二值化
draw1 = cv2.erode(draw1, kernel, iterations=1)
draw1 = cv2.dilate(draw1, kernel, iterations=1)
dics = {}
contours_m, hierarchy_m = cv2.findContours(draw1.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours_m:
dics[len(contour)] = contour
if len(dics.keys()) > 0:
cc = sorted(dics.keys())
iouArea = cv2.contourArea(dics[cc[-1]])
print("***********id0", id0, iouArea)
if iouArea>3000:
idx.append(id0)
# if len(idx) != 0 and abs(id0 - idx[-1]) > 30:
# break
# print('*******id0', id0, idx)
if len(idx) != 0:
idx.sort()
print('idx', idx)
for batch in self.dataset:
t0 = time.time()
id += 1
if idx[0] <= id <= idx[-1]:
self.run_callbacks('on_predict_batch_start')
self.batch = batch
path, im0s, vid_cap, s = batch
visualize = increment_path(self.save_dir / Path(path[0]).stem,
mkdir=True) if self.args.visualize and (not self.source_type.tensor) else False
# Preprocess
with profilers[0]:
im = self.preprocess(im0s)
# Inference
with profilers[1]:
preds = self.model(im, augment=self.args.augment, visualize=visualize)
# Postprocess
with profilers[2]:
self.results = self.postprocess(preds, im, im0s)
self.run_callbacks('on_predict_postprocess_end')
# Visualize, save, write results
n = len(im0s)
for i in range(n):
tt0 = time.time()
im1 = im0s[i].copy()
### create class MovingBox
boxesMov = MovingBox(id, self.results[i].boxes.xywh, self.results[i].boxes.xyxy, self.results[i].boxes.conf, path)
if id == idx[0]:
boxesAll= boxesMov._initiate_box()
else:
### allMovBoxes->是运动框的坐标
boxesAll, allMovBoxes = boxesMov.update(boxesAll, im1, self.save_dir)
if len(allMovBoxes) != 0:
mov_id = 0
for box in allMovBoxes:
box_xyxy = xywh2xyxy(box[0])
cropMov = im0s[i][int(box_xyxy[1]):int(box_xyxy[3]), int(box_xyxy[0]):int(box_xyxy[2]), ::-1]
# crop_save = os.path.abspath(im0s[i])
# Image.fromarray(cropMov).show()
### img_MovBoxes->运动商品图片
img_MovBoxes.append([id, cropMov])
tt1 = time.time() - tt0
# print('运动框判断所需时间{}s'.format(tt1))
crop_save = self.save_dir / 'movboxes/'
ori_img = self.save_dir / 'oriImage/'
if not os.path.exists(crop_save):
# crop_save.parent.mkdir(parents=True, exist_ok=True)
crop_save.mkdir(parents=True, exist_ok=True)
if not os.path.exists(ori_img):
ori_img.mkdir()
f = str(crop_save) + '\\frame' + str(id) + '_' + str(mov_id) + '_' + '.jpg'
g = str(ori_img) + '\\frame' + str(id) + '_' + '.jpg'
# Image.fromarray(cropMov[::-1]).save(f, quality=95, subsampling=0)
Image.fromarray(cropMov).save(f, quality=95, subsampling=0)
# Image.fromarray(im1[:,:,::-1]).save(g, quality=95, subsampling=0)
mov_id += 1
self.results[i].speed = {
'preprocess': profilers[0].dt * 1E3 / n,
'inference': profilers[1].dt * 1E3 / n,
'postprocess': profilers[2].dt * 1E3 / n}
if self.source_type.tensor: # skip write, show and plot operations if input is raw tensor
continue
p, im0 = path[i], im0s[i].copy()
p = Path(p)
if self.args.verbose or self.args.save or self.args.save_txt or self.args.show:
s += self.write_results(i, self.results, (p, im, im0))
if self.args.show and self.plotted_img is not None:
self.show(p)
if self.args.save and self.plotted_img is not None:
self.save_preds(vid_cap, i, str(self.save_dir / p.name))
elif id < idx[0]:
# self.results = []
continue
else:
break
else:
for batch in self.dataset:
t0 = time.time()
id += 1
self.run_callbacks('on_predict_batch_start')
self.batch = batch
path, im0s, vid_cap, s = batch
visualize = increment_path(self.save_dir / Path(path[0]).stem,
mkdir=True) if self.args.visualize and (
not self.source_type.tensor) else False
# Preprocess
with profilers[0]:
im = self.preprocess(im0s)
# Inference
with profilers[1]:
preds = self.model(im, augment=self.args.augment, visualize=visualize)
# Postprocess
with profilers[2]:
self.results = self.postprocess(preds, im, im0s)
self.run_callbacks('on_predict_postprocess_end')
# Visualize, save, write results
n = len(im0s)
for i in range(n):
tt0 = time.time()
im1 = im0s[i].copy()
### create class MovingBox
boxesMov = MovingBox(id, self.results[i].boxes.xywh, self.results[i].boxes.xyxy,
self.results[i].boxes.conf, path)
if id == 1:
boxesAll = boxesMov._initiate_box()
else:
### allMovBoxes->是运动框的坐标
boxesAll, allMovBoxes = boxesMov.update(boxesAll, im1, self.save_dir)
if len(allMovBoxes) != 0:
mov_id = 0
for box in allMovBoxes:
box_xyxy = xywh2xyxy(box[0])
cropMov = im0s[i][int(box_xyxy[1]):int(box_xyxy[3]), int(box_xyxy[0]):int(box_xyxy[2]),
::-1]
# crop_save = os.path.abspath(im0s[i])
# Image.fromarray(cropMov).show()
### img_MovBoxes->运动商品图片
img_MovBoxes.append([id, cropMov])
tt1 = time.time() - tt0
# print('运动框判断所需时间{}s'.format(tt1))
crop_save = self.save_dir / 'movboxes/'
ori_img = self.save_dir / 'oriImage/'
if not os.path.exists(crop_save):
# crop_save.parent.mkdir(parents=True, exist_ok=True)
crop_save.mkdir(parents=True, exist_ok=True)
if not os.path.exists(ori_img):
ori_img.mkdir()
f = str(crop_save) + '\\frame' + str(id) + '_' + str(mov_id) + '_' + '.jpg'
g = str(ori_img) + '\\frame' + str(id) + '_' + '.jpg'
# Image.fromarray(cropMov[::-1]).save(f, quality=95, subsampling=0)
Image.fromarray(cropMov).save(f, quality=95, subsampling=0)
# Image.fromarray(im1[:,:,::-1]).save(g, quality=95, subsampling=0)
mov_id += 1
self.results[i].speed = {
'preprocess': profilers[0].dt * 1E3 / n,
'inference': profilers[1].dt * 1E3 / n,
'postprocess': profilers[2].dt * 1E3 / n}
if self.source_type.tensor: # skip write, show and plot operations if input is raw tensor
continue
p, im0 = path[i], im0s[i].copy()
p = Path(p)
if self.args.verbose or self.args.save or self.args.save_txt or self.args.show:
s += self.write_results(i, self.results, (p, im, im0))
if self.args.show and self.plotted_img is not None:
self.show(p)
if self.args.save and self.plotted_img is not None:
self.save_preds(vid_cap, i, str(self.save_dir / p.name))
self.run_callbacks('on_predict_batch_end')
yield from self.results
# Print time (inference-only)
if self.args.verbose:
LOGGER.info(f'{s}{profilers[1].dt * 1E3:.1f}ms')
t1 = time.time() - t0
# print('推理所需时间:{}s'.format(t1))
t2 = time.time()
self.real_MovBox = self.boxesMov_output(path, img_MovBoxes)
for i in range(len(self.results)):
self.results[i].movBoxes = self.real_MovBox
# print("self.results11111111111", self.results[i])
t3 = time.time() - t2
print('保留最后十帧所有运动框所需时间:{}s'.format(t3))
# Release assets
if isinstance(self.vid_writer[-1], cv2.VideoWriter):
self.vid_writer[-1].release() # release final video writer
# Print results
if self.args.verbose and self.seen:
t = tuple(x.t / self.seen * 1E3 for x in profilers) # speeds per image
LOGGER.info(f'Speed: %.1fms preprocess, %.1fms inference, %.1fms postprocess per image at shape '
f'{(1, 3, *self.imgsz)}' % t)
if self.args.save or self.args.save_txt or self.args.save_crop:
nl = len(list(self.save_dir.glob('labels/*.txt'))) # number of labels
s = f"\n{nl} label{'s' * (nl > 1)} saved to {self.save_dir / 'labels'}" if self.args.save_txt else ''
LOGGER.info(f"Results saved to {colorstr('bold', self.save_dir)}{s}")
self.run_callbacks('on_predict_end')
def setup_model(self, model, verbose=True):
"""Initialize YOLO model with given parameters and set it to evaluation mode."""
device = select_device(self.args.device, verbose=verbose)
model = model or self.args.model
self.args.half &= device.type != 'cpu' # half precision only supported on CUDA
self.model = AutoBackend(model,
device=device,
dnn=self.args.dnn,
data=self.args.data,
fp16=self.args.half,
fuse=True,
verbose=verbose)
self.device = device
self.model.eval()
def show(self, p):
"""Display an image in a window using OpenCV imshow()."""
im0 = self.plotted_img
if platform.system() == 'Linux' and p not in self.windows:
self.windows.append(p)
cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO) # allow window resize (Linux)
cv2.resizeWindow(str(p), im0.shape[1], im0.shape[0])
cv2.imshow(str(p), im0)
cv2.waitKey(500 if self.batch[3].startswith('image') else 1) # 1 millisecond
def save_preds(self, vid_cap, idx, save_path):
"""Save video predictions as mp4 at specified path."""
im0 = self.plotted_img
# Save imgs
if self.dataset.mode == 'image':
cv2.imwrite(save_path, im0)
else: # 'video' or 'stream'
if self.vid_path[idx] != save_path: # new video
self.vid_path[idx] = save_path
if isinstance(self.vid_writer[idx], cv2.VideoWriter):
self.vid_writer[idx].release() # release previous video writer
if vid_cap: # video
fps = int(vid_cap.get(cv2.CAP_PROP_FPS)) # integer required, floats produce error in MP4 codec
w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
else: # stream
fps, w, h = 30, im0.shape[1], im0.shape[0]
save_path = str(Path(save_path).with_suffix('.mp4')) # force *.mp4 suffix on results videos
self.vid_writer[idx] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h))
self.vid_writer[idx].write(im0)
def run_callbacks(self, event: str):
"""Runs all registered callbacks for a specific event."""
for callback in self.callbacks.get(event, []):
callback(self)
def add_callback(self, event: str, func):
"""
Add callback
"""
self.callbacks[event].append(func)
class BoxState:
Static = 0
Moving = 1
class allBoxes:
def __init__(self, fame_id, tr_id, xywh):
self.fame_id = fame_id
self.state = BoxState.Static
self.track_id = tr_id
self.xywh = xywh
def is_static(self):
return self.state == BoxState.Static
def is_moving(self):
return self.state == BoxState.Moving
def xywh2xyxy(x):
# Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right
y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)
y[0] = x[0] - x[2] / 2 # top left x
y[1] = x[1] - x[3] / 2 # top left y
y[2] = x[0] + x[2] / 2 # bottom right x
y[3] = x[1] + x[3] / 2 # bottom right y
return y
def plot_one_box(x, img, trid, line_thickness=3,color=None):
# Plots one bounding box on image img
tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # line/font thickness
# print('x',x)
c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3]))
cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA)
cv2.putText(img, str(trid), (c1[0], c1[1] - 2), 0, tl / 3, [0, 0, 255], thickness=6, lineType=cv2.LINE_AA)
def compute_iou(box1, box2):
xx1 = max(box1[0], box2[0])
yy1 = max(box1[1], box2[1])
xx2 = min(box1[2], box2[2])
yy2 = min(box1[3], box2[3])
w = max(0., xx2 - xx1)
h = max(0., yy2 - yy1)
wh = w * h
o = wh / ((box1[2] - box1[0]) * (box1[3] - box1[1])
+ (box2[2] - box2[0]) * (box2[3] - box2[1]) - wh)
return o
# def sort_(elem):
# return elem[0]
class MovingBox(object):
def __init__(self, frame_id, xywh, xyxy, conf, path):
# self.track_id = 0
self.frame_id = frame_id
# self.state = 1 # 0 static, 1 moving
self.xywh = xywh
self.conf = conf
self.xyxy = xyxy
self.min_thr = 0.8
self.max_thr = 1.2
self.iou_thr = 0.9
self.path = path
def _initiate_box(self):
boxes = []
state = 0
for i in range(len(self.xywh)):
boxes.append([self.xywh[i], state, self.xyxy[i]])
# print('moving_box', boxes)
return boxes
def update(self, boxes, img, save_dir):
index = []
allBoxes = []
state = 1
print(">>>>>>>>>>>>id", self.frame_id)
# if len(self.xywh) != 0: ##detect box 不为空
if len(boxes) == 0:
for i in range(len(self.xywh)):
allBoxes.append([self.xywh[i], state, self.xyxy[i]])
else:
for i in range(len(self.xywh)): ## self.xywh为当前帧的检测框
flag0 = 0 # 0 长宽比未匹配上, 1 匹配上
for j in range(len(boxes)): ## boxes为前一帧的检测框
rw = self.xywh[i][2] / boxes[j][0][2]
rh = self.xywh[i][3] / boxes[j][0][3]
area0 = boxes[j][0][2] * boxes[j][0][3]
area1 = self.xywh[i][2] * self.xywh[i][3]
area_r = area1 / area0
# print(f'detect_{i} track_{j}')
# print("rw,rh,area_r", rw, rh, area_r)
##可能短边比长边,可能长边比短边
if (rw < self.max_thr and rw > self.min_thr) and (rh < self.max_thr and rh > self.min_thr) \
and (area_r < self.max_thr and area_r > self.min_thr):
flag0 = 1
iou = compute_iou(self.xyxy[i], boxes[j][2])
print('iou',iou)
if iou > self.iou_thr:
index.append(i)
break
print("=====last_box", boxes)
print('index', index)
for i in range(len(self.xywh)):
if i in index:
state = 0
allBoxes.append([self.xywh[i], state, self.xyxy[i]])
else:
state = 1
allBoxes.append([self.xywh[i], state, self.xyxy[i]])
# track_id += 1
moving_boxes = [box for box in allBoxes if box[1]==1]
if len(self.xywh) != 0:
for i, x in enumerate(allBoxes):
xyxy = xywh2xyxy(x[0])
if x[1] == 1:
# flag = str(i) + '_moving_'
flag = 'moving_'
box_color = (0,255,0)
else:
# flag = str(i) + '_static_'
flag = 'static_'
box_color = (0,0,255)
plot_one_box(xyxy, img, f'{flag}{self.conf[i].cpu().numpy():.2f}', color=box_color)
path2 = save_dir / 'detect_result/'
if not os.path.exists(path2):
path2.mkdir(parents=True, exist_ok=True)
cv2.imwrite(os.sep.join([str(path2), str(self.path).split('.mp4')[0].split('\\')[-1]+ "_" + str(self.frame_id) + '.jpg']), img)
else:
path2 = save_dir / 'detect_result/'
if not os.path.exists(path2):
path2.mkdir(parents=True, exist_ok=True)
cv2.imwrite(os.sep.join([str(path2), str(self.path).split('.mp4')[0].split('\\')[-1] + "_" + str(self.frame_id) + '.jpg']), img)
return allBoxes, moving_boxes