添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
精彩文章免费看

【python opencv】背景、前景分离

官方文档BackgroundSubtractorMOG2: https://docs.opencv.org/3.1.0/d7/d7b/classcv_1_1BackgroundSubtractorMOG2.html
前景检测(GMM模型): https://blog.csdn.net/xueweuchen/article/details/19936991
Opencv3之动态目标检测:BackgroundSubtractorMOG2参数配置: https://blog.csdn.net/m0_37901643/article/details/72841289
Python cv2.createBackgroundSubtractorMOG2() Examples: https://www.programcreek.com/python/example/89404/cv2.createBackgroundSubtractorMOG2

1. BackgroundSubtractorMOG2简介

BackgroundSubtractorMOG2是以高斯混合模型为基础的背景/前景分割算法。它是以2004年和2006年Z.Zivkovic的两篇文章为基础的。这个算法的一个特点是它为每一个像素选择一个合适数目的高斯分布。这样就会对由于亮度等发生变化引起的场景变化产生更好的适应。
官方文档: https://docs.opencv.org/3.1.0/d7/d7b/classcv_1_1BackgroundSubtractorMOG2.html#details

2. OpenCV实现结构

BackgroundSubtractorMOG2在OpenCV中的继承关系如下:

3. 几个重要参数

history – Length of the history. 默认值500
varThreshold – Threshold on the squared Mahalanobis distance to decide whether it is well described by the background model (see Cthr??). This parameter does not affect the background update. A typical value could be 4 sigma, that is,varThreshold=4*4=16;
bShadowDetection – Parameter defining whether shadow detection should be enabled (true or false).

4. 示例1

参考: https://www.programcreek.com/python/example/89404/cv2.createBackgroundSubtractorMOG2
https://www.youtube.com/watch?v=8-3vl71TjDs
简单使用,代码如下:

import cv2
import numpy as np
cap = cv2.VideoCapture(0)
fgbg = cv2. createBackgroundSubtractorMOG2()
while True:
    ret, frame = cap.read()
    fgmask = fgbg.apply(frame)
    cv2.imshow('original', frame)
    cv2.imshow('fg', fgmask)
    k = cv2.waitKey(30) & 0xff
    if k == 27:
        break
cap.release()
cv2.destroyAllWindows()

结果对比:

def camera_detect(self, device=0, func=None): self.camera = cv2.VideoCapture(device) self.width = int(self.camera.get(cv2.CAP_PROP_FRAME_WIDTH)) self.height = int(self.camera.get(cv2.CAP_PROP_FRAME_HEIGHT)) if not self.camera.isOpened(): print("Could not open camera") sys.exit() history = 10 # 20 # 训练帧数 bs = cv2.createBackgroundSubtractorKNN(detectShadows=True) # 背景减除器,设置阴影检测 #bs = cv2.createBackgroundSubtractorKNN(detectShadows=True) bs.setHistory(history) frames = 0 while True: res, frame = self.camera.read() if not res: break fg_mask = bs.apply(frame) # 获取 foreground mask if frames < history: frames += 1 continue # 对原始帧进行膨胀去噪 th = cv2.threshold(fg_mask.copy(), 244, 255, cv2.THRESH_BINARY)[1] th = cv2.erode(th, cv2.getStructuringElement( cv2.MORPH_ELLIPSE, (3, 3)), iterations=2) dilated = cv2.dilate(th, cv2.getStructuringElement( cv2.MORPH_ELLIPSE, (8, 3)), iterations=2) # 获取所有检测框 image, contours, hier = cv2.findContours( dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if len(contours) != 0: # find the biggest area # c = min(contours, key=cv2.contourArea) c = max(contours, key=cv2.contourArea) # shrink area rect = cv2.minAreaRect(c) box = cv2.boxPoints(rect) # get center point x = int(sum([point[0] for point in box])/4) y = int(sum([point[1] for point in box])/4) # convert all coordinates floating point values to int box = np.int0(box) # draw a red 'nghien' rectangle cv2.drawContours(frame, [box], 0, (0, 255, 0), 2) # run comstomer function if func != None: func({"info": {"width": self.width, "height": self.height}, "center_point": (x, y), "box": box}) else: print("the center point is: ({x}, {y})".format(x=x, y=y)) cv2.imshow("detection", frame) cv2.imshow("back", dilated) if cv2.waitKey(110) & 0xff == 27: break def screen_detect(self, record_box_size=600): record_box_size = record_box_size // 2 history = 10 # 训练帧数 bs = cv2.createBackgroundSubtractorKNN( detectShadows=True) # 背景减除器,设置阴影检测 bs.setHistory(history) frames = 0 while True: pos = pyautogui.position() mouse_x = pos[0] mouse_y = pos[1] left_top_x = mouse_x - record_box_size left_top_y = mouse_y - record_box_size right_bottom_x = mouse_x + record_box_size right_bottom_y = mouse_y + record_box_size frame = np.array(ImageGrab.grab( bbox=(left_top_x, left_top_y, right_bottom_x, right_bottom_y))) frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) fg_mask = bs.apply(frame) # 获取 foreground mask if frames < history: frames += 1 continue # 对原始帧进行膨胀去噪 th = cv2.threshold(fg_mask.copy(), 244, 255, cv2.THRESH_BINARY)[1] th = cv2.erode(th, cv2.getStructuringElement( cv2.MORPH_ELLIPSE, (3, 3)), iterations=2) dilated = cv2.dilate(th, cv2.getStructuringElement( cv2.MORPH_ELLIPSE, (8, 3)), iterations=2) # 获取所有检测框 image, contours, hier = cv2.findContours( dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if len(contours) != 0: # find the biggest area c = max(contours, key=cv2.contourArea) # shrink area rect = cv2.minAreaRect(c) box = cv2.boxPoints(rect) # get center point x = int(sum([point[0] for point in box])/4) y = int(sum([point[1] for point in box])/4) x = left_top_x + x y = left_top_y + y print("center point: ({x}, {y})".format(x=x, y=y)) #pyautogui.moveTo(x, y) # convert all coordinates floating point values to int box = np.int0(box) # draw a red 'nghien' rectangle cv2.drawContours(frame, [box], 0, (0, 255, 0), 2) cv2.imshow("detection", frame) # cv2.imshow("back", dilated) if cv2.waitKey(110) & 0xff == 27: break def func(return_values): camera_info = return_values["info"] width = camera_info["width"] half_width = width / 2 middle_width = 0.3 * width first_line = half_width - middle_width/2 second_line = half_width + middle_width/2 x = return_values["center_point"][0] if x < first_line: print("left") elif first_line < x < second_line: print("middle") elif x > second_line: print("right") if __name__ == '__main__': detector = MovingDetector() detector.camera_detect(device=0, func=func)