Вычитание фона в opencv2 - PullRequest
       39

Вычитание фона в opencv2

2 голосов
/ 02 апреля 2012

Я пытаюсь обнаружить движение переднего плана, используя opencv2, удаляя статические (в основном) элементы BG. Метод, который я использую, основан на взятии среднего значения серии изображений, представляющих фон. Затем рассчитывается одно стандартное отклонение выше и ниже этого среднего. Используя это как окно, чтобы обнаружить движение переднего плана.

Этот механизм, по сообщениям, хорошо работает для умеренно шумных сред, таких как размахивание деревьев в BG.

Желаемый вывод - маска, которую можно использовать в последующей операции, чтобы минимизировать дальнейшую обработку. В частности, я собираюсь использовать оптическое обнаружение потока в этом регионе.

cv2 сделал это намного проще, а код намного проще для чтения и понимания. Спасибо cv2 и numpy.

Но у меня возникают трудности с правильным определением FG.

В идеале я также хочу стереть / расширить среднее значение BG, чтобы устранить шум в 1 пиксель.

Код все вместе, поэтому у вас есть несколько кадров в начале (BGsample), чтобы собрать данные BG перед началом обнаружения FG. единственными зависимостями являются 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()

Ответы [ 2 ]

1 голос
/ 02 апреля 2012

Я не думаю, что вам нужно вручную вычислять среднее значение и стандартное отклонение, вместо этого используйте 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...

Надеюсь, это поможет!

0 голосов
/ 03 апреля 2012

мое лучшее предположение на данный момент.Используя Detemin, Max, чтобы привести сигма fp в градации серого для использования 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()
...