Skip to content

Instantly share code, notes, and snippets.

Last active October 15, 2023 20:56
  • Star 18 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
Star You must be signed in to star a gist
What would you like to do?
A simple example of using the Raspberry Pi Camera Module and python picamera for motion detection
import picamera
import cv2
import io
import numpy as np
import imutils
camera = picamera.PiCamera()
# Motion detection sensitivity
min_area = 100
def handle_new_frame(frame, past_frame, min_area):
(h, w) = frame.shape[:2]
r = 500 / float(w)
dim = (500, int(h * r))
frame = cv2.resize(frame, dim, cv2.INTER_AREA) # We resize the frame
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # We apply a black & white filter
gray = cv2.GaussianBlur(gray, (21, 21), 0) # Then we blur the picture
# if the first frame is None, initialize it because there is no frame for comparing the current one with a previous one
if past_frame is None:
past_frame = gray
return past_frame
# check if past_frame and current have the same sizes
(h_past_frame, w_past_frame) = past_frame.shape[:2]
(h_current_frame, w_current_frame) = gray.shape[:2]
if h_past_frame != h_current_frame or w_past_frame != w_current_frame: # This shouldnt occur but this is error handling
print('Past frame and current frame do not have the same sizes {0} {1} {2} {3}'.format(h_past_frame, w_past_frame, h_current_frame, w_current_frame))
# compute the absolute difference between the current frame and first frame
frame_detla = cv2.absdiff(past_frame, gray)
# then apply a threshold to remove camera motion and other false positives (like light changes)
thresh = cv2.threshold(frame_detla, 50, 255, cv2.THRESH_BINARY)[1]
# dilate the thresholded image to fill in holes, then find contours on thresholded image
thresh = cv2.dilate(thresh, None, iterations=2)
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]
# loop over the contours
for c in cnts:
# if the contour is too small, ignore it
if cv2.contourArea(c) < min_area:
print("Motion detected!")
if __name__ == '__main__':
camera.resolution = (640, 480)
past_frame = None
print("Starting motion detection")
while True:
stream = io.BytesIO()
camera.capture(stream, format='jpeg', use_video_port=False)
data = np.fromstring(stream.getvalue(), dtype=np.uint8)
frame = cv2.imdecode(data, 1)
if frame is not None:
past_frame = handle_new_frame(frame, past_frame, min_area)
print("No more frame")
Copy link

I sound like a total noob but where are the captured pictured stored and how do I run this script on my raspberry pi

Copy link

@theawsomeboss1102 this script just detects motion and prints to the console if it does indeed detect something. It does not save video or pictura of motion happening.

I suggest learning python and read the PiCamera docs if you need to tinker with this script.

Copy link

bluejakester commented Jul 20, 2018

Thank you for writing and sharing this! I've been trying unsuccessfully to modify "motion" and other programs to take a night vision image with "raspistill" and my parms. With your code the motion detect is there and working, making it simple to add my specific image capture requirements.

Copy link

Code Error Founded

You left out double quotation marks in 42 line. print "Scanning for Motion threshold=%i sensitivity=%i... % (threshold, sensitivity)

print "Scanning for Motion threshold=%i sensitivity=%i..." % (threshold, sensitivity)

Copy link

cooc1501 commented Jan 5, 2019

getting a syntax error at line 25, any idea what's causing that?

Copy link

mrcolo commented Feb 7, 2019

same syntax error, line 25..

Copy link

If you are having error on line 25, try to run the script with python 2.7..

Copy link

pabe40 commented Apr 8, 2019

 Line38       data2 = data1 . Shouldn't be data1 = data2 to get a new offset and not always comparing against the initial image in data1?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment