【问题标题】:Background subtraction in opencv2opencv2中的背景减法
【发布时间】:2012-04-02 12:46:30
【问题描述】:

我正在尝试通过删除静态(大部分)BG 元素来使用 opencv2 检测前景运动。我使用的方法是基于一系列图像的平均值 - 代表背景。然后计算高于和低于该平均值的一个标准差。将其用作检测前景运动的窗口。

据报道,这种机制适用于中等噪声环境,例如 BG 中挥动的树木。

所需的输出是可以在后续操作中使用的掩码,以尽量减少进一步的处理。具体来说,我将在该区域内使用光流检测。

cv2 使这变得更容易,代码更易于阅读和理解。感谢 cv2 和 numpy。

但我在进行正确的 FG 检测时遇到了困难。

理想情况下,我还想侵蚀/扩大 BG 均值以消除 1 个像素的噪声。

代码全部在一起,因此在开始 FG 检测之前,您有许多帧 (BGsample) 来收集 BG 数据。唯一的依赖是 opencv2 (> 2.3.1 ) 和 numpy (应该包含在 > opencv 2.3.1 中)

import cv2
import numpy as np


if __name__ == '__main__': 
    cap = cv2.VideoCapture(0) # webcam
    cv2.namedWindow("input")
    cv2.namedWindow("sig2")
    cv2.namedWindow("detect")
    BGsample = 20 # number of frames to gather BG samples from at start of capture
    success, img = cap.read()
    width = cap.get(3)
    height = cap.get(4)
    # can use img.shape(:-1) # cut off extra channels
    if success:
        acc = np.zeros((height, width), np.float32) # 32 bit accumulator
        sqacc = np.zeros((height, width), np.float32) # 32 bit accumulator
        for i in range(20): a = cap.read() # dummy to warm up sensor
        # gather BG samples
        for i in range(BGsample):
            success, img = cap.read()
            frame = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            cv2.accumulate(frame, acc)
            cv2.accumulateSquare(frame, sqacc)
        #
        M = acc/float(BGsample)
        sqaccM = sqacc/float(BGsample)
        M2 = M*M
        sig2 = sqaccM-M2
        # have BG samples now
        # start FG detection
        key = -1
        while(key < 0):
            success, img = cap.read()
            frame = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            #Ideally we create a mask for future use that is B/W for FG objects
            # (using erode or dilate to remove noise)
            # this isn't quite right
            level = M+sig2-frame
            grey = cv2.morphologyEx(level, cv2.MORPH_DILATE,
                                    cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3)), iterations=2)
            cv2.imshow("input", frame)
            cv2.imshow("sig2", sig2/60)
            cv2.imshow("detect", grey/20)
            key = cv2.waitKey(1)
    cv2.destroyAllWindows()

【问题讨论】:

  • 看起来它与 thsi c++ 答案有关:stackoverflow.com/questions/7958786/…
  • 很难理解你在这里问什么。您是否试图将图像的背景与前景分开?如果是这种情况,请使其更清晰:“我想将图像的背景与其前景分开。为此,我将值在 1 std.dev 之内的每个像素标记为来自图像的平均灰度为 bakground 。”
  • 我已经按照您的建议重新提出了这个问题,谢谢。

标签: image-processing opencv background-subtraction


【解决方案1】:

我认为您不需要手动计算平均值和标准差,而是使用cv2.meanStdDev。在下面的代码中,我使用的是从

计算的平均背景矩阵
M = acc/float(BGsample) 

所以,现在我们可以计算平均背景图像的均值和标准差,最后使用inRange 拉出您想要的范围(即均值 +/- 1 标准差)。

(mu, sigma) = cv2.meanStdDev(M)
fg = cv2.inRange(M, (mu[0] - sigma[0]), (mu[0] + sigma[0]))
# proceed with morphological clean-up here...

希望有帮助!

【讨论】:

  • 唉 cv2.meanStdDev 计算平均值和 sigma 的单个标量值 ... print type(mu), type(sigma), mu.shape, sigma.shape ... (1, 1) (1, 1)
  • cv2.inRange 是个好消息。出于某种原因,我认为他们会将其留在 cv 中,但文档仍然有些混乱......
【解决方案2】:

到目前为止我最好的猜测。使用 detectmin, max 将 fp sigma 强制转换为灰度以供 cv2.inRange 使用。 似乎工作正常,但希望更好……有效的 FG 数据中有很多漏洞。 我想它在 rgb 而不是灰度中会更好。 无法使用扩张或腐蚀来降低噪音。

有什么改进吗?

import cv2
import numpy as np


if __name__ == '__main__': 
    cap = cv2.VideoCapture(1)
    cv2.namedWindow("input")
    #cv2.namedWindow("sig2")
    cv2.namedWindow("detect")
    BGsample = 20 # number of frames to gather BG samples from at start of capture
    success, img = cap.read()
    width = cap.get(3)
    height = cap.get(4)
    if success:
        acc = np.zeros((height, width), np.float32) # 32 bit accumulator
        sqacc = np.zeros((height, width), np.float32) # 32 bit accumulator
        for i in range(20): a = cap.read() # dummy to warm up sensor
        # gather BG samples
        for i in range(BGsample):
            success, img = cap.read()
            frame = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            cv2.accumulate(frame, acc)
            cv2.accumulateSquare(frame, sqacc)
        #
        M = acc/float(BGsample)
        sqaccM = sqacc/float(BGsample)
        M2 = M*M
        sig2 = sqaccM-M2
        # have BG samples now
        # calculate upper and lower bounds of detection window around mean.
        # coerce into 8bit image space for cv2.inRange compare
        detectmin = cv2.convertScaleAbs(M-sig2)
        detectmax = cv2.convertScaleAbs(M+sig2)
        # start FG detection
        key = -1
        while(key < 0):
            success, img = cap.read()
            frame = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            level = cv2.inRange(frame, detectmin, detectmax)
            cv2.imshow("input", frame)
            #cv2.imshow("sig2", M/200)
            cv2.imshow("detect", level)
            key = cv2.waitKey(1)
    cv2.destroyAllWindows()

【讨论】:

    猜你喜欢
    • 2023-03-12
    • 2016-06-19
    • 1970-01-01
    • 2011-12-19
    • 1970-01-01
    • 1970-01-01
    • 2015-04-20
    相关资源
    最近更新 更多