宠物网站设计首页模板,九江建网站公司有哪些,ui设计培训是什么,友情链接的定义尽管YOLOv8已经集成了ByteTrack算法#xff0c;但在这里我还是想利用ByteTrack官网的代码#xff0c;自己实现目标跟踪。
要想应用ByteTrack算法#xff0c;首先就要从ByteTrack官网上下载并安装。虽然官网上介绍得很简单#xff0c;只需要区区6行代码#xff0c;但对于国…尽管YOLOv8已经集成了ByteTrack算法但在这里我还是想利用ByteTrack官网的代码自己实现目标跟踪。
要想应用ByteTrack算法首先就要从ByteTrack官网上下载并安装。虽然官网上介绍得很简单只需要区区6行代码但对于国内用户来说要想安装ByteTrack只要这些代码是万万不会成功的。我按照复现经典目标跟踪算法ByteTrack之路调通第一个demo这个网站介绍的安装过程成功地实现了ByteTrack的部署。该博文介绍得很详细我在这里就不再赘述了。下面我详细介绍如何应用ByteTrack。
我们首先给出ByteTrack的核心关键代码。
导入ByteTrack
import sys
sys.path.append(fD:/ByteTrack)
from yolox.tracker.byte_tracker import BYTETracker
D:\ByteTrack为下载ByteTrack时其所在的目录。
下面设置ByteTrack的参数
class BYTETrackerArgs:track_thresh: float 0.25track_buffer: int 30match_thresh: float 0.8aspect_ratio_thresh: float 3.0min_box_area: float 1.0mot20: bool False
track_thresh表示跟踪置信阈值。简单地说该值越大被赋予目标跟踪ID的数量越少也就意味着系统会把不太确定的轨迹抛弃掉。默认值为0.5。
track_buffer用于保留丢失轨迹的帧数。对于没有出现的ID最多保留该值的帧数。默认值为30。
match_thresh表示跟踪匹配阈值。该值越大目标与轨迹越容易匹配上。默认值为0.8。
aspect_ratio_thresh表示目标边框长宽之比的阈值。目标长宽之比大于该值时会把该目标滤除掉这是因为长宽比过大时显然它不会是任何物体。默认值为1.6。
min_box_area表示目标边框的面积阈值。目标面积小于该值时会把该目标滤除掉。默认值为10。
mot20表示是否使用mot20数据集进行测试。默认值为False。
实例化ByteTrack并带入参数
byte_tracker BYTETracker(BYTETrackerArgs(), frame_ratefps)
frame_rate表示视频每秒传输的帧数。默认值为30。
得到目标ID
tracks byte_tracker.update(outputs, img_infoframe.shape, img_sizeframe.shape)
outputs表示目标检测器的输出ByteTrack需要先进行目标检测然后才能利用ByteTrack算法实现跟踪outputs应为二维数组第一维表示目标第二维表示该目标的信息其前四个元素为目标边框的左上角和右下角的坐标第5个元素为该目标的得分值一般我们可以为该值赋予目标的置信值。
img_info表示输入视频图像的尺寸。
img_size表示输出图像的尺寸如果不对视频图像的尺寸进行改变的话就让该值等于img_info。
输出tracks即为目标跟踪的结果我们先用print(tracks)看看它的输出
[OT_2_(1-28), OT_3_(1-28), OT_4_(1-28), OT_7_(26-28)]
从中可以看出我们共得到了4个目标跟踪结果它们的ID分别为2、3、4和7其中ID为2的目标在第1帧开始出现28为当前帧数即在第28帧时我们使用了print(tracks)这个代码。
我们再看看tracks的几个重要属性
print(tracks[0].tlbr)
print(tracks[0].tlwh)
print(tracks[0].track_id)
print(tracks[0].score)
输出为
[ 820.39 184.35 852.77 204.6]
[ 820.39 184.35 32.382 20.246]
2
0.7806676
tlbr表示该目标边框的左上角和右下角坐标tlwh表示该目标边框的左上角坐标和它的长宽track_id表示该目标的IDscore表示该目标的得分值。
有了目标ID我们就可以为视频添加各类信息如为目标添加ID和类别以及绘制目标边框。我们可以直接利用tracks完成上述操作但这里会有几个问题第一由tracks得到的目标边框没有由outputs得到的目标边框准确第二tracks没有目标类别信息。因此在这里我们还是利用outputs为目标添加各类信息它要解决的问题是目标的ID是什么。
我们只需比较outputs和tracks的目标尺寸完成匹配成对就可以为outputs中的目标赋予ID。我们利用IOU算法来实现尺寸比较为此我们编写下面函数
def iou(box: np.ndarray, boxes: np.ndarray):# 计算交集xy_max np.minimum(boxes[:, 2:], box[2:])xy_min np.maximum(boxes[:, :2], box[:2])inter np.clip(xy_max-xy_min, a_min0, a_maxnp.inf)inter inter[:, 0]*inter[:, 1]# 计算面积area_boxes (boxes[:, 2]-boxes[:, 0])*(boxes[:, 3]-boxes[:, 1])area_box (box[2]-box[0])*(box[3]-box[1])return inter/(area_boxarea_boxes-inter)
对于这个函数我们不做过多解释它实现一对多的计算。下面给出它的应用
for track in tracks:box_iou iou(track.tlbr, outputs[:,:4])maxindex np.argmax(box_iou)newoutput np.append(outputs[maxindex], track.track_id)print(newoutput)输出为
[820.86 184.48 852.67 204.75 0.78067 2 2]
[766.21 212.08 808.44 246.9 0.73741 2 3]
[479.06 178.3 517.84 217.07 0.68729 2 4]
[508.42 147.98 529.87 165.88 0.62819 2 7]
每行的最后一个元素就是它的ID。
ByteTrack严重依赖于目标检测器的准确性。ByteTrack利用每个目标的得分值来计算目标跟踪并赋予ID。我们一般都是把目标检测得到的置信值作为这个得分值传递给ByteTrack作为其计算的依据。因此当置信值偏低并且track_thresh偏高时会出现tracks得到的目标少于outputs的目标也就出现了有一些目标没有被赋予ID。
为了减少这类问题出现我们可以人为的为目标置信值赋予更高的值充分信任目标检测器然后再传给ByteTrack即
for output in outputs:output[4] 0.95
应用ByteTrack进行目标跟踪的关键部分我们都解释清楚了下面就给出完整的代码在这里我们仍然选择YOLOv8作为目标检测器除了YOLO易于实现外另一个原因是它的输出与ByteTrack所要求的数据输入的格式完全相同
import numpy as np
import cv2
from ultralytics import YOLO
import sys
sys.path.append(fD:/ByteTrack)
from yolox.tracker.byte_tracker import BYTETrackerclass BYTETrackerArgs:track_thresh: float 0.25 track_buffer: int 30 match_thresh: float 0.8 aspect_ratio_thresh: float 3.0min_box_area: float 1.0mot20: bool False model YOLO(yolov8l.pt)cap cv2.VideoCapture(D:/track/Highway Traffic.mp4)
fps cap.get(cv2.CAP_PROP_FPS)
size (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
fNUMS cap.get(cv2.CAP_PROP_FRAME_COUNT)
fourcc cv2.VideoWriter_fourcc(*mp4v)
videoWriter cv2.VideoWriter(D:/track/mytrack.mp4, fourcc, fps, size)byte_tracker BYTETracker(BYTETrackerArgs(),frame_rate fps)def box_label(image, box, label, color(128, 128, 128), txt_color(255, 255, 255)):p1, p2 (int(box[0]), int(box[1])), (int(box[2]), int(box[3]))cv2.rectangle(image, p1, p2, color, thickness1, lineTypecv2.LINE_AA)if label:w, h cv2.getTextSize(label, 0, fontScale2 / 3, thickness1)[0] outside p1[1] - h 3p2 p1[0] w, p1[1] - h - 3 if outside else p1[1] h 3cv2.rectangle(image, p1, p2, color, -1, cv2.LINE_AA)cv2.putText(image,label, (p1[0], p1[1] - 2 if outside else p1[1] h 2),0, 2/3, txt_color, thickness1, lineTypecv2.LINE_AA)def iou(box: np.ndarray, boxes: np.ndarray):xy_max np.minimum(boxes[:, 2:], box[2:])xy_min np.maximum(boxes[:, :2], box[:2])inter np.clip(xy_max-xy_min, a_min0, a_maxnp.inf)inter inter[:, 0]*inter[:, 1]area_boxes (boxes[:, 2]-boxes[:, 0])*(boxes[:, 3]-boxes[:, 1])area_box (box[2]-box[0])*(box[3]-box[1])return inter/(area_boxarea_boxes-inter)while cap.isOpened():success, frame cap.read()if success: results model(frame,conf0.5)outputs results[0].boxes.data.cpu().numpy()if outputs is not None:for output in outputs:output[4] 0.95tracks byte_tracker.update(outputs[:,:5], img_infoframe.shape, img_sizeframe.shape)for track in tracks:box_iou iou(track.tlbr, outputs[:,:4])maxindex np.argmax(box_iou)if outputs[maxindex, 5] 2:box_label(frame, outputs[maxindex], #str(track.track_id) car , (167, 146, 11))elif outputs[maxindex, 5] 5:box_label(frame, outputs[maxindex], #str(track.track_id) bus, (186, 55, 2))elif outputs[maxindex, 5] 7:box_label(frame, outputs[maxindex], #str(track.track_id) truck, (19, 222, 24))cv2.putText(frame, https://blog.csdn.net/zhaocj, (25, 50),cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)cv2.imshow(ByteTrack, frame)videoWriter.write(frame)if cv2.waitKey(1) 0xFF ord(q):breakelse:breakcap.release()
videoWriter.release()
cv2.destroyAllWindows()
结果为 ByteTrack 我们也可以再看一个示例 people