Motion Detection using OpenCV & Python
Lately, CCTV security systems have multiple algorithms running to ensure safety, such as Face-Recognition, Object Detection, Theft Detection, Fire Alert, etc. We implement many algorithms on top of motion detection because there is no point in running all those processes on idle frames. In this article, we’ll discuss implementing motion-detection-based video saving.
Dependencies
Install OpenCV:
pip install opencv-python
Basic Motion Detection
In computer vision, motion is considered as a change in surroundings. To calculate this transition, a background image is required for comparison. Below is the step-by-step process:
1. Converting the Image to GrayScale
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (21, 21), 0)
2. Saving the First Frame
if first_frame is None:
first_frame = gray
continue
Subsequent frames are compared with the saved first frame to observe differences. After calculating the difference, thresholds are applied to convert it into a black-and-white image.
3. Detecting Motion
# Calculate difference to detect motion
delta_frame = cv2.absdiff(first_frame, gray)
# Apply threshold and convert to black-and-white image
thresh_delta = cv2.threshold(delta_frame, 30, 255, cv2.THRESH_BINARY)
thresh_delta = cv2.dilate(thresh_delta, None, iterations=0)
# Find contours on the white portion (made by the threshold)
cnts, _ = cv2.findContours(thresh_delta.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
The contours in this black-and-white image are used to create bounding boxes around detected motion.
Perks of Using Motion Detection
- Avoids saving idle footage and reduces workload for other algorithms.
- Requires fewer computations and is suitable for live implementations.
Obstacles & Solutions
1. Static First Frame
The naïve approach saves the first frame at the start of execution for all comparisons. This can fail due to:
- Changing lighting conditions.
- Weather changes.
- Blocked camera at execution time.
Solution: Regularly update the saved frame during idle periods.
# Number of idle frames before updating the saved frame
FRAMES_TO_PERSIST = 1000
# Increment delay counter for every idle frame
delay_counter += 1
# Update the saved first frame
if delay_counter > FRAMES_TO_PERSIST:
delay_counter = 0
first_frame = next_frame
Reset delay_counter
when motion is detected.
2. Noise from Small Objects
Minute objects (e.g., insects) or minor motions can trigger unwanted detections.
Solution: Set a threshold over the area of detected motion.
# Minimum boxed area (in pixels) for a detected motion to count as actual motion
MIN_SIZE_FOR_MOVEMENT = 2000
# Check if the area is big enough to be considered as motion
if cv2.contourArea(c) > MIN_SIZE_FOR_MOVEMENT:
# Your code here
Benchmarks on Various Platforms
Performance was tested on a video (30 FPS, 1280x720 resolution):
Platform | Specifications | FPS Achieved |
---|---|---|
Raspberry Pi 2 | 1.5 GHz processor, 1 GB RAM, No GPU | 8.08 |
Jetson Nano | Quad-Core ARM 1.43 GHz processor, 2 GB RAM, Nvidia GPU | 33 |
PC | i7 8th Gen processor, 16 GB RAM, GTX 1060 GPU | 37 |
Potential Applications
1. Smart Bell
Automatically triggers a bell and sends a snapshot if someone is standing at your doorstep.
2. Potential Threat Alert
Alerts you if someone lingers in front of your house for an unusually long duration.
Conclusion
This article demonstrated a basic yet essential algorithm for efficiently running other algorithms by reducing idle-frame processing. While functional in its current form, further modifications can make this motion detection algorithm more robust.
You have reached the end of the blog. Thanks for reading!
For any queries or issues, feel free to reach out to me via the contact page.