#!/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)