Motion Detection using OpenCV & Python

09 December, 2020

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):

PlatformSpecificationsFPS Achieved
Raspberry Pi 21.5 GHz processor, 1 GB RAM, No GPU8.08
Jetson NanoQuad-Core ARM 1.43 GHz processor, 2 GB RAM, Nvidia GPU33
PCi7 8th Gen processor, 16 GB RAM, GTX 1060 GPU37

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.

Inspired by Trekhleb. All rights reserved.