Chapter 10: Movement Detection With Background

a. The average method

I Have created this method taking as a fact that we could compute the number of pixels that have changed between to frames. To do movement detection the basic idea is to query a frame then query another and compare them two to find the difference. So this method works as follow:

  1. A first frame is taken. All the following frames are compared with the previous one using the Absdiff function
  2. The result is an image we more the two pixel difference is high more the pixel is white
  3. Then multiples operations are applied to reduce the noise and refine the moving objects
    1. Smooth: Intent to delete the noise in the image
    2. MorphologyEx: OPEN and then CLOSE to get more smooth shapes
  4. To finish a threshold is applied so that we get a nice shapes of moving object in black
  5. Then to decide either something has moved or not, a threshold is set (by default 5%). So if more than 5% of pixels are black and so have changed a message is triggered
  6. To calculate the percentage of black pixels we have to iterate the entire matrix, count the number of black pixels and calculate the percentage with the total number of pixels
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import cv2.cv as cv

capture=cv.CaptureFromCAM(0)

frame1 = cv.QueryFrame(capture)
frame1gray = cv.CreateMat(frame1.height, frame1.width, cv.CV_8U)
cv.CvtColor(frame1, frame1gray, cv.CV_RGB2GRAY)

res = cv.CreateMat(frame1.height, frame1.width, cv.CV_8U)

frame2gray = cv.CreateMat(frame1.height, frame1.width, cv.CV_8U)

w= frame2gray.width
h= frame2gray.height
nb_pixels = frame2gray.width * frame2gray.height

while True:
    frame2 = cv.QueryFrame(capture)
    cv.CvtColor(frame2, frame2gray, cv.CV_RGB2GRAY)

    cv.AbsDiff(frame1gray, frame2gray, res)
    cv.ShowImage("After AbsDiff", res)

    cv.Smooth(res, res, cv.CV_BLUR, 5,5)
    element = cv.CreateStructuringElementEx(5*2+1, 5*2+1, 5, 5,  cv.CV_SHAPE_RECT)
    cv.MorphologyEx(res, res, None, None, cv.CV_MOP_OPEN)
    cv.MorphologyEx(res, res, None, None, cv.CV_MOP_CLOSE)
    cv.Threshold(res, res, 10, 255, cv.CV_THRESH_BINARY_INV)

    cv.ShowImage("Image", frame2)
    cv.ShowImage("Res", res)

    #-----------
    nb=0
    for y in range(h):
        for x in range(w):
            if res[y,x] == 0.0:
                nb += 1
    avg = (nb*100.0)/nb_pixels
    #print "Average: ",avg, "%\r",
    if avg >= 5:
        print "Something is moving !"
    #-----------


    cv.Copy(frame2gray, frame1gray)
    c=cv.WaitKey(1)
    if c==27: #Break if user enters 'Esc'.
        break

After Absdiff:

After treatment:

b. Adaptative method

The second method inspired from an OpenCV book is a prety eficient method that learn the background overtime. It means that if an object come in the scene it is firstly considered as a foreground element. And become a background element overtime. Basically background frames are acumulate into an image that constitute the background. The example below use a video as input but you can switch it to your webcam.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import cv2.cv as cv

capture = cv.CaptureFromFile('img/myvideo.avi')
nbFrames = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_COUNT))
fps = cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FPS)
wait = int(1/fps * 1000/1)
width = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH))
height = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT))

gray = cv.CreateImage((width,height), cv.IPL_DEPTH_8U, 1)

background = cv.CreateMat(height, width, cv.CV_32F)
backImage = cv.CreateImage((width,height), cv.IPL_DEPTH_8U, 1)
foreground = cv.CreateImage((width,height), cv.IPL_DEPTH_8U, 1)
output = cv.CreateImage((width,height), 8, 1)

begin = True
threshold = 10

for f in xrange( nbFrames ):
    frame = cv.QueryFrame( capture )

    cv.CvtColor(frame, gray, cv.CV_BGR2GRAY)

    if begin:
        cv.Convert(gray, background) #Convert gray into background format
        begin = False

    cv.Convert(background, backImage) #convert existing background to backImage

    cv.AbsDiff(backImage, gray, foreground) #Absdiff to get differences

    cv.Threshold(foreground, output, threshold, 255, cv.CV_THRESH_BINARY_INV)

    cv.Acc(foreground, background,output) #Accumulate to background

    cv.ShowImage("Output", output)
    cv.ShowImage("Gray", gray)
    c = cv.WaitKey(wait)
    if c==27: #Break if user enters 'Esc'.
        break

The video used is the same than the previous chapter one (with the small piece of plastic crossing the screen).

<<Tracking Moving Objects | Home | Officials OpenCV Python Samples>>