Leveraging computer vision to mitigate false-alarms in CCTV motion-detection with Python and OpenCV

The problem with motion detection

When a modern CCTV camera/NVR detects motion, it can save still frames of the image and, if configured to do so, will email those images to one or more addresses. This can lead to many false-alarms, however, which will often result in the recipient disregarding what could be, at any given moment, a very serious problem.

My solution so far

To that end, I’ve taken up the task of writing a Python script, utilizing OpenCV’s computer vision libraries, that will process and curate the images generated by an NVR. The script will determine if the generated images contain faces of people. If the images do not contain faces, then I won’t be sent an email alert. If the image does include a face, then I will indeed receive an email with that image attached. This should make alerts more useful, and result in fewer false-alarms so that we can avoid a boy-who-cried-wolf scenario.

The benefits of Python

Some NVRs and IP Cameras already feature facial-detection capabilities, but what if yours does not? This script runs independent of your CCTV equipment, providing modularity and saving you from hardware upgrade expenses. Given the nature of Python, this can be run from virtually any operating system you might be using.

Things I’d still like to add

  • Improve file-selection and saving
  • Implement batch processing
  • Add capability to detect facial profiles
  • Add capability to detect full body, lower body, and upper body
  • Add graphical user interface
Input Image
Output Image @ 1.01
Output Image @ 1.05
Output Image @ 1.10
Output Image @ 1.15
import numpy as np
import sys
import cv2
import matplotlib

face_cascade = cv2.CascadeClassifier('c:\\opencv\\build\\etc\\haarcascades\\haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('c:\\opencv\\build\\etc\\haarcascades\\haarcascade_eye.xml')
full_body = cv2.CascadeClassifier('c:\\opencv\\build\\etc\\haarcascades\\haarcascade_fullbody.xml')
upper_body = cv2.CascadeClassifier('c:\\opencv\\build\\etc\\haarcascades\\haarcascade_upperbody.xml')

selected_image = raw_input('Enter a file for processing: ')

img = cv2.imread(selected_image)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
    img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
    roi_gray = gray[y:y+h, x:x+w]
    roi_color = img[y:y+h, x:x+w]
    eyes = eye_cascade.detectMultiScale(roi_gray)
    for (ex,ey,ew,eh) in eyes:
        cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)

cv2.imshow('img',img)

k = cv2.waitKey(0)
if k == 27:         # wait for ESC key to exit
    cv2.destroyAllWindows()
elif k == ord('s'): # wait for 's' key to save and exit
    saveas = raw_input('Save file as: ')
    cv2.imwrite(saveas+'.jpg',img)
    cv2.destroyAllWindows()

sys.exit()