1 '''
2 Created on Oct 22, 2010
3 @author: Stephen O'Hara
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 import scipy as sp
38 import pyvision as pv
39 import math
40 import cv
41
42
43
44 BG_SUBTRACT_FD = "BG_SUBTRACT_FD"
45 BG_SUBTRACT_MCFD = "BG_SUBTRACT_MCFD"
46 BG_SUBTRACT_MF = "BG_SUBTRACT_MF"
47 BG_SUBTRACT_AMF = "BG_SUBTRACT_AMF"
48
49
51 - def __init__(self, imageBuffer, thresh=20, soft_thresh=False):
52 '''
53 @param imageBuffer: An ImageBuffer object that has already been filled
54 with the appropriate number of images. (Provide a full buffer...so a few
55 frames of initialization will be required in most cases to fill up a
56 newly created buffer.)
57 @param thresh: A noise threshold to remove very small differences.
58 '''
59 self._imageBuffer = imageBuffer
60 self._threshold = thresh
61 self._softThreshold = soft_thresh
62
64 '''
65 This private method should be overridden by a concrete background subtraction
66 class to yield a difference image from the background model.
67 '''
68 raise NotImplemented
69
71 '''
72 @return: A mask image indicating which pixels are considered foreground.
73 Depending on whether soft-thresholding is used, this may be a binary image
74 with values of [0 or 255], or image of weights [0.0-255.0], which will
75 have to be divided by 255 to get weights [0.0-1.0].
76 @note: One may wish to perform additional morphological operations
77 on the foreground mask prior to use.
78 '''
79 diff = self._computeBGDiff()
80 if self._softThreshold:
81 mask = 1 - (math.e)**(-(1.0*diff)/self._threshold)
82
83 else:
84 mask = (sp.absolute(diff) > self._threshold)
85
86
87
88 return pv.Image(mask*255.0)
89
90
92 '''
93 This class is useful for simple N-frame differencing method of
94 background subtraction. If you have a stationary camera, this can
95 be a simple and effective way to isolate people/moving objects
96 from the background scene.
97
98 FrameDifferencer uses ImageBuffer for operation. Assume the buffer
99 size is 5. The output of the frame differencing operation will
100 be based on the middle image, the 3rd in the buffer. The output
101 is the intersection of the following two absolute differences:
102 abs(Middle-First) AND abs(Last-Middle).
103 '''
104
105 - def __init__(self, imageBuffer, thresh=20, soft_thresh = False):
107
109 prevImg = self._imageBuffer[0].asMatrix2D()
110 curImg = self._imageBuffer.getMiddle().asMatrix2D()
111 nextImg = self._imageBuffer[-1].asMatrix2D()
112
113 delta1 = sp.absolute(curImg - prevImg)
114 delta2 = sp.absolute(nextImg - curImg)
115
116
117
118 return sp.minimum(delta1, delta2)
119
121 '''
122 This class represents a more sophisticated frame differencing
123 algorithm that takes into account potential camera motion, and
124 applies a registration method to align subsequent images prior
125 to frame subtraction.
126 '''
127
128 - def __init__(self, imageBuffer, thresh=20, soft_thresh = False):
133
134
135
137 '''
138 Should be called after buffer is full to compute the optical flow
139 information on the buffered frames. Only needs to be called once,
140 prior to first call of _computeBGDiff(), because from then on,
141 the flow will be updated as new frames are added to the buffer.
142 '''
143 for i in range( len(self._imageBuffer)):
144 self._flow.update( self._imageBuffer[i])
145
146
148 '''
149 @return: A handle to the pv.OpticalFlow object being used by this object.
150 '''
151 return self._flow
152
154 '''
155 This is an optional method that allows the user to provide an
156 optical flow object (pv.OpticalFlow) with non-default settings.
157 @param OF_Object: The optical flow object desired for use in computing the
158 motion compensated frame difference.
159 '''
160 self._flow = OF_Object
161
163 self._flow.update( self._imageBuffer.getLast() )
164
165 n = len(self._imageBuffer)
166 prev_im = self._imageBuffer[0]
167 forward = None
168 for i in range(0,n/2):
169 if forward == None:
170 forward = self._imageBuffer[i].to_next
171 else:
172 forward = forward * self._imageBuffer[i].to_next
173
174 w,h = size = prev_im.size
175 mask = cv.CreateImage(size,cv.IPL_DEPTH_8U,1)
176 cv.Set(mask,0)
177 interior = cv.GetSubRect(mask, pv.Rect(2,2,w-4,h-4).asOpenCV())
178 cv.Set(interior,255)
179 mask = pv.Image(mask)
180
181 prev_im = forward(prev_im)
182 prev_mask = forward(mask)
183
184
185 next_im = self._imageBuffer[n-1]
186 back = None
187 for i in range(n-1,n/2,-1):
188 if back == None:
189 back = self._imageBuffer[i].to_prev
190 else:
191 back = back * self._imageBuffer[i].to_prev
192
193 next_im = back(next_im)
194 next_mask = back(mask)
195
196 curr_im = self._imageBuffer[n/2]
197
198
199 prevImg = prev_im.asMatrix2D()
200 curImg = curr_im.asMatrix2D()
201 nextImg = next_im.asMatrix2D()
202 prevMask = prev_mask.asMatrix2D()
203 nextMask = next_mask.asMatrix2D()
204
205
206 delta1 = sp.absolute(curImg - prevImg)
207 delta2 = sp.absolute(nextImg - curImg)
208
209 delta1 = sp.minimum(delta1,prevMask)
210 delta2 = sp.minimum(delta2,nextMask)
211
212
213
214 return sp.minimum(delta1, delta2)
215
237
238
266