It is surprisingly easy to make a small Python script that takes a webcam or any other video and detects when something is moving there. It uses the OpenCV library.
1. Difference between frames
Compares two frames and displays only what are change. The rest is black.
import cv2
# Select camera. Usualy 0, or 1 and so on
cam = cv2.VideoCapture(0)
try:
while cam.isOpened():
ret, frame1 = cam.read()
ret, frame2 = cam.read()
diff = cv2.absdiff(frame1, frame2)
# To exit press 'q'
if cv2.waitKey(10) == ord('q'):
break
# Display
cv2.imshow('Erinevus', diff)
except:
print("Error.")

2. Binary image
Turn it into binary: only black and white. To make it easy to find contours.
import cv2
# Select camera. Usualy 0, or 1 and so on
cam = cv2.VideoCapture(0)
try:
while cam.isOpened():
ret, frame1 = cam.read()
ret, frame2 = cam.read()
# Compare frames
diff = cv2.absdiff(frame1, frame2)
# Convert diff to grayscale image
gray = cv2.cvtColor(diff, cv2.COLOR_RGB2GRAY)
# Blur gray image
blur = cv2.GaussianBlur(gray, (5, 5), 0)
# Converts to Binary images. Only black and white colour.
_, thresh = cv2.threshold(blur, 20, 255, cv2.THRESH_BINARY)
# Expand moving image part
dilated = cv2.dilate(thresh, None, iterations=3)
# To exit press 'q'
if cv2.waitKey(10) == ord('q'):
break
# Display
cv2.imshow('Erinevus', dilated)
except:
print("Error.")

3. Contours
Now displays founded contours over the original image.
import cv2
# Select camera. Usualy 0, or 1 and so on
cam = cv2.VideoCapture(0)
try:
while cam.isOpened():
ret, frame1 = cam.read()
ret, frame2 = cam.read()
# Compare frames
diff = cv2.absdiff(frame1, frame2)
# Convert diff to grayscale image
gray = cv2.cvtColor(diff, cv2.COLOR_RGB2GRAY)
# Blur gray image
blur = cv2.GaussianBlur(gray, (5, 5), 0)
# Converts to Binary images. Only black and white colour.
_, thresh = cv2.threshold(blur, 20, 255, cv2.THRESH_BINARY)
# Expand moving image part
dilated = cv2.dilate(thresh, None, iterations=3)
# Find moving part contures
contours, _ = cv2.findContours(dilated, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# Draw contours
cv2.drawContours(frame1, contours, -1, (0, 255, 0), 2) #
# To exit press 'q'
if cv2.waitKey(10) == ord('q'):
break
# Display
cv2.imshow('Erinevus', frame1)
except:
print("Error.")

Rectangle
When we know where the contours are. Where are the coordinates of the beginning on the x and y axes. We can draw rectangles around these regions.
import cv2
# Select camera. Usualy 0, or 1 and so on
cam = cv2.VideoCapture(0)
try:
while cam.isOpened():
ret, frame1 = cam.read()
ret, frame2 = cam.read()
# Compare frames
diff = cv2.absdiff(frame1, frame2)
# Convert diff to grayscale image
gray = cv2.cvtColor(diff, cv2.COLOR_RGB2GRAY)
# Blur gray image
blur = cv2.GaussianBlur(gray, (5, 5), 0)
# Converts to Binary images. Only black and white colour.
_, thresh = cv2.threshold(blur, 20, 255, cv2.THRESH_BINARY)
# Expand moving image part
dilated = cv2.dilate(thresh, None, iterations=3)
# Find moving part contures
contours, _ = cv2.findContours(dilated, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
# Select movement size area.
# If contour is smaller it will be ignored.
if cv2.contourArea(c) < 2000:
continue
# Contour position and size
x, y, w, h = cv2.boundingRect(c)
# Draw rectangle
cv2.rectangle(frame1, (x, y), (x+w, y+h), (0, 255, 0), 2)
# To something
# To exit press 'q'
if cv2.waitKey(10) == ord('q'):
break
# Display
cv2.imshow('Liikumine', frame1)
except:
print("Error.")
