Video based Motion Detection in Python with OpenCV
Demo
I added 30 seconds buffer before the scipt start recording so we can see the green color indicates the detected movements.
What you need
- A Webcam
- Python and pip
Requirements.txt
1 | opencv-python |
Goal
To implement a security camera auto record videos when some thing moves in the view port.
Source code
The original implementation was in Python 2.x with OpenCV 3.x
I fork it to Python 3.x and make it compatible with OpenCV 4.x
The
MotionDetectorContours.py
andMotionDetector.py
results the same in the original implementation. But they give different result in my implementation, I guess it is because I skipedcv.Erode()
inMotionDetectorContours.py
.
The original implementation
There are two implementation according to the developer.
Simple way
- Receive frames and send to process in
run()
processImage()
calculate difference of pixels in frames- If number of different pixels exceed the threshold,
somethingHasMoved()
returnTrue
run()
enable recording ifsomethingHasMoved()
returnTrue
Smart way
- Receive frames and send to process in
run()
processImage()
calculate difference of areas in frames withcv2.findContours()
- If change of area in comparing to total area exceed the threshold,
somethingHasMoved()
returnTrue
run()
enable recording ifsomethingHasMoved()
returnTrue
Our implementation
Our implementation will be based on MotionDetectorContours.py
. It did better job for me and it can catch my eye blinking.
Import OpenCV for image processing, Numpy for replacing cv2.CreateImage()
, datetime and tmie for showing video recording time.
1 | import cv2 as cv |
Define a class for image processing and maintain the loop of reading frames.
1 | class MotionDetectorAdaptative(): |
The initializatoin:
1 | def __init__(self,threshold=25, doRecord=True, showWindows=True): |
run()
will maintain the loop to:
- read frame
- pass to
processImage()
- check if anything moved in
somethingHasMoved()
,isRecording = True
if things moved - if
isRecording == True
a video recorder will be activated - draw area of moved/changed to frame and display it on screen
- repeat the steps if
Esc
was not pressed
1 | def run(self): |
Find the change between frames and do simple feature extraction, result saved to self.gray_frame
.
1 | def processImage(self, curframe): |
Find the area of changes and compare to threshold over the whole area:
1 | def somethingHasMoved(self): |
If user change threshold during runtime, onChange()
method in the class will be triggered:
1 | def onChange(self, val): #callback when the user change the detection threshold |
Declare a video recorder writes frame to video file:
1 | def initRecorder(self): #Create the recorder |
Let’s try it.
1 | if __name__=="__main__": |
Improvements
There is a problem the video only record for 10 seconds. Base on MotionDetectorContours.py modify its condition to end recording:
1 | if instant >= self.trigger_time +10 and not self.somethingHasMoved(): #Record until move stop 10 seconds |
We can add an Email notification in this. You may refer to the tutorial sending Email notification for network usage report. And we can then combine it with Raspberry Pi to build a security camera.
You will need these things for a Raspberry Pi security camera:
If you ask, I used a wide angle camera
Sixfab has a tutorial about Raspberry Pi Security System with Sixfab 3G, 4G/LTE Base Shield. It seem to use a motion sensor to detect moment in the area and activate camera when sensor detect movement, it then send a frame to a email specified in the Python script.
I didn’t find the hardware list of their design, but the Python source code is here.
I think using a motion sensor is a good idea, Docker Pi Series of Sensor Hub seem to be a good option, considering to have it in my production environment.