├── 6008ff4aad324519a83f73e1602b3412.png ├── 95a1bedf801749d3898c7d4d177c9aef.png ├── 9c4c0adf54d6422da6272749a6aad8be.png ├── cb1c9a78ce2e4db9919c2ce70b7ef530.png ├── cd4ce788cbb942eaa002c1df1ecaba89.png ├── f5d2e8e3085e480dac832ba0595ad396.png ├── faef9ab759c34b0db4e0e6a5bb27e811.png ├── ui.py ├── Mouse.py ├── detector_GPU.py ├── detector_CPU.py ├── tracker.py └── README.md /6008ff4aad324519a83f73e1602b3412.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qunshansj/OpenCV-YOLO-Traffic-Flow-Counting-System/HEAD/6008ff4aad324519a83f73e1602b3412.png -------------------------------------------------------------------------------- /95a1bedf801749d3898c7d4d177c9aef.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qunshansj/OpenCV-YOLO-Traffic-Flow-Counting-System/HEAD/95a1bedf801749d3898c7d4d177c9aef.png -------------------------------------------------------------------------------- /9c4c0adf54d6422da6272749a6aad8be.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qunshansj/OpenCV-YOLO-Traffic-Flow-Counting-System/HEAD/9c4c0adf54d6422da6272749a6aad8be.png -------------------------------------------------------------------------------- /cb1c9a78ce2e4db9919c2ce70b7ef530.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qunshansj/OpenCV-YOLO-Traffic-Flow-Counting-System/HEAD/cb1c9a78ce2e4db9919c2ce70b7ef530.png -------------------------------------------------------------------------------- /cd4ce788cbb942eaa002c1df1ecaba89.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qunshansj/OpenCV-YOLO-Traffic-Flow-Counting-System/HEAD/cd4ce788cbb942eaa002c1df1ecaba89.png -------------------------------------------------------------------------------- /f5d2e8e3085e480dac832ba0595ad396.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qunshansj/OpenCV-YOLO-Traffic-Flow-Counting-System/HEAD/f5d2e8e3085e480dac832ba0595ad396.png -------------------------------------------------------------------------------- /faef9ab759c34b0db4e0e6a5bb27e811.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qunshansj/OpenCV-YOLO-Traffic-Flow-Counting-System/HEAD/faef9ab759c34b0db4e0e6a5bb27e811.png -------------------------------------------------------------------------------- /ui.py: -------------------------------------------------------------------------------- 1 | python 2 | import numpy as np 3 | import tracker 4 | from detector_CPU import Detector 5 | import cv2 6 | 7 | class TrafficFlowDetection: 8 | def __init__(self, video_path): 9 | self.video_path = video_path 10 | self.detector = Detector() 11 | self.tracker = tracker 12 | self.down_count = 0 13 | self.up_count = 0 14 | 15 | def detect_traffic_flow(self): 16 | mask_image_temp = np.zeros((1080, 1920), dtype=np.uint8) 17 | list_pts_blue = [[0, 600], [0, 900], [1920, 900], [1920, 600]] 18 | ndarray_pts_blue = np.array(list_pts_blue, np.int32) 19 | polygon_blue_value_1 = cv2.fillPoly(mask_image_temp, [ndarray_pts_blue], color=1) 20 | polygon_blue_value_1 = 21 | -------------------------------------------------------------------------------- /Mouse.py: -------------------------------------------------------------------------------- 1 | python 2 | import cv2 3 | 4 | class MouseClick: 5 | def __init__(self, img): 6 | self.img = img 7 | 8 | def on_EVENT_LBUTTONDOWN(self, event, x, y, flags, param): 9 | if event == cv2.EVENT_LBUTTONDOWN: 10 | print("(%d,%d)" % (x, y)) 11 | xy = "%d,%d" % (x, y) 12 | cv2.circle(self.img, (x, y), 1, (255, 0, 0), thickness=-1) 13 | cv2.putText(self.img, xy, (x, y), cv2.FONT_HERSHEY_PLAIN, 14 | 1.0, (0, 0, 0), thickness=1) 15 | cv2.imshow("image", self.img) 16 | 17 | def mouse(self): 18 | cv2.namedWindow("image") 19 | cv2.setMouseCallback("image", self.on_EVENT_LBUTTONDOWN) 20 | cv2.imshow("image", self.img) 21 | 22 | while (True): 23 | try: 24 | cv2.waitKey(100) 25 | except Exception: 26 | cv2.destroyAllWindows() 27 | break 28 | 29 | cv2.waitKey(0) 30 | cv2.destroyAllWindows() 31 | -------------------------------------------------------------------------------- /detector_GPU.py: -------------------------------------------------------------------------------- 1 | python 2 | 3 | class Detector: 4 | def __init__(self): 5 | self.img_size = 640 6 | self.threshold = 0.1 7 | self.stride = 1 8 | self.weights = './weights/Attention_mechanism.pt' 9 | self.device = '0' if torch.cuda.is_available() else 'cpu' 10 | self.device = select_device(self.device) 11 | model = attempt_load(self.weights, map_location=self.device) 12 | model.to(self.device).eval() 13 | model.half() 14 | self.m = model 15 | self.names = model.module.names if hasattr(model, 'module') else model.names 16 | 17 | def preprocess(self, img): 18 | img0 = img.copy() 19 | img = letterbox(img, new_shape=self.img_size)[0] 20 | img = img[:, :, ::-1].transpose(2, 0, 1) 21 | img = np.ascontiguousarray(img) 22 | img = torch.from_numpy(img).to(self.device) 23 | img = img.half() 24 | img /= 255.0 25 | if img.ndimension() == 3: 26 | img = img.unsqueeze(0) 27 | return img0, img 28 | 29 | def detect(self, im): 30 | im0, img = self.preprocess(im) 31 | pred = self.m(img, augment=False)[0] 32 | pred = pred.float() 33 | pred = non_max_suppression(pred, self.threshold, 0.4) 34 | boxes = [] 35 | for det in pred: 36 | if det is not None and len(det): 37 | det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round() 38 | for *x, conf, cls_id in det: 39 | lbl = self.names[int(cls_id)] 40 | if lbl not in ['bicycle','car', 'bus', 'truck']: 41 | continue 42 | x1, y1 = int(x[0]), int(x[1]) 43 | x2, y2 = int(x[2]), int(x[3]) 44 | xm = x2 45 | ym = y2 46 | if ym +0.797* xm -509.77 > 0: 47 | boxes.append((x1, y1, x2, y2, lbl, conf)) 48 | return boxes 49 | -------------------------------------------------------------------------------- /detector_CPU.py: -------------------------------------------------------------------------------- 1 | python 2 | 3 | class Detector: 4 | def __init__(self): 5 | self.img_size = 640 6 | self.threshold = 0.1 7 | self.stride = 1 8 | 9 | self.weights = './weights/output_of_small_target_detection.pt' 10 | 11 | self.device = '0' if torch.cuda.is_available() else 'cpu' 12 | self.device = select_device(self.device) 13 | model = attempt_load(self.weights, map_location=self.device) 14 | model.to(self.device).eval() 15 | model.float() 16 | 17 | self.m = model 18 | self.names = model.module.names if hasattr( 19 | model, 'module') else model.names 20 | 21 | def preprocess(self, img): 22 | img0 = img.copy() 23 | img = letterbox(img, new_shape=self.img_size)[0] 24 | img = img[:, :, ::-1].transpose(2, 0, 1) 25 | img = np.ascontiguousarray(img) 26 | img = torch.from_numpy(img).to(self.device) 27 | img = img.float() 28 | img /= 255.0 29 | if img.ndimension() == 3: 30 | img = img.unsqueeze(0) 31 | 32 | return img0, img 33 | 34 | def detect(self, im): 35 | im0, img = self.preprocess(im) 36 | 37 | pred = self.m(img, augment=False)[0] 38 | pred = pred.float() 39 | pred = non_max_suppression(pred, self.threshold, 0.4) 40 | 41 | boxes = [] 42 | for det in pred: 43 | if det is not None and len(det): 44 | det[:, :4] = scale_coords( 45 | img.shape[2:], det[:, :4], im0.shape).round() 46 | 47 | for *x, conf, cls_id in det: 48 | lbl = self.names[int(cls_id)] 49 | if lbl not in ['car','bus','truck']: 50 | continue 51 | x1, y1 = int(x[0]), int(x[1]) 52 | x2, y2 = int(x[2]), int(x[3]) 53 | 54 | xm = x2 55 | ym = y2 56 | boxes.append((x1, y1, x2, y2, lbl, conf)) 57 | 58 | return boxes 59 | -------------------------------------------------------------------------------- /tracker.py: -------------------------------------------------------------------------------- 1 | python 2 | 3 | class ObjectTracker: 4 | def __init__(self): 5 | cfg = get_config() 6 | cfg.merge_from_file("./deep_sort/configs/deep_sort.yaml") 7 | self.deepsort = DeepSort(cfg.DEEPSORT.REID_CKPT, 8 | max_dist=cfg.DEEPSORT.MAX_DIST, min_confidence=cfg.DEEPSORT.MIN_CONFIDENCE, 9 | nms_max_overlap=cfg.DEEPSORT.NMS_MAX_OVERLAP, max_iou_distance=cfg.DEEPSORT.MAX_IOU_DISTANCE, 10 | max_age=cfg.DEEPSORT.MAX_AGE, n_init=cfg.DEEPSORT.N_INIT, nn_budget=cfg.DEEPSORT.NN_BUDGET, 11 | use_cuda=True) 12 | 13 | def draw_bboxes(self, image, bboxes, line_thickness): 14 | line_thickness = line_thickness or round( 15 | 0.002 * (image.shape[0] + image.shape[1]) * 0.5) + 1 16 | 17 | list_pts = [] 18 | point_radius = 4 19 | 20 | for (x1, y1, x2, y2, cls_id, pos_id) in bboxes: 21 | color = (0, 255, 0) 22 | 23 | # 撞线的点 24 | check_point_x = x1 25 | check_point_y = int(y1 + ((y2 - y1) * 0.6)) 26 | 27 | c1, c2 = (x1, y1), (x2, y2) 28 | cv2.rectangle(image, c1, c2, color, thickness=line_thickness, lineType=cv2.LINE_AA) 29 | 30 | font_thickness = max(line_thickness - 1, 1) 31 | t_size = cv2.getTextSize(cls_id, 0, fontScale=line_thickness / 3, thickness=font_thickness)[0] 32 | c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3 33 | cv2.rectangle(image, c1, c2, color, -1, cv2.LINE_AA) # filled 34 | cv2.putText(image, '{} ID-{}'.format(cls_id, pos_id), (c1[0], c1[1] - 2), 0, line_thickness / 3, 35 | [225, 255, 255], thickness=font_thickness, lineType=cv2.LINE_AA) 36 | 37 | list_pts.append([check_point_x - point_radius, check_point_y - point_radius]) 38 | list_pts.append([check_point_x - point_radius, check_point_y + point_radius]) 39 | list_pts.append([check_point_x + point_radius, check_point_y + point_radius]) 40 | list_pts.append([check_point_x + point_radius, check_point_y - point_radius]) 41 | 42 | ndarray_pts = np.array(list_pts, np.int32) 43 | 44 | cv2.fillPoly(image, [ndarray_pts], color=(0, 0, 255)) 45 | 46 | list_pts.clear() 47 | 48 | return image 49 | 50 | def update(self, bboxes, image): 51 | bbox_xywh = [] 52 | confs = [] 53 | bboxes2draw = [] 54 | 55 | if len(bboxes) > 0: 56 | for x1, y1, x2, y2, lbl, conf in bboxes: 57 | obj = [ 58 | int((x1 + x2) * 0.5), int((y1 + y2) * 0.5), 59 | x2 - x1, y2 - y1 60 | ] 61 | bbox_xywh.append(obj) 62 | confs.append(conf) 63 | 64 | xywhs = torch.Tensor(bbox_xywh) 65 | confss = torch.Tensor(confs) 66 | 67 | outputs = self.deepsort.update(xywhs, confss, image) 68 | 69 | for x1, y1, x2, y2, track_id in list(outputs): 70 | # x1, y1, x2, y2, track_id = value 71 | center_x = (x1 + x2) * 0.5 72 | center_y = (y1 + y2) * 0.5 73 | 74 | label = self.search_label(center_x=center_x, center_y=center_y, 75 | bboxes_xyxy=bboxes, max_dist_threshold=20.0) 76 | 77 | bboxes2draw.append((x1, y1, x2, y2, label, track_id)) 78 | pass 79 | pass 80 | 81 | return bboxes2draw 82 | 83 | def search_label(self, center_x, center_y, bboxes_xyxy, max_dist_threshold): 84 | """ 85 | 在 yolov5 的 bbox 中搜索中心点最接近的label 86 | :param center_x: 87 | :param center_y: 88 | :param bboxes_xyxy: 89 | :param max_dist_threshold: 90 | :return: 字符串 91 | """ 92 | label = '' 93 | # min_label = '' 94 | min_dist = -1.0 95 | 96 | for x1, y1, x2, y2, lbl, conf in bboxes_xyxy: 97 | center_x2 = (x1 + x2) * 0.5 98 | center_y2 = (y1 + y2) * 0.5 99 | 100 | # 横纵距离都小于 max_dist 101 | min_x = abs(center_x2 - center_x) 102 | min_y = abs(center_y2 - center_y) 103 | 104 | if min_x < max_dist_threshold and min_y < max_dist_threshold: 105 | # 距离阈值,判断是否在允许误差范围内 106 | # 取 x, y 方向上的距离平均值 107 | avg_dist = (min_x + min_y) * 0.5 108 | if min_dist == -1.0: 109 | # 第一次赋值 110 | min_dist = avg_dist 111 | # 赋值label 112 | label = lbl 113 | pass 114 | else: 115 | # 若不是第一次,则距离小的优先 116 | if avg_dist < min_dist: 117 | min_dist = avg_dist 118 | # label 119 | label = lbl 120 | pass 121 | pass 122 | pass 123 | 124 | return label 125 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 1.项目背景与意义 2 | 3 | 4 | 5 | 随着城市化进程的加快和交通工具的普及,车辆数量的快速增长给城市交通管理带来了巨大的挑战。车流量检测是交通管理的重要组成部分,它可以提供实时的交通状况信息,帮助交通管理部门制定合理的交通策略,优化交通流量,提高道路利用效率,减少交通拥堵和事故发生的可能性。 6 | 7 | 传统的车流量检测方法主要依赖于传感器设备,如地磁传感器、红外线传感器等,这些传感器需要在道路上布设,成本较高且安装维护困难。而基于计算机视觉的车流量检测系统则可以通过分析道路上的摄像头图像来实现,具有成本低、安装方便、实时性强等优势。 8 | 9 | OpenCV是一个开源的计算机视觉库,提供了丰富的图像处理和计算机视觉算法,可以用于车流量检测系统中的图像处理和分析。Yolov5是一个基于深度学习的目标检测算法,具有高准确率和实时性的特点,可以用于车辆的检测和跟踪。 10 | 11 | # 2.图片演示 12 | ![在这里插入图片描述](95a1bedf801749d3898c7d4d177c9aef.png#pic_center) 13 | ![在这里插入图片描述](f5d2e8e3085e480dac832ba0595ad396.png#pic_center) 14 | ![在这里插入图片描述](cd4ce788cbb942eaa002c1df1ecaba89.png#pic_center) 15 | 16 | # 3.视频演示 17 | 18 | # 4.系统流程步骤 19 | 20 | 基于OpenCV和Yolov5的车流量检测系统可以通过以下步骤实现: 21 | 22 | 1. 图像采集:使用摄像头采集道路上的车辆图像。 23 | 24 | 2. 图像预处理:使用OpenCV对采集到的图像进行预处理,包括图像去噪、图像增强等。 25 | 26 | 3. 车辆检测:使用Yolov5对预处理后的图像进行车辆检测,识别出图像中的车辆。 27 | 28 | 4. 车辆跟踪:根据检测到的车辆,使用OpenCV进行车辆的跟踪,追踪车辆在不同帧之间的位置和运动轨迹。 29 | 30 | 5. 车流量统计:根据车辆的跟踪结果,统计道路上的车流量,包括车辆的数量、车辆的速度等。 31 | 32 | 33 | # 5.算法优点 34 | 基于OpenCV和Yolov5的车流量检测系统具有以下优势和意义: 35 | 36 | 1. 高准确率:Yolov5作为一种先进的目标检测算法,具有较高的准确率,可以准确地检测和识别道路上的车辆。 37 | 38 | 2. 实时性强:Yolov5算法的实时性较好,可以在较短的时间内完成车辆的检测和跟踪,实时更新车流量信息。 39 | 40 | 3. 成本低:相比传统的车流量检测方法,基于OpenCV和Yolov5的系统不需要额外的传感器设备,只需要使用摄像头即可实现车流量检测,成本较低。 41 | 42 | 4. 安装方便:基于OpenCV和Yolov5的系统只需要在道路上布设摄像头,安装和维护较为方便。 43 | 44 | 5. 实用性强:车流量检测系统可以为交通管理部门提供实时的交通状况信息,帮助制定合理的交通策略,优化交通流量,提高道路利用效率,减少交通拥堵和事故发生的可能性。 45 | 46 | 综上所述,基于OpenCV和Yolov5的车流量检测系统具有重要的研究意义和实际应用价值,可以为城市交通管理提供有效的技术支持,促进交通运输的安全、高效和可持续发展。 47 | 48 | # 6.数据集的制作 49 | 在车流量统计中只需要识别道路中的车辆,因此在制作数据集时只选取车辆一种类别,其他非车辆物体作为负样本,包含车辆的正样本有8000个,负样本包含行人、飞机、船等共3000个。 50 | 车辆识别数据集制作首先运用图像标注软件对车辆进行标注,并将所标注的信息生成相对应的xml文件,xml文件包含图片名称、图片路径、目标标签名称及目标位置坐标,车辆标注过程如图3.18所示。包含标注信息的xml文件不能直接用来训练YOLO网络,需要将xml文件转换成YOLO支持的txt文件。标注完所有图片后,将原图及生成的所有文件按照VOC数据文件结构存放,以供训练车辆识别模型使用。 51 | ![在这里插入图片描述](cb1c9a78ce2e4db9919c2ce70b7ef530.png) 52 | # 7.网络模型优化 53 | YOLO网络采用均方误差(mean squared error)作为损失函数,这种损失函数的设计形式对优化模型参数非常有利。为了更好地训练网络模型,YOLO网络在反向传播的过程中,其损失函数共包含三部分内容: 54 | (1)标注数据与网格预测坐标之间的误差(coordError) ; 55 | (2)目标的预测边界框与真实边界框之间的交集与并集的比值误差( iouError) ;(3)目标的分类误差(classError)。 56 | YOLO的损失函数如下: 57 | ![在这里插入图片描述](6008ff4aad324519a83f73e1602b3412.png) 58 | (w,y)表示网络预测目标框的宽和高;(w,,h, )表示标签中目标框的宽和高;C表示网络预测目标时计算的置信度分数;己,表示网络设置的置信度分数;P(c)表示网络预测的目标属于某一类别的概率;(c)表示目标真实类别的概率;参数⒉ora的引入是为了增强边界框在损失计算中的重要性。 59 | 能够减弱非目标区域对目标区域置信度计算的影响,Aoobj =0.5;I表示图像中第i个图像块有目标,TW表示在第i个图像块的第i个预测框中有目标,若无目标刷头noobj在预测目标的边界框时,预测结果对大目标和小目标的影响是相同的,然而真实情况是大目标的敏感性小于小目标,当边界框的宽和高(w,h)发生略微变化时,小目标的边界框就会消失,因此,YOLO网络采用平方根处理边界框的宽和高(w,h),这种对边界框的处理方式虽然能够使得大目标与小目标的敏感性接近一致,但是没有考虑到物体尺寸存在差异时对整体误差的影响不同,交通视频中往往车型较多,YOLO网络损失函数对大车和小车的预测边界框采用统一的误差,这与真实情况不符,为了体现出不同尺寸的车辆产生的误差在整个网络中所占的比重不同,本文采用比值的方式对损失函数进行优化,运用( w;-w, / ,,h,-h, / h,)代替原损失函数的(w,-w,,(h,-Vh,),这样不但可以提升网络预测物体类别的能力,也可以优化目标边框的位置。优化后的损失函数如式所示: 60 | ![在这里插入图片描述](9c4c0adf54d6422da6272749a6aad8be.png) 61 | 62 | # 8.核心代码讲解 63 | 64 | #### 8.1 detector_CPU.py 65 | 66 | ```python 67 | 68 | class Detector: 69 | def __init__(self): 70 | self.img_size = 640 71 | self.threshold = 0.1 72 | self.stride = 1 73 | 74 | self.weights = './weights/output_of_small_target_detection.pt' 75 | 76 | self.device = '0' if torch.cuda.is_available() else 'cpu' 77 | self.device = select_device(self.device) 78 | model = attempt_load(self.weights, map_location=self.device) 79 | model.to(self.device).eval() 80 | model.float() 81 | 82 | self.m = model 83 | self.names = model.module.names if hasattr( 84 | model, 'module') else model.names 85 | 86 | def preprocess(self, img): 87 | img0 = img.copy() 88 | img = letterbox(img, new_shape=self.img_size)[0] 89 | img = img[:, :, ::-1].transpose(2, 0, 1) 90 | img = np.ascontiguousarray(img) 91 | img = torch.from_numpy(img).to(self.device) 92 | img = img.float() 93 | img /= 255.0 94 | if img.ndimension() == 3: 95 | img = img.unsqueeze(0) 96 | 97 | return img0, img 98 | 99 | def detect(self, im): 100 | im0, img = self.preprocess(im) 101 | 102 | pred = self.m(img, augment=False)[0] 103 | pred = pred.float() 104 | pred = non_max_suppression(pred, self.threshold, 0.4) 105 | 106 | boxes = [] 107 | for det in pred: 108 | if det is not None and len(det): 109 | det[:, :4] = scale_coords( 110 | img.shape[2:], det[:, :4], im0.shape).round() 111 | 112 | for *x, conf, cls_id in det: 113 | lbl = self.names[int(cls_id)] 114 | if lbl not in ['car','bus','truck']: 115 | continue 116 | x1, y1 = int(x[0]), int(x[1]) 117 | x2, y2 = int(x[2]), int(x[3]) 118 | 119 | xm = x2 120 | ym = y2 121 | boxes.append((x1, y1, x2, y2, lbl, conf)) 122 | 123 | return boxes 124 | ``` 125 | 封装的类名为`Detector`,包含以下方法: 126 | - `__init__`:初始化模型和参数 127 | - `preprocess`:预处理图像 128 | - `detect`:检测目标并返回检测结果 129 | 130 | 这个程序文件名为detector_CPU.py,它是一个目标检测器的类。该类具有以下属性和方法: 131 | 132 | 属性: 133 | - img_size:图像的尺寸,默认为640 134 | - threshold:目标检测的置信度阈值,默认为0.1 135 | - stride:步长,默认为1 136 | - weights:模型的权重文件路径,默认为'./weights/output_of_small_target_detection.pt' 137 | - device:设备类型,如果有GPU则为'0',否则为'cpu' 138 | - m:加载的模型 139 | - names:目标类别的名称列表 140 | 141 | 方法: 142 | - __init__(self):初始化方法,加载模型并设置相关参数 143 | - preprocess(self, img):预处理方法,将输入图像进行尺寸调整、通道转换等操作,返回原始图像和处理后的图像 144 | - detect(self, im):目标检测方法,对输入图像进行目标检测,返回检测到的目标框的列表 145 | 146 | 在detect方法中,首先调用preprocess方法对输入图像进行预处理。然后使用加载的模型对处理后的图像进行目标检测,得到预测结果。接着对预测结果进行非最大抑制,去除重叠的目标框。最后,遍历每个检测到的目标框,筛选出类别为'car'、'bus'和'truck'的目标框,并将其添加到结果列表中。最终返回结果列表。 147 | 148 | #### 8.2 detector_GPU.py 149 | 150 | ```python 151 | 152 | class Detector: 153 | def __init__(self): 154 | self.img_size = 640 155 | self.threshold = 0.1 156 | self.stride = 1 157 | self.weights = './weights/Attention_mechanism.pt' 158 | self.device = '0' if torch.cuda.is_available() else 'cpu' 159 | self.device = select_device(self.device) 160 | model = attempt_load(self.weights, map_location=self.device) 161 | model.to(self.device).eval() 162 | model.half() 163 | self.m = model 164 | self.names = model.module.names if hasattr(model, 'module') else model.names 165 | 166 | def preprocess(self, img): 167 | img0 = img.copy() 168 | img = letterbox(img, new_shape=self.img_size)[0] 169 | img = img[:, :, ::-1].transpose(2, 0, 1) 170 | img = np.ascontiguousarray(img) 171 | img = torch.from_numpy(img).to(self.device) 172 | img = img.half() 173 | img /= 255.0 174 | if img.ndimension() == 3: 175 | img = img.unsqueeze(0) 176 | return img0, img 177 | 178 | def detect(self, im): 179 | im0, img = self.preprocess(im) 180 | pred = self.m(img, augment=False)[0] 181 | pred = pred.float() 182 | pred = non_max_suppression(pred, self.threshold, 0.4) 183 | boxes = [] 184 | for det in pred: 185 | if det is not None and len(det): 186 | det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round() 187 | for *x, conf, cls_id in det: 188 | lbl = self.names[int(cls_id)] 189 | if lbl not in ['bicycle','car', 'bus', 'truck']: 190 | continue 191 | x1, y1 = int(x[0]), int(x[1]) 192 | x2, y2 = int(x[2]), int(x[3]) 193 | xm = x2 194 | ym = y2 195 | if ym +0.797* xm -509.77 > 0: 196 | boxes.append((x1, y1, x2, y2, lbl, conf)) 197 | return boxes 198 | ``` 199 | 200 | 这个程序文件名为detector_GPU.py,它是一个目标检测器的类。该类具有以下功能: 201 | 202 | 1. 初始化函数:设置图像大小、阈值和步长等参数,加载模型权重文件,选择设备(如果有GPU则选择GPU,否则选择CPU),将模型加载到设备上,并设置为评估模式。 203 | 204 | 2. 预处理函数:对输入的图像进行预处理,包括调整图像大小、转换颜色通道顺序、转换为numpy数组、转换为torch张量、归一化等操作。 205 | 206 | 3. 检测函数:对输入的图像进行目标检测,返回检测到的目标框的坐标、类别和置信度。该函数首先调用预处理函数对图像进行处理,然后使用加载的模型对图像进行推理,得到预测结果。接着使用非最大抑制算法对预测结果进行筛选,去除重叠的框,并根据阈值进行置信度过滤。最后,根据类别进行筛选,只保留自行车、汽车、公交车和卡车的目标框。 207 | 208 | 该程序依赖于其他模块和库,如torch、numpy、cv2等,这些模块和库需要提前安装和导入。 209 | 210 | #### 8.3 Mouse.py 211 | 212 | ```python 213 | import cv2 214 | 215 | class MouseClick: 216 | def __init__(self, img): 217 | self.img = img 218 | 219 | def on_EVENT_LBUTTONDOWN(self, event, x, y, flags, param): 220 | if event == cv2.EVENT_LBUTTONDOWN: 221 | print("(%d,%d)" % (x, y)) 222 | xy = "%d,%d" % (x, y) 223 | cv2.circle(self.img, (x, y), 1, (255, 0, 0), thickness=-1) 224 | cv2.putText(self.img, xy, (x, y), cv2.FONT_HERSHEY_PLAIN, 225 | 1.0, (0, 0, 0), thickness=1) 226 | cv2.imshow("image", self.img) 227 | 228 | def mouse(self): 229 | cv2.namedWindow("image") 230 | cv2.setMouseCallback("image", self.on_EVENT_LBUTTONDOWN) 231 | cv2.imshow("image", self.img) 232 | 233 | while (True): 234 | try: 235 | cv2.waitKey(100) 236 | except Exception: 237 | cv2.destroyAllWindows() 238 | break 239 | 240 | cv2.waitKey(0) 241 | cv2.destroyAllWindows() 242 | ``` 243 | 244 | 这个程序文件名为Mouse.py,主要功能是在图像上显示鼠标点击的坐标,并在点击位置绘制一个蓝色的圆圈。程序使用了OpenCV库来处理图像和鼠标事件。具体的实现过程如下: 245 | 246 | 1. 导入cv2库。 247 | 2. 定义一个名为mouse的函数,该函数接受一个图像作为参数。 248 | 3. 在函数内部定义一个名为on_EVENT_LBUTTONDOWN的回调函数,用于处理鼠标左键点击事件。 249 | 4. 如果检测到鼠标左键点击事件,将点击的坐标打印出来,并将坐标信息添加到图像上,绘制一个蓝色的圆圈。 250 | 5. 创建一个名为"image"的窗口,并将鼠标事件回调函数绑定到该窗口上。 251 | 6. 在窗口中显示图像。 252 | 7. 进入一个无限循环,等待用户操作。 253 | 8. 如果捕获到异常,关闭窗口并退出循环。 254 | 9. 等待用户按下任意键后关闭窗口。 255 | 256 | 总体来说,这个程序实现了一个简单的图像交互界面,可以显示鼠标点击的坐标,并在图像上进行标注。 257 | 258 | #### 8.4 tracker.py 259 | 260 | ```python 261 | 262 | class ObjectTracker: 263 | def __init__(self): 264 | cfg = get_config() 265 | cfg.merge_from_file("./deep_sort/configs/deep_sort.yaml") 266 | self.deepsort = DeepSort(cfg.DEEPSORT.REID_CKPT, 267 | max_dist=cfg.DEEPSORT.MAX_DIST, min_confidence=cfg.DEEPSORT.MIN_CONFIDENCE, 268 | nms_max_overlap=cfg.DEEPSORT.NMS_MAX_OVERLAP, max_iou_distance=cfg.DEEPSORT.MAX_IOU_DISTANCE, 269 | max_age=cfg.DEEPSORT.MAX_AGE, n_init=cfg.DEEPSORT.N_INIT, nn_budget=cfg.DEEPSORT.NN_BUDGET, 270 | use_cuda=True) 271 | 272 | def draw_bboxes(self, image, bboxes, line_thickness): 273 | line_thickness = line_thickness or round( 274 | 0.002 * (image.shape[0] + image.shape[1]) * 0.5) + 1 275 | 276 | list_pts = [] 277 | point_radius = 4 278 | 279 | for (x1, y1, x2, y2, cls_id, pos_id) in bboxes: 280 | color = (0, 255, 0) 281 | 282 | # 撞线的点 283 | check_point_x = x1 284 | check_point_y = int(y1 + ((y2 - y1) * 0.6)) 285 | 286 | c1, c2 = (x1, y1), (x2, y2) 287 | cv2.rectangle(image, c1, c2, color, thickness=line_thickness, lineType=cv2.LINE_AA) 288 | 289 | font_thickness = max(line_thickness - 1, 1) 290 | t_size = cv2.getTextSize(cls_id, 0, fontScale=line_thickness / 3, thickness=font_thickness)[0] 291 | c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3 292 | cv2.rectangle(image, c1, c2, color, -1, cv2.LINE_AA) # filled 293 | cv2.putText(image, '{} ID-{}'.format(cls_id, pos_id), (c1[0], c1[1] - 2), 0, line_thickness / 3, 294 | [225, 255, 255], thickness=font_thickness, lineType=cv2.LINE_AA) 295 | 296 | list_pts.append([check_point_x - point_radius, check_point_y - point_radius]) 297 | list_pts.append([check_point_x - point_radius, check_point_y + point_radius]) 298 | list_pts.append([check_point_x + point_radius, check_point_y + point_radius]) 299 | list_pts.append([check_point_x + point_radius, check_point_y - point_radius]) 300 | 301 | ndarray_pts = np.array(list_pts, np.int32) 302 | 303 | cv2.fillPoly(image, [ndarray_pts], color=(0, 0, 255)) 304 | 305 | list_pts.clear() 306 | 307 | return image 308 | 309 | def update(self, bboxes, image): 310 | bbox_xywh = [] 311 | confs = [] 312 | bboxes2draw = [] 313 | 314 | if len(bboxes) > 0: 315 | for x1, y1, x2, y2, lbl, conf in bboxes: 316 | obj = [ 317 | int((x1 + x2) * 0.5), int((y1 + y2) * 0.5), 318 | x2 - x1, y2 - y1 319 | ] 320 | bbox_xywh.append(obj) 321 | confs.append(conf) 322 | 323 | xywhs = torch.Tensor(bbox_xywh) 324 | confss = torch.Tensor(confs) 325 | 326 | outputs = self.deepsort.update(xywhs, confss, image) 327 | 328 | for x1, y1, x2, y2, track_id in list(outputs): 329 | # x1, y1, x2, y2, track_id = value 330 | center_x = (x1 + x2) * 0.5 331 | center_y = (y1 + y2) * 0.5 332 | 333 | label = self.search_label(center_x=center_x, center_y=center_y, 334 | bboxes_xyxy=bboxes, max_dist_threshold=20.0) 335 | 336 | bboxes2draw.append((x1, y1, x2, y2, label, track_id)) 337 | pass 338 | pass 339 | 340 | return bboxes2draw 341 | 342 | def search_label(self, center_x, center_y, bboxes_xyxy, max_dist_threshold): 343 | """ 344 | 在 yolov5 的 bbox 中搜索中心点最接近的label 345 | :param center_x: 346 | :param center_y: 347 | :param bboxes_xyxy: 348 | :param max_dist_threshold: 349 | :return: 字符串 350 | """ 351 | label = '' 352 | # min_label = '' 353 | min_dist = -1.0 354 | 355 | for x1, y1, x2, y2, lbl, conf in bboxes_xyxy: 356 | center_x2 = (x1 + x2) * 0.5 357 | center_y2 = (y1 + y2) * 0.5 358 | 359 | # 横纵距离都小于 max_dist 360 | min_x = abs(center_x2 - center_x) 361 | min_y = abs(center_y2 - center_y) 362 | 363 | if min_x < max_dist_threshold and min_y < max_dist_threshold: 364 | # 距离阈值,判断是否在允许误差范围内 365 | # 取 x, y 方向上的距离平均值 366 | avg_dist = (min_x + min_y) * 0.5 367 | if min_dist == -1.0: 368 | # 第一次赋值 369 | min_dist = avg_dist 370 | # 赋值label 371 | label = lbl 372 | pass 373 | else: 374 | # 若不是第一次,则距离小的优先 375 | if avg_dist < min_dist: 376 | min_dist = avg_dist 377 | # label 378 | label = lbl 379 | pass 380 | pass 381 | pass 382 | 383 | return label 384 | ``` 385 | 386 | 该程序文件名为tracker.py,主要功能是使用深度学习模型进行目标跟踪。程序首先导入了所需的库和模块,包括cv2、torch和numpy等。然后,通过解析配置文件获取配置信息,并使用这些配置信息初始化DeepSort跟踪器。接下来,程序定义了一些辅助函数,包括绘制边界框和更新跟踪结果的函数。其中,绘制边界框函数用于在图像上绘制检测到的目标边界框和标签,更新函数用于根据检测结果更新跟踪器的状态。最后,程序定义了一个搜索标签的函数,用于在检测到的目标边界框中搜索与给定中心点最接近的标签。整个程序的目标是实现目标跟踪的功能。 387 | 388 | #### 8.5 ui.py 389 | 390 | ```python 391 | import numpy as np 392 | import tracker 393 | from detector_CPU import Detector 394 | import cv2 395 | 396 | class TrafficFlowDetection: 397 | def __init__(self, video_path): 398 | self.video_path = video_path 399 | self.detector = Detector() 400 | self.tracker = tracker 401 | self.down_count = 0 402 | self.up_count = 0 403 | 404 | def detect_traffic_flow(self): 405 | mask_image_temp = np.zeros((1080, 1920), dtype=np.uint8) 406 | list_pts_blue = [[0, 600], [0, 900], [1920, 900], [1920, 600]] 407 | ndarray_pts_blue = np.array(list_pts_blue, np.int32) 408 | polygon_blue_value_1 = cv2.fillPoly(mask_image_temp, [ndarray_pts_blue], color=1) 409 | polygon_blue_value_1 = 410 | ``` 411 | 这个程序文件名为ui.py,主要实现了一个车流量监测系统的图形界面。程序中导入了一些必要的库,包括numpy、tracker、detector_CPU、cv2、matplotlib等。程序定义了一些函数,包括det_yolov5v6、ssd、yolox等。其中det_yolov5v6函数是主要的车流量监测函数,通过读取视频文件,进行目标检测和跟踪,并根据撞线检测来统计车辆的进入和离开数量。程序还定义了一些线程类,用于在后台进行视频处理。最后,程序创建了一个图形界面,并实现了 412 | 413 | 这个程序文件是一个深度排序(DeepSort)的实现。它包含了一个名为DeepSort的类,该类用于跟踪目标并输出目标的边界框和身份信息。 414 | 415 | DeepSort类的构造函数接受一些参数,包括模型路径、最大距离、最小置信度、非最大抑制的最大重叠度、最大IOU距离、最大年龄、初始化帧数和NN预算。构造函数初始化了一些变量,并创建了一个特征提取器(Extractor)和一个跟踪器(Tracker)。 416 | 417 | 类中的update方法用于更新跟踪器。它接受目标的边界框、置信度和原始图像作为输入,并生成检测结果。然后,它运行非最大抑制算法,对检测结果进行筛选。接下来,它通过调用跟踪器的predict和update方法来更新跟踪器的状态。最后,它输出跟踪结果,包括边界框和身份信息。 418 | 419 | 类中还包含了一些辅助方法,用于将边界框的表示方式进行转换,以及获取目标的特征。 420 | 421 | 总的来说,这个程序文件实现了一个深度排序算法,用于目标跟踪和身份识别。它使用了深度学习模型进行特征提取,并结合了最近邻距离度量和非最大抑制算法来实现目标跟踪。 422 | 423 | # 9.系统整体结构 424 | 425 | 整体功能和构架概述: 426 | 该项目是一个车流量监测系统,主要功能是通过目标检测和跟踪来统计车辆的进入和离开数量。程序使用了深度学习模型进行目标检测和特征提取,并结合了DeepSort算法进行目标跟踪。图形界面提供了用户交互的界面,可以选择视频文件进行车流量监测,并显示监测结果。 427 | 428 | 下面是每个文件的功能概述: 429 | 430 | | 文件路径 | 功能概述 | 431 | | --- | --- | 432 | | detector_CPU.py | 实现目标检测器的类,使用CPU进行目标检测 | 433 | | detector_GPU.py | 实现目标检测器的类,使用GPU进行目标检测 | 434 | | Mouse.py | 实现图像交互界面,显示鼠标点击的坐标 | 435 | | tracker.py | 实现目标跟踪器的类,使用深度学习模型进行目标跟踪 | 436 | | ui.py | 实现车流量监测系统的图形界面 | 437 | | deep_sort\deep_sort\deep_sort.py | 实现DeepSort跟踪算法的类 | 438 | | deep_sort\deep_sort\__init__.py | 初始化文件 | 439 | | deep_sort\deep_sort\deep\evaluate.py | 实现评估函数 | 440 | | deep_sort\deep_sort\deep\feature_extractor.py | 实现特征提取器的类 | 441 | | deep_sort\deep_sort\deep\model.py | 实现模型的类 | 442 | | deep_sort\deep_sort\deep\original_model.py | 实现原始模型的类 | 443 | | deep_sort\deep_sort\deep\test.py | 实现测试函数 | 444 | | deep_sort\deep_sort\deep\train.py | 实现训练函数 | 445 | | deep_sort\deep_sort\deep\__init__.py | 初始化文件 | 446 | | deep_sort\deep_sort\sort\detection.py | 实现目标检测的类 | 447 | | deep_sort\deep_sort\sort\iou_matching.py | 实现IOU匹配的类 | 448 | | deep_sort\deep_sort\sort\kalman_filter.py | 实现卡尔曼滤波的类 | 449 | | deep_sort\deep_sort\sort\linear_assignment.py | 实现线性分配的类 | 450 | | deep_sort\deep_sort\sort\nn_matching.py | 实现最近邻匹配的类 | 451 | | deep_sort\deep_sort\sort\preprocessing.py | 实现预处理的类 | 452 | | deep_sort\deep_sort\sort\track.py | 实现跟踪目标的类 | 453 | | deep_sort\deep_sort\sort\tracker.py | 实现跟踪器的类 | 454 | | deep_sort\deep_sort\sort\__init__.py | 初始化文件 | 455 | | deep_sort\utils\asserts.py | 实现断言函数 | 456 | | deep_sort\utils\draw.py | 实现绘图函数 | 457 | | deep_sort\utils\evaluation.py | 实现评估函数 | 458 | | deep_sort\utils\io.py | 实现输入输出函数 | 459 | | deep_sort\utils\json_logger.py | 实现JSON日志记录器的类 | 460 | | deep_sort\utils\log.py | 实现日志记录函数 | 461 | | deep_sort\utils\parser.py | 实现解析器的类 | 462 | | deep_sort\utils\tools.py | 实现工具函数 | 463 | | deep_sort\utils\__init__.py | 初始化文件 | 464 | | models\common.py | 实现通用模型函数 | 465 | | models\experimental.py | 实现实验模型函数 | 466 | | models\export.py | 实现模型导出函数 | 467 | | models\yolo.py | 实现YOLO模型的类 | 468 | | models\__init__.py | 初始化文件 | 469 | | utils\activations.py | 实现激活函数 | 470 | | utils\autoanchor.py | 实现自动锚框函数 | 471 | | utils\datasets.py | 实现数据集函数 | 472 | | utils\general.py | 实现通用函数 | 473 | | utils\google_utils.py | 实现Google工具函数 | 474 | | utils\loss.py | 实现损失函数 | 475 | | utils\metrics.py | 实现评估指标函数 | 476 | | utils\plots.py | 实现绘图函数 | 477 | | utils\torch_utils.py | 实现PyTorch工具函数 | 478 | | utils\__init__.py | 初始化文件 | 479 | | utils\aws\resume.py | 实现AWS恢复函数 | 480 | | utils\aws\__init__.py | 初始化文件 | 481 | | utils\wandb_logging\log_dataset.py | 实现WandB日志记录器的类 | 482 | | utils\wandb_logging\wandb_utils.py | 实现WandB工具函数 | 483 | | utils\wandb_logging\__init__.py | 初始化文件 | 484 | 485 | # 10.系统整合 486 | 下图[完整源码&环境部署视频教程&自定义UI界面](https://xiaocichang.com/886633438a604fd381c464d58b62bc28/goods/detail?timestamp=1699423816397&share_type=LINK&spmId=a0.bs11.0.0&type=spu&nw_k=619c0ea0-0744-4f98-8a4b-2111b57da1f7&invite_club=QlcA7CaU75V5wBagRCbMMA%3D%3D&invite_user=c11K2IbpkcZMC1IeE4DrscDKZrZ3wVSyMWkosA9Pl4U%3D&d_id=d0Ie4bwWSP1pRojg63Qfdw%3D%3D) 487 | ![在这里插入图片描述](faef9ab759c34b0db4e0e6a5bb27e811.png#pic_center) 488 | 参考博客[《OpenCV&YOLOv5的车流量统计系统(源码&部署教程)》](https://mbd.pub/o/qunshan/work) 489 | 490 | --- 491 | # 11.参考文献 492 | 493 | [1]王信,汪友生.基于深度学习与传统机器学习的人脸表情识别综述[J].应用科技.2018,(1).DOI:10.11991/yykj.201707008. 494 | [2]蔡成涛,吴科君,刘秋飞,等.基于改进YOLO算法的全景多目标实时检测[J].计算机工程与设计.2018,(10).DOI:10.16208/j.issn1000-7024.2018.10.044. 495 | [3]樊香所,徐智勇,张建林.改进梯度倒数加权滤波红外弱小目标背景抑制[J].光电工程.2017,(7).DOI:10.3969/j.issn.1003-501X.2017.07.008. 496 | [4]周海鹏,王芳,田建艳.基于HSV颜色特征的多目标视频检测与跟踪算法[J].科学技术与工程.2017,(20). 497 | [5]朱煜,赵江坤,王逸宁,等.基于深度学习的人体行为识别算法综述[J].自动化学报.2016,(6).DOI:10.16383/j.aas.2016.c150710. 498 | [6]孟令成,吴健珍.基于视频图像的车流量检测系统[J].黑龙江科技信息.2015,(35).DOI:10.3969/j.issn.1673-1328.2015.35.078. 499 | [7]马怀志.基于视频图像处理技术的车流量检测系统的设计与研究[J].长春工程学院学报(自然科学版).2015,(4).DOI:10.3969/j.issn.1009-8984.2015.04.026. 500 | [8]席志红,李永佳,段炼.基于局部特征和Mean Shift的目标跟踪算法研究[J].电子科技.2015,(6).DOI:10.16180/j.cnki.issn1007-7820.2015.06.004. 501 | [9]张桂梅,姚伟.一种基于低秩矩阵的车流量检测算法[J].南昌航空大学学报(自然科学版).2014,(4).DOI:10.3969/j.issn.1001-4926.2014.04.012. 502 | [10]陆化普,李瑞敏.城市智能交通系统的发展现状与趋势[J].工程研究-跨学科视野中的工程.2014,(1).DOI:10.3724/SP.J.1224.2014.00006. 503 | 504 | --- 505 | 506 | --- 507 | #### 如果您需要更详细的【源码和环境部署教程】,除了通过【系统整合】小节的链接获取之外,还可以通过邮箱以下途径获取: 508 | #### 1.请先在GitHub上为该项目点赞(Star),编辑一封邮件,附上点赞的截图、项目的中文描述概述(About)以及您的用途需求,发送到我们的邮箱 509 | #### sharecode@yeah.net 510 | #### 2.我们收到邮件后会定期根据邮件的接收顺序将【完整源码和环境部署教程】发送到您的邮箱。 511 | #### 【免责声明】本文来源于用户投稿,如果侵犯任何第三方的合法权益,可通过邮箱联系删除。 --------------------------------------------------------------------------------