LK 博客
OpenCV 实战:基于背景减法的智能车辆计数系统
项目
约 1 分钟阅读 1 赞 1 条评论 鸿蒙黑体

OpenCV 实战:基于背景减法的智能车辆计数系统

Dang
党旭 @Dang
累计点赞 1 登录后每个账号只能点一次
内容长度 0 正文词元数
正文
目录会跟随阅读位置移动。
阅读进度

基于 OpenCV 的车辆检测与计数系统

引言

在交通监控、智能停车场管理等领域,车辆的检测与计数是一项非常重要的任务。借助计算机视觉技术,我们可以实现自动化的车辆检测与计数,提高效率和准确性。本文将详细介绍如何使用 OpenCV 库实现一个简单的车辆检测与计数系统。

实现思路

整个系统的实现主要分为以下几个步骤:

  1. 背景减除:通过背景减除算法,将视频中的背景去除,只保留运动的物体(车辆)。
  2. 形态学操作:对去除背景后的图像进行腐蚀、膨胀、闭运算和开运算等形态学操作,以去除噪声并连接车辆的轮廓。
  3. 轮廓检测:使用 cv2.findContours 函数查找图像中的轮廓,并筛选出符合条件的车辆轮廓。
  4. 车辆计数:通过检测车辆中心是否通过预设的检测线,对车辆进行计数。
  5. 用户交互:允许用户通过鼠标绘制多边形区域,只对该区域内的车辆进行检测和计数。

代码实现

1. 初始化参数和变量

min_w = 50
min_h = 50
line_high = 325
offset = 12
car_centers = []
carno = 0
drawing = False
current_line = []
polygons = []
  • min_wmin_h:用于筛选车辆轮廓的最小宽度和高度。
  • line_high:检测线的高度。
  • offset:允许车辆中心通过检测线的误差范围。
  • car_centers:用于存储车辆中心坐标的列表。
  • carno:车辆计数器。
  • drawing:用于标记是否正在绘制多边形。
  • current_line:用于存储当前绘制的多边形的顶点。
  • polygons:用于存储所有绘制的多边形。

2. 定义辅助函数

def center(x, y, w, h):
    cx = x + w // 2
    cy = y + h // 2
    return (cx, cy)

def draw_callback(event, x, y, flags, param):
    global drawing, current_line
    if event == cv2.EVENT_LBUTTONDOWN:
        drawing = True
        current_line = [(x, y)]
    elif event == cv2.EVENT_MOUSEMOVE:
        if drawing:
            current_line.append((x, y))
    elif event == cv2.EVENT_LBUTTONUP:
        drawing = False
        current_line.append((x, y))
        if len(current_line) > 2:
            polygons.append(current_line.copy())
        current_line = []

def is_point_in_any_polygon(point):
    if len(polygons) == 0:
        return True  # 没画区域,全显示
    for poly in polygons:
        pts = np.array(poly, np.int32)
        if cv2.pointPolygonTest(pts, point, False) >= 0:
            return True
    return False
  • center 函数:用于计算矩形的中心坐标。
  • draw_callback 函数:鼠标回调函数,用于处理鼠标事件,实现多边形的绘制。
  • is_point_in_any_polygon 函数:用于判断一个点是否在任意一个绘制的多边形内。

3. 视频处理和车辆检测

cv2.namedWindow('frame', cv2.WINDOW_NORMAL)
cv2.namedWindow('dilate', cv2.WINDOW_NORMAL)
cv2.resizeWindow('dilate', 540, 540)
cv2.resizeWindow('frame', 540, 540)
cv2.setMouseCallback('frame', draw_callback)
cap = cv2.VideoCapture("car three.mp4")
bgsubmog = cv2.createBackgroundSubtractorMOG2()
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

while True:
    ret, frame = cap.read()
    if not ret:
        break
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray, (3, 3), 3)
    mask = bgsubmog.apply(blurred)
    mask1 = cv2.medianBlur(mask, 5)
    eroded = cv2.erode(mask1, kernel)
    dilated = cv2.dilate(eroded, kernel, iterations=4)
    closed = cv2.morphologyEx(dilated, cv2.MORPH_CLOSE, kernel)
    closed = cv2.morphologyEx(closed, cv2.MORPH_OPEN, kernel)
    contours, _ = cv2.findContours(closed, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    cv2.line(frame, (10, line_high), (1200, line_high), (255, 255, 0), 2)
    for contour in contours:
        x, y, w, h = cv2.boundingRect(contour)
        if w >= min_w and h >= min_h:
            center_point = center(x, y, w, h)
            if is_point_in_any_polygon(center_point):
                car_centers.append(center_point)
                cv2.circle(frame, center_point, 5, (0, 255, 0), -1)
                cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)
                if abs(center_point[1] - line_high) <= offset:
                    carno += 1
                    car_centers = []
    cv2.putText(frame, f"Car Count: {carno}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
    for poly in polygons:
        pts = np.array(poly, np.int32)
        pts = pts.reshape((-1, 1, 2))
        cv2.polylines(frame, [pts], True, (0, 255, 0), 2)
    cv2.imshow('frame', frame)
    cv2.imshow('dilate', closed)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()
  • 首先,创建窗口并设置鼠标回调函数,打开视频文件。
  • 然后,在循环中读取视频帧,进行背景减除、高斯模糊、中值滤波、形态学操作等处理。
  • 接着,查找图像中的轮廓,并筛选出符合条件的车辆轮廓。
  • 对于每个符合条件的车辆轮廓,计算其中心坐标,并判断是否在绘制的多边形内。
  • 如果车辆中心通过检测线,则车辆计数器加 1。
  • 最后,在图像上显示车辆计数结果和绘制的多边形,并显示处理后的图像。
  • 提醒:上述代码没有进行精简处理,作者本人进行多轮调试,背景减法代码多有叠加,后来者可进行更细致化学习,对上述主代码进行精修。

总结

通过以上步骤,我们实现了一个简单的车辆检测与计数系统。该系统可以对视频中的车辆进行检测和计数,并允许用户通过鼠标绘制多边形区域,只对该区域内的车辆进行检测和计数。在实际应用中,可以根据需要调整参数和算法,以提高检测的准确性和效率。

交于普通车辆检测代码,此项目添加了上篇所讲的鼠标绘图知识,再次对opencv的学习进行了一次总结。

作者名片

Dang
党旭
@Dang

这个作者暂时还没有填写个人简介。

评论区
文章作者和管理员都可以管理这里的评论。
1 条评论
登录后即可参与评论。 去登录
hyy888
黄洋洋 @hyy888 2026-04-28 22:02
继续深入学习