【精选】车流量统计系统:OpenCV&YOLOv5(源码&部署教程) 您所在的位置:网站首页 车辆超速检测系统属于什么类别 【精选】车流量统计系统:OpenCV&YOLOv5(源码&部署教程)

【精选】车流量统计系统:OpenCV&YOLOv5(源码&部署教程)

2024-07-13 01:14| 来源: 网络整理| 查看: 265

1.项目背景与意义

随着城市化进程的加快和交通工具的普及,车辆数量的快速增长给城市交通管理带来了巨大的挑战。车流量检测是交通管理的重要组成部分,它可以提供实时的交通状况信息,帮助交通管理部门制定合理的交通策略,优化交通流量,提高道路利用效率,减少交通拥堵和事故发生的可能性。

传统的车流量检测方法主要依赖于传感器设备,如地磁传感器、红外线传感器等,这些传感器需要在道路上布设,成本较高且安装维护困难。而基于计算机视觉的车流量检测系统则可以通过分析道路上的摄像头图像来实现,具有成本低、安装方便、实时性强等优势。

OpenCV是一个开源的计算机视觉库,提供了丰富的图像处理和计算机视觉算法,可以用于车流量检测系统中的图像处理和分析。Yolov5是一个基于深度学习的目标检测算法,具有高准确率和实时性的特点,可以用于车辆的检测和跟踪。

2.图片演示

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

3.视频演示

OpenCV&YOLOv5的车流量统计系统(源码&部署教程)

4.系统流程步骤

基于OpenCV和Yolov5的车流量检测系统可以通过以下步骤实现:

图像采集:使用摄像头采集道路上的车辆图像。

图像预处理:使用OpenCV对采集到的图像进行预处理,包括图像去噪、图像增强等。

车辆检测:使用Yolov5对预处理后的图像进行车辆检测,识别出图像中的车辆。

车辆跟踪:根据检测到的车辆,使用OpenCV进行车辆的跟踪,追踪车辆在不同帧之间的位置和运动轨迹。

车流量统计:根据车辆的跟踪结果,统计道路上的车流量,包括车辆的数量、车辆的速度等。

5.算法优点

基于OpenCV和Yolov5的车流量检测系统具有以下优势和意义:

高准确率:Yolov5作为一种先进的目标检测算法,具有较高的准确率,可以准确地检测和识别道路上的车辆。

实时性强:Yolov5算法的实时性较好,可以在较短的时间内完成车辆的检测和跟踪,实时更新车流量信息。

成本低:相比传统的车流量检测方法,基于OpenCV和Yolov5的系统不需要额外的传感器设备,只需要使用摄像头即可实现车流量检测,成本较低。

安装方便:基于OpenCV和Yolov5的系统只需要在道路上布设摄像头,安装和维护较为方便。

实用性强:车流量检测系统可以为交通管理部门提供实时的交通状况信息,帮助制定合理的交通策略,优化交通流量,提高道路利用效率,减少交通拥堵和事故发生的可能性。

综上所述,基于OpenCV和Yolov5的车流量检测系统具有重要的研究意义和实际应用价值,可以为城市交通管理提供有效的技术支持,促进交通运输的安全、高效和可持续发展。

6.数据集的制作

在车流量统计中只需要识别道路中的车辆,因此在制作数据集时只选取车辆一种类别,其他非车辆物体作为负样本。 车辆识别数据集制作首先运用图像标注软件对车辆进行标注,并将所标注的信息生成相对应的xml文件,xml文件包含图片名称、图片路径、目标标签名称及目标位置坐标,车辆标注过程如图3.18所示。包含标注信息的xml文件不能直接用来训练YOLO网络,需要将xml文件转换成YOLO支持的txt文件。标注完所有图片后,将原图及生成的所有文件按照VOC数据文件结构存放,以供训练车辆识别模型使用。 在这里插入图片描述

7.网络模型优化

YOLO网络采用均方误差(mean squared error)作为损失函数,这种损失函数的设计形式对优化模型参数非常有利。为了更好地训练网络模型,YOLO网络在反向传播的过程中,其损失函数共包含三部分内容: (1)标注数据与网格预测坐标之间的误差(coordError) ; (2)目标的预测边界框与真实边界框之间的交集与并集的比值误差( iouError) ;(3)目标的分类误差(classError)。 YOLO的损失函数如下: 在这里插入图片描述 (w,y)表示网络预测目标框的宽和高;(w,,h, )表示标签中目标框的宽和高;C表示网络预测目标时计算的置信度分数;己,表示网络设置的置信度分数;P©表示网络预测的目标属于某一类别的概率;©表示目标真实类别的概率;参数⒉ora的引入是为了增强边界框在损失计算中的重要性。 能够减弱非目标区域对目标区域置信度计算的影响,Aoobj =0.5;I表示图像中第i个图像块有目标,TW表示在第i个图像块的第i个预测框中有目标,若无目标刷头noobj在预测目标的边界框时,预测结果对大目标和小目标的影响是相同的,然而真实情况是大目标的敏感性小于小目标,当边界框的宽和高(w,h)发生略微变化时,小目标的边界框就会消失,因此,YOLO网络采用平方根处理边界框的宽和高(w,h),这种对边界框的处理方式虽然能够使得大目标与小目标的敏感性接近一致,但是没有考虑到物体尺寸存在差异时对整体误差的影响不同,交通视频中往往车型较多,YOLO网络损失函数对大车和小车的预测边界框采用统一的误差,这与真实情况不符,为了体现出不同尺寸的车辆产生的误差在整个网络中所占的比重不同,本文采用比值的方式对损失函数进行优化,运用( w;-w, / ,h,-h, / h,)代替原损失函数的(w,-w,,(h,-Vh,),这样不但可以提升网络预测物体类别的能力,也可以优化目标边框的位置。优化后的损失函数如式所示: 在这里插入图片描述

8.核心代码讲解 8.1 detector_CPU.py class Detector: def __init__(self): self.img_size = 640 self.threshold = 0.1 self.stride = 1 self.weights = './weights/output_of_small_target_detection.pt' self.device = '0' if torch.cuda.is_available() else 'cpu' self.device = select_device(self.device) model = attempt_load(self.weights, map_location=self.device) model.to(self.device).eval() model.float() self.m = model self.names = model.module.names if hasattr( model, 'module') else model.names def preprocess(self, img): img0 = img.copy() img = letterbox(img, new_shape=self.img_size)[0] img = img[:, :, ::-1].transpose(2, 0, 1) img = np.ascontiguousarray(img) img = torch.from_numpy(img).to(self.device) img = img.float() img /= 255.0 if img.ndimension() == 3: img = img.unsqueeze(0) return img0, img def detect(self, im): im0, img = self.preprocess(im) pred = self.m(img, augment=False)[0] pred = pred.float() pred = non_max_suppression(pred, self.threshold, 0.4) boxes = [] for det in pred: if det is not None and len(det): det[:, :4] = scale_coords( img.shape[2:], det[:, :4], im0.shape).round() for *x, conf, cls_id in det: lbl = self.names[int(cls_id)] if lbl not in ['car','bus','truck']: continue x1, y1 = int(x[0]), int(x[1]) x2, y2 = int(x[2]), int(x[3]) xm = x2 ym = y2 boxes.append((x1, y1, x2, y2, lbl, conf)) return boxes

封装的类名为Detector,包含以下方法:

__init__:初始化模型和参数preprocess:预处理图像detect:检测目标并返回检测结果

这个程序文件名为detector_CPU.py,它是一个目标检测器的类。该类具有以下属性和方法:

属性:

img_size:图像的尺寸,默认为640threshold:目标检测的置信度阈值,默认为0.1stride:步长,默认为1weights:模型的权重文件路径,默认为’./weights/output_of_small_target_detection.pt’device:设备类型,如果有GPU则为’0’,否则为’cpu’m:加载的模型names:目标类别的名称列表

方法:

init(self):初始化方法,加载模型并设置相关参数preprocess(self, img):预处理方法,将输入图像进行尺寸调整、通道转换等操作,返回原始图像和处理后的图像detect(self, im):目标检测方法,对输入图像进行目标检测,返回检测到的目标框的列表

在detect方法中,首先调用preprocess方法对输入图像进行预处理。然后使用加载的模型对处理后的图像进行目标检测,得到预测结果。接着对预测结果进行非最大抑制,去除重叠的目标框。最后,遍历每个检测到的目标框,筛选出类别为’car’、'bus’和’truck’的目标框,并将其添加到结果列表中。最终返回结果列表。

8.2 detector_GPU.py class Detector: def __init__(self): self.img_size = 640 self.threshold = 0.1 self.stride = 1 self.weights = './weights/Attention_mechanism.pt' self.device = '0' if torch.cuda.is_available() else 'cpu' self.device = select_device(self.device) model = attempt_load(self.weights, map_location=self.device) model.to(self.device).eval() model.half() self.m = model self.names = model.module.names if hasattr(model, 'module') else model.names def preprocess(self, img): img0 = img.copy() img = letterbox(img, new_shape=self.img_size)[0] img = img[:, :, ::-1].transpose(2, 0, 1) img = np.ascontiguousarray(img) img = torch.from_numpy(img).to(self.device) img = img.half() img /= 255.0 if img.ndimension() == 3: img = img.unsqueeze(0) return img0, img def detect(self, im): im0, img = self.preprocess(im) pred = self.m(img, augment=False)[0] pred = pred.float() pred = non_max_suppression(pred, self.threshold, 0.4) boxes = [] for det in pred: if det is not None and len(det): det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round() for *x, conf, cls_id in det: lbl = self.names[int(cls_id)] if lbl not in ['bicycle','car', 'bus', 'truck']: continue x1, y1 = int(x[0]), int(x[1]) x2, y2 = int(x[2]), int(x[3]) xm = x2 ym = y2 if ym +0.797* xm -509.77 > 0: boxes.append((x1, y1, x2, y2, lbl, conf)) return boxes

这个程序文件名为detector_GPU.py,它是一个目标检测器的类。该类具有以下功能:

初始化函数:设置图像大小、阈值和步长等参数,加载模型权重文件,选择设备(如果有GPU则选择GPU,否则选择CPU),将模型加载到设备上,并设置为评估模式。

预处理函数:对输入的图像进行预处理,包括调整图像大小、转换颜色通道顺序、转换为numpy数组、转换为torch张量、归一化等操作。

检测函数:对输入的图像进行目标检测,返回检测到的目标框的坐标、类别和置信度。该函数首先调用预处理函数对图像进行处理,然后使用加载的模型对图像进行推理,得到预测结果。接着使用非最大抑制算法对预测结果进行筛选,去除重叠的框,并根据阈值进行置信度过滤。最后,根据类别进行筛选,只保留自行车、汽车、公交车和卡车的目标框。

该程序依赖于其他模块和库,如torch、numpy、cv2等,这些模块和库需要提前安装和导入。

8.3 Mouse.py import cv2 class MouseClick: def __init__(self, img): self.img = img def on_EVENT_LBUTTONDOWN(self, event, x, y, flags, param): if event == cv2.EVENT_LBUTTONDOWN: print("(%d,%d)" % (x, y)) xy = "%d,%d" % (x, y) cv2.circle(self.img, (x, y), 1, (255, 0, 0), thickness=-1) cv2.putText(self.img, xy, (x, y), cv2.FONT_HERSHEY_PLAIN, 1.0, (0, 0, 0), thickness=1) cv2.imshow("image", self.img) def mouse(self): cv2.namedWindow("image") cv2.setMouseCallback("image", self.on_EVENT_LBUTTONDOWN) cv2.imshow("image", self.img) while (True): try: cv2.waitKey(100) except Exception: cv2.destroyAllWindows() break cv2.waitKey(0) cv2.destroyAllWindows()

这个程序文件名为Mouse.py,主要功能是在图像上显示鼠标点击的坐标,并在点击位置绘制一个蓝色的圆圈。程序使用了OpenCV库来处理图像和鼠标事件。具体的实现过程如下:

导入cv2库。定义一个名为mouse的函数,该函数接受一个图像作为参数。在函数内部定义一个名为on_EVENT_LBUTTONDOWN的回调函数,用于处理鼠标左键点击事件。如果检测到鼠标左键点击事件,将点击的坐标打印出来,并将坐标信息添加到图像上,绘制一个蓝色的圆圈。创建一个名为"image"的窗口,并将鼠标事件回调函数绑定到该窗口上。在窗口中显示图像。进入一个无限循环,等待用户操作。如果捕获到异常,关闭窗口并退出循环。等待用户按下任意键后关闭窗口。

总体来说,这个程序实现了一个简单的图像交互界面,可以显示鼠标点击的坐标,并在图像上进行标注。

8.4 tracker.py class ObjectTracker: def __init__(self): cfg = get_config() cfg.merge_from_file("./deep_sort/configs/deep_sort.yaml") self.deepsort = DeepSort(cfg.DEEPSORT.REID_CKPT, max_dist=cfg.DEEPSORT.MAX_DIST, min_confidence=cfg.DEEPSORT.MIN_CONFIDENCE, nms_max_overlap=cfg.DEEPSORT.NMS_MAX_OVERLAP, max_iou_distance=cfg.DEEPSORT.MAX_IOU_DISTANCE, max_age=cfg.DEEPSORT.MAX_AGE, n_init=cfg.DEEPSORT.N_INIT, nn_budget=cfg.DEEPSORT.NN_BUDGET, use_cuda=True) def draw_bboxes(self, image, bboxes, line_thickness): line_thickness = line_thickness or round( 0.002 * (image.shape[0] + image.shape[1]) * 0.5) + 1 list_pts = [] point_radius = 4 for (x1, y1, x2, y2, cls_id, pos_id) in bboxes: color = (0, 255, 0) # 撞线的点 check_point_x = x1 check_point_y = int(y1 + ((y2 - y1) * 0.6)) c1, c2 = (x1, y1), (x2, y2) cv2.rectangle(image, c1, c2, color, thickness=line_thickness, lineType=cv2.LINE_AA) font_thickness = max(line_thickness - 1, 1) t_size = cv2.getTextSize(cls_id, 0, fontScale=line_thickness / 3, thickness=font_thickness)[0] c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3 cv2.rectangle(image, c1, c2, color, -1, cv2.LINE_AA) # filled cv2.putText(image, '{} ID-{}'.format(cls_id, pos_id), (c1[0], c1[1] - 2), 0, line_thickness / 3, [225, 255, 255], thickness=font_thickness, lineType=cv2.LINE_AA) list_pts.append([check_point_x - point_radius, check_point_y - point_radius]) list_pts.append([check_point_x - point_radius, check_point_y + point_radius]) list_pts.append([check_point_x + point_radius, check_point_y + point_radius]) list_pts.append([check_point_x + point_radius, check_point_y - point_radius]) ndarray_pts = np.array(list_pts, np.int32) cv2.fillPoly(image, [ndarray_pts], color=(0, 0, 255)) list_pts.clear() return image def update(self, bboxes, image): bbox_xywh = [] confs = [] bboxes2draw = [] if len(bboxes) > 0: for x1, y1, x2, y2, lbl, conf in bboxes: obj = [ int((x1 + x2) * 0.5), int((y1 + y2) * 0.5), x2 - x1, y2 - y1 ] bbox_xywh.append(obj) confs.append(conf) xywhs = torch.Tensor(bbox_xywh) confss = torch.Tensor(confs) outputs = self.deepsort.update(xywhs, confss, image) for x1, y1, x2, y2, track_id in list(outputs): # x1, y1, x2, y2, track_id = value center_x = (x1 + x2) * 0.5 center_y = (y1 + y2) * 0.5 label = self.search_label(center_x=center_x, center_y=center_y, bboxes_xyxy=bboxes, max_dist_threshold=20.0) bboxes2draw.append((x1, y1, x2, y2, label, track_id)) pass pass return bboxes2draw def search_label(self, center_x, center_y, bboxes_xyxy, max_dist_threshold): """ 在 yolov5 的 bbox 中搜索中心点最接近的label :param center_x: :param center_y: :param bboxes_xyxy: :param max_dist_threshold: :return: 字符串 """ label = '' # min_label = '' min_dist = -1.0 for x1, y1, x2, y2, lbl, conf in bboxes_xyxy: center_x2 = (x1 + x2) * 0.5 center_y2 = (y1 + y2) * 0.5 # 横纵距离都小于 max_dist min_x = abs(center_x2 - center_x) min_y = abs(center_y2 - center_y) if min_x


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有