opencv学习中——车辆检测代码
1自学一个月白天上班晚上看b站视频大模型求教写了个视频车辆检测代码记录一下。2Cars.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), (xw, yh), (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