Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Motion detection illumination from the sun

Hi, I have a raspberry pi which records videos on motion detections from a PIR sensor. Sometimes "random" heat variations will falsely trigger the sensor and record a video when there isn't any motion. If there isn't any motion in the picture I would like to filter out those videos. There are two criterias for a video to be saved: a heat varation triggering the PIR sensor and motion in the video. It works for most of the videos but I have noticed that illumination will sometimes vary a lot and mimic real motion in the video and trigger the filter falsely.

# -*- coding: utf-8 -*-
import os
import cv2
import numpy as np

def diffImg(t0, t1, t2):
  d1 = cv2.absdiff(t2, t1)
  d2 = cv2.absdiff(t1, t0)
  return cv2.bitwise_and(d1, d2)

kernel = np.ones((5,5),np.uint8)

for dirpath, dnames, fnames in os.walk("/path/to/videos"):
    for f in fnames:
        cap = cv2.VideoCapture(os.path.join(dirpath, f))

        total = 0
        count = 0

        # Read three images first:
        t_minus = cv2.cvtColor(cap.read()[1], cv2.COLOR_RGB2GRAY)
        t = cv2.cvtColor(cap.read()[1], cv2.COLOR_RGB2GRAY)
        t_plus = cv2.cvtColor(cap.read()[1], cv2.COLOR_RGB2GRAY)

        while True:
            opening = cv2.morphologyEx(diffImg(t_minus, t, t_plus), cv2.MORPH_OPEN, kernel)
            total += cv2.countNonZero(opening)

            # Read next image
            t_minus = t
            t = t_plus
            ret, frame = cap.read()
            if ret == False:
              break
            t_plus = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
            count += 1

        if total/count < 800:
            print "file %s has no motion (%d)" % (os.path.join(dirpath, f), total/count)

My algorithm is very simple. It grabs three frames and calculates the difference and creates a binary image using cv2.bitwise_and. In order to remove noise it performs a morphological open on that differential image. Finally it uses cv2.countNonZero to determine the amount of motion in that frame. In the end i divide the total amount of motion by the number of frames (let's call this motion/frame) to get a number to work with. If this number is less than 800, the video is persumed to have no motion.

Here are two examples (one positive detection and one false positive detection)
Positive:
https://www.dropbox.com/s/ryvemvkoda6morn/2016-05-11_07-12-20.ts?dl=0 (motion/frame: 843) False positive:
https://www.dropbox.com/s/lqegj92jxhjjegv/2016-05-12_19-16-10.ts?dl=0 (motion/frame: 879)

As you can see from the latter, when the illumination varies a lot, it is falsely detected as motion. How can I remove these false positives from illumination changes?

Another thing worth mentioning is that this filter will be run as a post-process, i.e it won't be in realtime thus I am okay with a solution that is a somewhat heavier performance-wise than my current one.