Motion Detector Using BackgroundSubtractorKNN
import cv2
_IMAGE_SIZE = (512 , 512 )
_BACKGROUND_SUBTRACTOR_HISTORY = 100
_BACKGROUND_SUBTRACTOR_DISTANCE_THRESHOLD = 400
_BACKGROUND_DETECT_SHADOWS = True
_BLUR_KERNEL_SIZE = (5 , 5 )
_BINARY_THRESHOLD = 5
_ERODE_KERNEL_SIZE = (3 , 3 )
_ERODE_ITERATIONS = 1
_DILATE_KERNEL_SIZE = (5 , 5 )
_DILATE_ITERATIONS = 1
class MotionDetector :
def __init__ (self , motion_threshold = 0.001 ):
self .motion_threshold = motion_threshold
self ._background_subtractor = cv2 .createBackgroundSubtractorKNN (
history = _BACKGROUND_SUBTRACTOR_HISTORY ,
dist2Threshold = _BACKGROUND_SUBTRACTOR_DISTANCE_THRESHOLD ,
detectShadows = _BACKGROUND_DETECT_SHADOWS )
def detect (self , image ):
image = cv2 .resize (src = image , dsize = _IMAGE_SIZE )
image = cv2 .GaussianBlur (src = image , ksize = _BLUR_KERNEL_SIZE , sigmaX = 0 )
foreground = self ._background_subtractor .apply (image = image )
_ , foreground = cv2 .threshold (src = foreground , thresh = _BINARY_THRESHOLD , maxval = 255 , type = cv2 .THRESH_BINARY )
kernel = cv2 .getStructuringElement (shape = cv2 .MORPH_RECT , ksize = _ERODE_KERNEL_SIZE )
foreground = cv2 .erode (src = foreground , kernel = kernel , iterations = _ERODE_ITERATIONS )
kernel = cv2 .getStructuringElement (shape = cv2 .MORPH_RECT , ksize = _DILATE_KERNEL_SIZE )
foreground = cv2 .dilate (src = foreground , kernel = kernel , iterations = _DILATE_ITERATIONS )
contours , _ = cv2 .findContours (foreground , cv2 .RETR_EXTERNAL , cv2 .CHAIN_APPROX_SIMPLE )
max_area = 0
for contour in contours :
area = cv2 .contourArea (contour )
if area > max_area :
max_area = area
image_area = _IMAGE_SIZE [0 ] * _IMAGE_SIZE [1 ]
motion_ratio = max_area / image_area
if motion_ratio >= self .motion_threshold :
return True
else :
return False
Motion Detector Using absdiff
import cv2
_IMAGE_SIZE = (512 , 512 )
_BLUR_KERNEL_SIZE = (21 , 21 )
_BINARY_THRESHOLD = 5
_MORPHOLOGY_KERNEL_SIZE = (5 , 5 )
_MORPHOLOGY_ITERATIONS = 1
class MotionDetector :
def __init__ (self , motion_threshold = 0.001 ):
self .motion_threshold = motion_threshold
self ._previous_image = None
def detect (self , image ):
image = cv2 .resize (src = image , dsize = _IMAGE_SIZE )
image = cv2 .cvtColor (image , cv2 .COLOR_BGR2GRAY )
image = cv2 .GaussianBlur (src = image , ksize = _BLUR_KERNEL_SIZE , sigmaX = 0 )
if self ._previous_image is None :
self ._previous_image = image
return False
foreground = cv2 .absdiff (self ._previous_image , image )
_ , foreground = cv2 .threshold (src = foreground , thresh = _BINARY_THRESHOLD , maxval = 255 , type = cv2 .THRESH_BINARY )
kernel = cv2 .getStructuringElement (shape = cv2 .MORPH_RECT , ksize = _MORPHOLOGY_KERNEL_SIZE )
foreground = cv2 .morphologyEx (src = foreground , op = cv2 .MORPH_DILATE , kernel = kernel ,
iterations = _MORPHOLOGY_ITERATIONS )
contours , _ = cv2 .findContours (foreground , cv2 .RETR_EXTERNAL , cv2 .CHAIN_APPROX_SIMPLE )
max_area = 0
for contour in contours :
area = cv2 .contourArea (contour )
if area > max_area :
max_area = area
image_area = _IMAGE_SIZE [0 ] * _IMAGE_SIZE [1 ]
motion_ratio = max_area / image_area
self ._previous_image = image
if motion_ratio >= self .motion_threshold :
return True
else :
return False
import cv2
from motion_detector import MotionDetector
motion_detector = MotionDetector (motion_threshold = 0.001 )
video_capture = cv2 .VideoCapture ('test.mp4' )
while True :
success , frame = video_capture .read ()
if not success :
break
motion_detected = motion_detector .detect (frame )
print ('Motion:' , motion_detected )
cv2 .imshow ('Video' , frame )
if cv2 .waitKey (1 ) == 27 :
break
video_capture .release ()