YOLOv8测速测距车辆计数系统 ByteTrack算法 深度学习 目标计数 目标测速 目标检测
2026/4/11 8:23:22 网站建设 项目流程

博主介绍:✌全网粉丝10W+,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业项目实战6年之久,选择我们就是选择放心、选择安心毕业✌
> 🍅想要获取完整文章或者源码,或者代做,拉到文章底部即可与我联系了。🍅

点击查看作者主页,了解更多项目!

🍅感兴趣的可以先收藏起来,点赞、关注不迷路,大家在毕设选题,项目以及论文编写等相关问题都可以给我留言咨询,希望帮助同学们顺利毕业 。🍅

1、毕业设计:2025年计算机专业毕业设计选题汇总(建议收藏)✅

2、最全计算机专业毕业设计选题大全(建议收藏)✅

1、项目介绍

技术栈:
Python语言、YOLOv8、ByteTrack算法 YOLOv8测速+测距+车辆计数、目标计数+目标测速

2、项目界面

(1)测速测距车辆计数界面1

(2)测速测距车辆计数界面2

(3)测速测距车辆计数界面3

3、项目说明

技术栈:
Python语言、YOLOv8、ByteTrack算法 YOLOv8测速+测距+车辆计数、目标计数+目标测速

ByteTrack是基于tracking-by-detection范式的跟踪方法。大多数多目标跟踪方法通过关联分数高于阈值的检测框来获取目标ID。
对于检测分数较低的目标,例如遮挡目标,会被简单的丢弃,这带来了不可忽略的问题,
包括大量的漏检和碎片化轨迹。为了解决该问题,作者提出了一种简单、高效且通用的数据关联方法BYTE,
通过关联每个检测框而不仅仅是高分检测框来进行跟踪。对于低分检测框,利用它们与轨迹的相似性来恢复真实目标并过滤掉背景检测。
ByteTrack 使用当前性能非常优秀的检测器 YOLOX 得到检测结果。
在数据关联的过程中,和 SORT 一样,只使用卡尔曼滤波来预测当前帧的跟踪轨迹在下一帧的位置,
预测的框和实际的检测框之间的 IoU 作为两次匹配时的相似度,通过匈牙利算法完成匹配。
这里值得注意的是我们没有使用 ReID 特征来计算外观相似度

实现了一个基于YOLO目标检测和ByteTrack跟踪算法的视频分析系统,主要用于检测视频中的目标(如车辆或行人)、跟踪它们的运动轨迹,并计算它们的速度和流量(如进入和离开的计数)。
实现原理和步骤的详细描述:


  1. 参数解析**
    代码使用argparse模块解析命令行参数,这些参数包括:
  • 检测模型权重路径(--weights)。
  • 输入视频路径(--source)。
  • 输出保存路径(--save)。
  • 检测和跟踪相关的阈值(如置信度阈值--conf_thre、IoU阈值--iou_thre、跟踪阈值--track_thresh等)。
  • 相机参数(如高度--H、角度--alpha、相机内参--calib)。

这些参数为后续的目标检测、跟踪和距离计算提供了必要的配置。


  1. 相机内参解析**
    相机内参--calib以字符串形式输入,代码将其转换为一个3×3的numpy数组,用于后续的深度计算。

  1. 目标检测**
    代码使用ultralytics的YOLO模型进行目标检测:
  • 加载YOLO模型(YOLO(weight_path))。
  • 对每一帧图像使用YOLO模型进行检测,获取检测框(boxes)、置信度(confidences)和类别(class_preds)。
  • 将检测结果传递给跟踪模块。

  1. 目标跟踪**
    代码使用ByteTrack跟踪算法对检测到的目标进行跟踪:
  • 初始化BYTETracker对象,设置跟踪相关的参数(如track_threshtrack_buffermatch_thresh)。
  • 跟踪模块会根据检测结果更新目标的轨迹,并为每个目标分配唯一的跟踪ID(tid)。

  1. 轨迹绘制与流量统计**
  • 轨迹绘制:代码为每个目标维护一个轨迹队列(self.trajectories[tid]),记录目标的运动轨迹,并在图像上绘制轨迹线。
  • 流量统计:通过设置一条虚拟的计数线(self.pointlist),代码判断目标是否穿过这条线,从而统计进入(self.id_in)和离开(self.id_out)的数量。

  1. 距离和速度计算**
  • 深度计算:代码通过相机模型和目标在图像中的位置(u, v),结合相机高度(H)和角度(alpha),计算目标在相机坐标系下的深度(zc_cam_other)。
  • 速度计算:通过目标在连续两帧中的深度变化和时间间隔(time_interval),计算目标的速度(单位:公里/小时)。

  1. 图像可视化**
  • 在图像上绘制检测框、类别、跟踪ID、速度信息以及计数结果。
  • 如果设置了--vis参数,会显示可视化结果。

  1. 视频处理**
  • 使用cv2.VideoCapture读取输入视频。
  • 对每一帧调用detect_image方法进行处理。
  • 将处理后的帧写入输出视频文件。

  1. 总结**
    这段代码的核心功能是:
  2. 使用YOLO模型检测视频中的目标。
  3. 使用ByteTrack算法跟踪目标的运动轨迹。
  4. 计算目标的速度和流量。
  5. 可视化检测和跟踪结果,并保存到输出视频中。

它结合了目标检测和多目标跟踪技术,适用于交通监控、人群分析等场景。

4、核心代码

importcv2importtorchfromultralyticsimportYOLOimportosimportargparsefrombytetrack_tracker.byte_trackerimportBYTETrackerfromcollectionsimportdequeimportnumpyasnpimportmath parser=argparse.ArgumentParser()# 检测参数parser.add_argument('--weights',default=r"yolov8m.pt",type=str,help='weights path')# 设置检测的视频路径parser.add_argument('--source',default=r"cound.mp4",type=str,help='img or video(.mp4)path')# parser.add_argument('--source', default=r"test2.mp4", type=str, help='img or video(.mp4)path')parser.add_argument('--save',default=r"./save",type=str,help='save img or video path')parser.add_argument('--vis',default=True,action='store_true',help='visualize image')parser.add_argument('--conf_thre',type=float,default=0.5,help='conf_thre')parser.add_argument('--iou_thre',type=float,default=0.5,help='iou_thre')# 跟踪参数parser.add_argument('--track_thresh',type=float,default=0.5,help='track_thresh')parser.add_argument('--track_buffer',type=int,default=70,help='track_buffer')parser.add_argument('--match_thresh',type=float,default=0.8,help='match_thresh')# 添加高度(H)、角度(alpha)和相机内参(calib)参数parser.add_argument('--H',type=float,default=6.5,help='Height of the camera from the ground')parser.add_argument('--alpha',type=int,default=8,help='Angle of the camera view')parser.add_argument('--calib',type=str,default='2900,0.0,640; 0.0,2900,360; 0.0,0.0,1.0',help='Camera intrinsic parameters')# 解析参数opt=parser.parse_args()# 将字符串形式的 calib 转换为 numpy 数组calib_values=[float(x)forxinopt.calib.replace(';',',').split(',')]opt.calib=np.array(calib_values).reshape(3,3)device=torch.device('cuda:0'iftorch.cuda.is_available()else'cpu')classDetector(object):def__init__(self,weight_path,conf_threshold=0.5,iou_threshold=0.5):self.device=device self.model=YOLO(weight_path).to(self.device)self.conf_threshold=conf_threshold self.iou_threshold=iou_threshold self.tracker=BYTETracker(track_thresh=opt.track_thresh,track_buffer=opt.track_buffer,match_thresh=opt.match_thresh)self.pointlist=[(6,410),(1278,410)]self.trajectories={}self.max_trajectory_length=5self.id_in=0self.id_in_list=[]self.id_out=0self.id_out_list=[]@staticmethoddefget_color(idx):idx=idx*3color=((37*idx)%255,(17*idx)%255,(29*idx)%255)returncolordefdraw_measure_line(self,H,calib,u,v,alpha):alpha=alpha# 角度a# 相机焦距fy=calib[1][1]# 相机光心u0=calib[0][2]v0=calib[1][2]pi=math.pi Q_pie=[u-u0,v-v0]gamma_pie=math.atan(Q_pie[1]/fy)*180/np.pi beta_pie=alpha+gamma_pieifbeta_pie==0:beta_pie=1e-2z_in_cam=(H/math.sin(beta_pie/180*pi))*math.cos(gamma_pie*pi/180)returnz_in_camdefdetect_image(self,img_bgr):results=self.model(img_bgr,conf=self.conf_threshold,iou=self.iou_threshold)# Extracting the necessary details from the resultsboxes=results[0].boxes.xyxy.cpu().numpy()# xyxy formatconfidences=results[0].boxes.conf class_preds=results[0].boxes.cls confidences_expanded=confidences.unsqueeze(1)class_preds_expanded=class_preds.unsqueeze(1)boxes_tensor=torch.from_numpy(boxes).to(class_preds_expanded.device)result=torch.cat((boxes_tensor,confidences_expanded,class_preds_expanded),dim=1)online_targets=self.tracker.update(result.cpu(),[results[0].orig_shape[0],results[0].orig_shape[1]])cv2.line(img_bgr,self.pointlist[0],self.pointlist[1],(0,255,0),2)fortinonline_targets:speed_km_per_h=0tlwh=t.tlwh xmin,ymin,xmax,ymax=tlwh[0],tlwh[1],tlwh[0]+tlwh[2],tlwh[1]+tlwh[3]tid=t.track_id cls=t.cls.item()class_pred=int(cls)color=self.get_color(class_pred+2)bottom_center=(int(tlwh[0]+tlwh[2]/2),int(tlwh[1]+tlwh[3]))bbox_label=results[0].names[class_pred]cv2.rectangle(img_bgr,(int(xmin),int(ymin)),(int(xmax),int(ymax)),color,2)zc_cam_other=self.draw_measure_line(opt.H,opt.calib,int(tlwh[0]+tlwh[2]/2),int(tlwh[1]+tlwh[3]),opt.alpha)iftidnotinself.trajectories:self.trajectories[tid]=deque(maxlen=self.max_trajectory_length)trajectory_point={'bottom_center':bottom_center,'zc_cam_other':zc_cam_other}self.trajectories[tid].appendleft(trajectory_point)# 截断轨迹长度iflen(self.trajectories[tid])>self.max_trajectory_length:self.trajectories[tid]=self.trajectories[tid][:self.max_trajectory_length]foriinrange(1,len(self.trajectories[tid])):ifself.trajectories[tid][i-1]isNoneorself.trajectories[tid][i]isNone:continuethickness=int(np.sqrt(64/float(i+1))*2.5)cv2.line(img_bgr,self.trajectories[tid][i-1]['bottom_center'],self.trajectories[tid][i]['bottom_center'],color,thickness)# 通过阈值判断是竖线还是横线,若x2和x1之间的差值小于20 判断为竖线 否则为横线""" 例如:如下垂线上下两点的x保持不变,y存在变化 所以垂线的x2-x1=0 * * * * 如下横线左右两点的y保持不变,x存在变化 所以横线的y2-y1=0 *********** """ifabs(self.pointlist[1][0]-self.pointlist[0][0])<20:# 通过判断同一个目标上下两帧是否过线 来进行计数# self.trajectories[tid][i - 1][0]代表上一帧 self.trajectories[tid][i][0]代表当前帧if((self.trajectories[tid][i-1]['bottom_center'][0]<=self.pointlist[0][0])and(self.trajectories[tid][i]['bottom_center'][0]>self.pointlist[0][0]))and\((self.trajectories[tid][i]['bottom_center'][1]>self.pointlist[1][1])and# 设置目标的撞线范围 不得超线(self.trajectories[tid][i]['bottom_center'][1]<self.pointlist[0][1])):# 如果目标ID已经计数过,则忽略iftidinself.id_in_list:continue# 否则,增加进入计数,并将ID添加到已计数列表中else:self.id_in+=1self.id_in_list.append(tid)if((self.trajectories[tid][i-1]['bottom_center'][0]>=self.pointlist[0][0])and(self.trajectories[tid][i]['bottom_center'][0]<self.pointlist[0][0]))and\((self.trajectories[tid][i]['bottom_center'][1]>self.pointlist[1][1])and(self.trajectories[tid][i]['bottom_center'][1]<self.pointlist[0][1])):iftidinself.id_out_list:continueelse:self.id_out+=1self.id_out_list.append(tid)else:if((self.trajectories[tid][i-1]['bottom_center'][1]>=self.pointlist[0][1])and(self.trajectories[tid][i]['bottom_center'][1]<self.pointlist[0][1]))and\((self.trajectories[tid][i]['bottom_center'][0]>self.pointlist[0][0])and(self.trajectories[tid][i]['bottom_center'][0]<self.pointlist[1][0])):iftidinself.id_in_list:continueelse:self.id_in+=1self.id_in_list.append(tid)if((self.trajectories[tid][i-1]['bottom_center'][1]<=self.pointlist[0][1])and(self.trajectories[tid][i]['bottom_center'][1]>self.pointlist[0][1]))and\((self.trajectories[tid][i]['bottom_center'][0]>self.pointlist[0][0])and(self.trajectories[tid][i]['bottom_center'][0]<self.pointlist[1][0])):iftidinself.id_out_list:continueelse:self.id_out+=1self.id_out_list.append(tid)time_interval=1/fps speed_m_per_s=abs(self.trajectories[tid][i]['zc_cam_other']-self.trajectories[tid][i-1]['zc_cam_other'])/time_interval speed_km_per_h=speed_m_per_s*3.6# 转换为公里/小时# 显示类名和跟踪IDcv2.putText(img_bgr,f"{bbox_label}{int(tid)}",(int(tlwh[0]),int(tlwh[1])),cv2.FONT_HERSHEY_COMPLEX,0.6,color,2)# 显示速度,纵坐标比类名和跟踪ID的位置稍低一些cv2.putText(img_bgr,f"{zc_cam_other:.1f}m{speed_km_per_h:.1f}km/h",(int(tlwh[0]),int(tlwh[1])+20),cv2.FONT_HERSHEY_COMPLEX,0.6,color,2)cv2.putText(img_bgr,str(f"down:{self.id_in}"),(int(img_bgr.shape[1]*0.1),int(img_bgr.shape[0]*0.17)),cv2.FONT_HERSHEY_COMPLEX,2,(0,255,0),2)cv2.putText(img_bgr,str(f"up:{self.id_out}"),(int(img_bgr.shape[1]*0.1),int(img_bgr.shape[0]*0.1)),cv2.FONT_HERSHEY_COMPLEX,2,(0,0,255),2)returnimg_bgr# Example usageif__name__=='__main__':model=Detector(weight_path=opt.weights,conf_threshold=opt.conf_thre,iou_threshold=opt.iou_thre)capture=cv2.VideoCapture(opt.source)fps=capture.get(cv2.CAP_PROP_FPS)size=(int(capture.get(cv2.CAP_PROP_FRAME_WIDTH)),int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT)))fourcc=cv2.VideoWriter_fourcc('m','p','4','v')outVideo=cv2.VideoWriter(os.path.join(opt.save,os.path.basename(opt.source).split('.')[-2]+"_out.mp4"),fourcc,fps,size)whileTrue:ret,frame=capture.read()ifnotret:breakimg_vis=model.detect_image(frame)outVideo.write(img_vis)img_vis=cv2.resize(img_vis,None,fx=1,fy=1,interpolation=cv2.INTER_NEAREST)cv2.imshow('track',img_vis)cv2.waitKey(30)capture.release()outVideo.release()

5、项目获取

(绿色聊天软件)yuanmazhiwu 或 biyesheji0005

🍅由于篇幅限制,获取完整文章或源码、代做项目的,查看我的【用户名】、【专栏名称】、【顶部选题链接】就可以找到我啦🍅

感兴趣的可以先收藏起来,点赞、关注不迷路,下方查看👇🏻获取联系方式👇🏻

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询