智慧城市交通系列之车流量检测(一)

您所在的位置:网站首页 线路检测的作用 智慧城市交通系列之车流量检测(一)

智慧城市交通系列之车流量检测(一)

2023-12-24 22:25| 来源: 网络整理| 查看: 265

序言

车流量在目前的交通系统中应该是非常普遍的,可以用于统计某条干道的车辆经过总数,与人流检测实现原理几乎是一样的,都是基于目标检测和跟踪进行,本例的实现是基于yolov5+deepsort,使用yolov5对车辆进行检测,再用deepsort对其跟踪,而后设计一系列的规则撞线进行两个方向的车流数量统计。网上实现的方式有很多种,效果大同小异,可以择优选择学习。

一、实现原理

基于之前的yolo+deepsort上,将person类别改为车辆类别,因为coco数据集中,车辆类别有几种【car,bus,truck】,所以都要保存下来。

首先来看一下yolov5+deepsort的车辆跟踪初始效果,看着密密麻麻的框和id,思考一下该如何去设计这些规则进行统计。 在这里插入图片描述 首先观察图中,需要构建一个区域对经过的车辆进行统计,因为有两个方向,所以这里构建了黄、蓝两个区域,因为考虑到路面并不是规则矩形,所以构建的是多边形区域。mask掩码代码如下:

def draw_mask(height,width): # 根据视频尺寸,填充一个polygon,供撞线计算使用 mask_image_temp = np.zeros((height, width), dtype=np.uint8) # 初始化2个撞线polygon 蓝色 list_pts_blue = [[277, 305], [926, 308], [983, 344], [220, 335]] # 蓝色多边形坐标,可根据自己的场景修改 ndarray_pts_blue = np.array(list_pts_blue, np.int32) polygon_blue_value_1 = cv2.fillPoly(mask_image_temp, [ndarray_pts_blue], color=1) # 构建多边形 polygon_blue_value_1 = polygon_blue_value_1[:, :, np.newaxis] # 填充第二个polygon 黄色 mask_image_temp = np.zeros((height, width), dtype=np.uint8) list_pts_yellow = [[220, 335], [983, 344], [1030, 370], [170, 356]] # 黄色多边形坐标,可根据自己的场景修改 ndarray_pts_yellow = np.array(list_pts_yellow, np.int32) polygon_yellow_value_2 = cv2.fillPoly(mask_image_temp, [ndarray_pts_yellow], color=2) # 构建多边形 polygon_yellow_value_2 = polygon_yellow_value_2[:, :, np.newaxis] # 撞线检测用mask,包含2个polygon,(值范围 0、1、2),供撞线计算使用 polygon_mask_blue_and_yellow = polygon_blue_value_1 + polygon_yellow_value_2 # 缩小尺寸,1920x1080->960x540 polygon_mask_blue_and_yellow = cv2.resize(polygon_mask_blue_and_yellow, (width, height)) # 蓝 色盘 b,g,r blue_color_plate = [255, 0, 0] # 蓝 polygon图片 blue_image = np.array(polygon_blue_value_1 * blue_color_plate, np.uint8) # 黄 色盘 yellow_color_plate = [0, 255, 255] # 黄 polygon图片 yellow_image = np.array(polygon_yellow_value_2 * yellow_color_plate, np.uint8) # 彩色图片(值范围 0-255) color_polygons_image = blue_image + yellow_image # 缩小尺寸,1920x1080->960x540 color_polygons_image = cv2.resize(color_polygons_image, (width, height)) return polygon_mask_blue_and_yellow,color_polygons_image

最后掩码图如下,后面我们会告诉这个掩码怎么使用。 在这里插入图片描述 为了构建出更好的可视化效果,得到的掩码我们使用opencv中的add函数,将deepsort输出的跟踪图与之相融合,得到如下效果图,就能够很清晰的看到车辆经过该区域后计数器开始工作。 在这里插入图片描述 好了,准备工作做完了,接下来该介绍如何使用掩码进行计数。首先yolov5检测后得到的框,需要设计一个撞线的点,这个点将代表着这辆车的坐标,而不是检测得到的框,可以取框的中心点,也可以取其他的点,例如我的例子中就取了图中的该点,这个点将代表着这辆汽车: 在这里插入图片描述 创建两个列表,分别用于记录经过黄色、蓝色区域的车辆id。所以我们就有如下计数规则:

向下记录规则:

当某个点在蓝色区域,并且不在黄色区域时,说明该点是从上往下经过蓝色区域,蓝色区域列表添加其id,不予处理。当该点位于黄色区域后,检查其是否也在蓝色区域列表中,如果在,则说明其是向下的方向,向下计数器+1,同时在两个列表中将其id删除。

往上记录规则同理:

当某个点在黄色区域,并且不在蓝色区域时,说明该点是从下往上经过黄色区域,黄色区域列表添加其id,不予处理。当该点位于蓝色区域后,检查其是否也在黄色区域列表中,如果在,则说明其是向上的方向,向上计数器+1,同时在两个列表中将其id删除。

光看文字的话可能会比较懵逼,可以结合效果图进行理解。 在这里插入图片描述

说了这么多,怎么判断车辆的点是否进入了颜色区域呢?回到上面的代码中,在创建mask掩码的时候,额外创建了一个图像矩阵polygon_mask_blue_and_yellow,蓝色区域在矩阵中的值为1,黄色的则为2。与检测的视频中的位置是对应的,所以我们可以很好的判断,如果某个点的坐标在这个矩阵中值为1,则在蓝色区域中,如果值为2,则在黄色区域。具体代码实现如下:

if len(list_bboxs) > 0: # 如果图上有目标 # ----------------------判断撞线---------------------- for item_bbox in list_bboxs: x1, y1, x2, y2, _, track_id = item_bbox # 取出deepsort返回坐标和id y1_offset = int(y1 + ((y2 - y1) * 0.6)) # 设置一个撞线检测点,(x1,y1),y方向偏移比例 0.0~1.0 # 撞线的点 x, y = x1, y1_offset if polygon_mask_blue_and_yellow[y, x] == 1: # 如果撞线点进入蓝色区域 # 如果撞 蓝polygon if track_id not in self.list_overlapping_blue_polygon: self.list_overlapping_blue_polygon.append(track_id) # 用一个列表记录下车辆id if track_id in self.list_overlapping_yellow_polygon: # 如果这个id也在黄色区域,那么则是外出方向 self.up_count += 1 # 外出计数+1 # print('up count:', self.up_count, ', up id:', track_id) self.list_overlapping_yellow_polygon.remove(track_id) # 删除 黄polygon list 中的此id else: # 无此 track_id,不做其他操作 pass elif polygon_mask_blue_and_yellow[y, x] == 2: # 如果车辆撞线点进入 # 如果撞 黄polygon if track_id not in self.list_overlapping_yellow_polygon: self.list_overlapping_yellow_polygon.append(track_id) # 用另一个列表记录下车辆id if track_id in self.list_overlapping_blue_polygon: # 如果这个id也在蓝色区域,那么则是进入方向 self.down_count += 1 # 进入计数+1 # print('down count:', self.down_count, ', down id:', track_id) self.list_overlapping_blue_polygon.remove(track_id) # 删除 蓝polygon list 中的此id else: # 无此 track_id,不做其他操作 pass else: pass

写的有些凌乱,过后如果发现表达不足的地方过后再修改。

另外本文代码实现是基于此行人计数的仓库,做了部分改进和优化,非常感谢他的开源工作。自己的代码有点凌乱还未整理,打算写完这一系列的文章后再进行上传。原理相对来说比较简单,可以自己尝试着去实现。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3