背景减除(Background Subtraction)是许多基于计算机视觉的任务中的主要预处理步骤,如果我们有完整的静止的背景帧,那么我们可以通过帧差法来计算像素差从而获得到前景对象。 但是在大多数情况下,我们可能没有这样的图像,所以我们需要从我们拥有的任何图像中提取背景。当运动物体有阴影时,由于阴影也在运动,情况会变的更加复杂,为此引入了背景减除法,通过这一方法我们能够从视频中分离出运动的物体前景,从而达到目标检测的目的。 cv2.BackgroundSubtractorMOG2()用法: 这是一个以混合高斯模型为基础的前景/背景分割算法。它是 P.KadewTraKuPong 和 R.Bowden 在2001年提出的。 它使用 K(K = 3 或 5)个高斯分布混合对背景像素进行建模。使用这些颜色(在整个视频中)存在时间的长短作为混合的权重。背景的颜色一般持续的时间最长,而且更加静止。 在编写代码时,我们需要使用函数:mog = cv2.bgsegm.createBackgroundSubtractorMOG() 创建一个背景对象。 这个函数有些可选参数,比如要进行建模场景的时间长度,高斯混合成分的数量,阈值等。将它们全部设置为默认值,然后在整个视频中我们是需要使用 mask = mog.apply(frame) 就可以得到前景的掩膜了。 移动的物体会被标记为白色,背景会被标记为黑色的。 原文链接:https://blog.youkuaiyun.com/weixin_64443786/article/details/131833812
import cv2 import numpy as np cv2.namedWindow('video',cv2.WINDOW_NORMAL) cv2.resizeWindow('video',(640,480)) cap=cv2.VideoCapture(0)#调用自己的摄像头 mog = cv2.createBackgroundSubtractorMOG2() #kernel1 = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))#获取卷积核,相当于np.ones(5,5) kernel2 = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))#获取卷积核,相当于np.ones(5,5) min_w=40#框的大小的参数 min_h=60 line_high=240#线的高度参数 offset=5#在线的周围活动大于line_high才计数 cars=[] carno=0 def center(x,y,w,h): x1=int(w/2) y1=int(h/2) cx=int(x)+x1 cy=int(y)+y1 return cx,cy #z循环读取视频帧 while True: ret,frame=cap.read()#捕捉画面并返回两个值:ret(布尔值,表示是否正确捕捉到图像帧。);frame(图像帧) if ret == True: gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) blur=cv2.GaussianBlur(gray,(3,3),5)#(高斯滤波) fgmask = mog.apply(blur)#通过apply提取出前景 #thresh, fgmask = cv2.threshold(fgmask, 150, 255, cv2.THRESH_BINARY)#将图像二值化 #fgmask1 = cv2.morphologyEx(fgmask, cv2.MORPH_CLOSE, kernel1)#形态学运算,开闭等,后面是卷积核 fgmask2 = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel2) contours,hierarchy = cv2.findContours(fgmask2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)#找到经过处理后的图像中可识别的轮廓 cv2.line(frame,(1,line_high),(630,line_high),(255,0,0),3) # print(contours) # print('------------------') #print(hierarchy) for contour in contours: x,y,w,h=cv2.boundingRect(contour)#返回框的四个点位 value1 = (w > min_w) and (h > min_h) # 判断画出的矩形框是否大于最小值,否则进入下一次循环 if not value1: continue cv2.rectangle(frame,(int(x),int(y)),(int(x+w),int(y+h)),(0,255,255),3)#第一个参数表示在哪个采集处理阶段画框,后面两个是对角坐标 #cv2.imshow('video',fgmask) #将车抽象为一点,即外接矩形的中心点,路过图上线的车才算 xy1=center(x,y,w,h) cars.append(xy1)#做拼接 cv2.circle(frame,(xy1),5,(0,255,255),-1)#-1代表实心圆 for (x,y) in cars: if (y>line_high-offset) and (y<line_high+offset): carno+=1 cars.remove((x,y)) print(carno) cv2.imshow('video', frame) key=cv2.waitKey(10) if key==27:#按ESC退出 break cap.release() cv2.destroyAllWindows()