-
Notifications
You must be signed in to change notification settings - Fork 0
/
motion_detection.py
162 lines (131 loc) · 7.15 KB
/
motion_detection.py
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#!/usr/bin/env python
#The MIT License (MIT)
#Copyright (c) 2016 Massimiliano Patacchiola
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
#MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
#CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
#SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import numpy as np
import cv2
import sys
class DiffMotionDetector:
"""Motion is detected through the difference between
the background (static) and the foregroung (dynamic).
This class calculated the absolute difference between two frames.
The first one is a static frame which represent the background
and the second is the image containing the moving object.
The resulting mask is passed to a threshold and cleaned from noise.
"""
def __init__(self):
"""Init the color detector object.
"""
self.background_gray = None
def setBackground(self, frame):
"""Set the BGR image used as template during the pixel selection
The template can be a spedific region of interest of the main
frame or a representative color scheme to identify. the template
is internally stored as an HSV image.
@param frame the template to use in the algorithm
"""
if(frame is None): return None
self.background_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
def getBackground(self):
"""Get the BGR image used as template during the pixel selection
The template can be a spedific region of interest of the main
frame or a representative color scheme to identify.
"""
if(self.background_gray is None):
return None
else:
return cv2.cvtColor(self.background_gray, cv2.COLOR_GRAY2BGR)
def returnMask(self, foreground_image, threshold=25):
"""Return the binary image after the detection process
@param foreground_image the frame to check
@param threshold the value used for filtering the pixels after the absdiff
"""
if(foreground_image is None):
return None
foreground_gray = cv2.cvtColor(foreground_image, cv2.COLOR_BGR2GRAY)
delta_image = cv2.absdiff(self.background_gray, foreground_gray)
threshold_image = cv2.threshold(delta_image, threshold, 255, cv2.THRESH_BINARY)[1]
return threshold_image
class MogMotionDetector:
"""Motion is detected through the Mixtures of Gaussian (MOG)
This class is the implementation of the article "An Improved
Adaptive Background Mixture Model for Realtime Tracking with
Shadow Detection" by KaewTraKulPong and Bowden (2008).
ABSTRACT: Real-time segmentation of moving regions in image
sequences is a fundamental step in many vision systems
including automated visual surveillance, human-machine
interface, and very low-bandwidth telecommunications. A
typical method is background subtraction. Many background
models have been introduced to deal with different problems.
One of the successful solutions to these problems is to use a
multi-colour background model per pixel proposed by Grimson
et al [1,2,3]. However, the method suffers from slow learning
at the beginning, especially in busy environments. In addition,
it can not distinguish between moving shadows and moving objects.
This paper presents a method which improves this adaptive
background mixture model. By reinvestigating the update equations,
we utilise different equations at different phases. This allows
our system learn faster and more accurately as well as adapt
effectively to changing environments. A shadow detection scheme
is also introduced in this paper. It is based on a computational
colour space that makes use of our background model. A comparison
has been made between the two algorithms. The results show the
speed of learning and the accuracy of the model using our update
algorithm over the Grimson et al tracker. When incorporate with
the shadow detection, our method results in far better segmentation
than that of Grimson et al.
"""
def __init__(self, history=10, numberMixtures=3, backgroundRatio=0.6, noise=20):
"""Init the color detector object.
@param history lenght of the history
@param numberMixtures The maximum number of Gaussian Mixture components allowed.
Each pixel in the scene is modelled by a mixture of K Gaussian distributions.
This value should be a small number from 3 to 5.
@param backgroundRation define a threshold which specifies if a component has to be included
into the foreground or not. It is the minimum fraction of the background model.
In other words, it is the minimum prior probability that the background is in the scene.
@param noise specifies the noise strenght
"""
self.BackgroundSubtractorMOG = cv2.BackgroundSubtractorMOG(history, numberMixtures, backgroundRatio, noise)
def returnMask(self, foreground_image):
"""Return the binary image after the detection process
@param foreground_image the frame to check
@param threshold the value used for filtering the pixels after the absdiff
"""
return self.BackgroundSubtractorMOG.apply(foreground_image)
class Mog2MotionDetector:
"""Motion is detected through the Imporved Mixtures of Gaussian (MOG)
This class is the implementation of the article "Improved Adaptive
Gaussian Mixture Model for Background Subtraction" by Zoran Zivkovic.
ABSTRACT: Background subtraction is a common computer vision task.
We analyze the usual pixel-level approach. We develop an efficient
adaptive algorithm using Gaussian mixture probability density.
Recursive equations are used to constantly update the parameters
and but also to simultaneously select the appropriate number of
components for each pixel.
"""
def __init__(self):
"""Init the color detector object.
"""
self.BackgroundSubtractorMOG2 = cv2.BackgroundSubtractorMOG2()
def returnMask(self, foreground_image):
"""Return the binary image after the detection process
@param foreground_image the frame to check
"""
#Since the MOG2 returns shadows with value 127 we have to
#filter these values in order to have a binary mask
img = self.BackgroundSubtractorMOG2.apply(foreground_image)
ret, thresh = cv2.threshold(img, 126, 255,cv2.THRESH_BINARY)
return thresh
def returnGreyscaleMask(self, foreground_image):
"""Return the greyscale image after the detection process
The MOG2 can return shadows. The pixels associated with
shadows have value 127. This mask is not a classic binary
mask since it incorporates the shadow pixels.
@param foreground_image the frame to check
"""
return self.BackgroundSubtractorMOG2.apply(foreground_image)