opencv学习中——车辆检测代码

📅 2026/7/22 3:15:15 👁️ 阅读次数 📝 编程学习
opencv学习中——车辆检测代码

(1)自学一个月,白天上班,晚上看b站视频+大模型求教,写了个视频车辆检测代码,记录一下。

(2)Cars.mp4视频在上一篇文章中。

(3)最终效果不太好,每一帧识别的外框会变动甚至嵌套,不知道是不是前面的形态学处理和轮廓识别的问题。可以通过YOLOv8 + ByteTrack 集成代码解决,还没学,等之后对比下效果。

import cv2 import numpy as np video_path = 'D:/video/' cap = cv2.VideoCapture(f'{video_path}Cars.mp4') #检测线高度,frame.shape是(768, 1364, 3),取550在视频下部 line_high = 550 #线的偏移量 offset = 2 #存放有限车辆的数组 cars = [] #统计车的数量 carno = 0 def center(x, y, w, h): x1 = int(w/2) y1 = int(h/2) cx = x + x1 cy = y + y1 return cx, cy #背景减除,MOG2是改进版本,可以直接apply,需要先进行灰度及去噪处理 sub = cv2.createBackgroundSubtractorMOG2() #sub = cv2.bgsegm.BackgroundSubtractorMOG() #形态学kernel,视频内容是行人、车辆、动物等自然运动目标则首选椭圆核 kernel_ellipse = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) while True: ret, frame = cap.read() if not ret: break #(1)应用背景减除 #灰度 gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #去噪(高斯) blur = cv2.GaussianBlur(gray, (3, 3), 5) fg_mask = sub.apply(blur) # 查看像素值的唯一值 unique_values = np.unique(fg_mask) #print("像素值种类:", unique_values) # 如果输出 [0, 127, 255],说明是三值图 # 如果输出 [0, 255],才是二值图 # 一般默认是输出三值图,开启阴影检测 + 后处理过滤 #(2)阴影过滤:将灰色阴影(127)归为背景(0),只保留纯前景(255) _, fg_clean = cv2.threshold(fg_mask, 127, 255, cv2.THRESH_BINARY) #(3)形态学去噪+填洞:使用椭圆核,先开运算(去除噪声)后闭运算(填充空洞) fg_mask_ellipse = cv2.morphologyEx(fg_clean, cv2.MORPH_OPEN, kernel_ellipse) fg_mask_ellipse = cv2.morphologyEx(fg_mask_ellipse, cv2.MORPH_CLOSE, kernel_ellipse) #(4)轮廓筛选,使用cv2.RETR_EXTERNAL,不用cv2.RETR_TREE # 只需要最外层轮廓,不然会引入无效信息,增加计算开销,增加筛选难度 contours, _ = cv2.findContours(fg_mask_ellipse, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 过滤掉面积小的残留噪声 min_area = 500 valid_contours = [cnt for cnt in contours if cv2.contourArea(cnt) > min_area] #(5)绘图展示 result = frame.copy() # 复制原始彩色帧 #绘制检测线 cv2.line(result, (400, line_high), (1200, line_high), (0, 255, 0), 2) for (i, c) in enumerate(valid_contours): x, y, w, h = cv2.boundingRect(c) #对车辆宽高进行判断,以验证是否是有效车辆 # 根据视频分辨率动态计算最小尺寸 frame_h, frame_w = frame.shape[:2] min_w = int(frame_w * 0.06) # 最小宽度为帧宽的xx% min_h = int(frame_h * 0.08) # 最小高度为帧高的xx% isValid = (w >= min_w) and (h >= min_h) if not isValid: continue #不满足则跳过接下来的步骤重新步入循环 #到这里都是有效车 cv2.rectangle(result, (x, y), (x+w, y+h), (0, 0, 255), 2) cpoint = center(x, y, w, h) cars.append(cpoint) for (x, y) in cars: #要有一条线 #有范围,上下2个像素 #从数组中减去 if(( y > line_high - offset) and (y < line_high + offset)): carno += 1 cars.remove((x, y)) print(carno) #对比之后确实椭圆核的每一帧都处理的更细腻 cv2.putText(result, 'Cars Count: ' + str(carno), (500, 60), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 5) cv2.imshow('Video', result) #cv2.imshow('Mask', fg_mask) #cv2.imshow('Clean', fg_clean) #cv2.imshow('Ellipse Kernel Result', fg_mask_ellipse) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()

翻译

搜索

复制

src="">