Loading [MathJax]/extensions/MathZoom.js

Thursday, 9 March 2017

Bird Motion Detector

It was pointed out to me that while live streaming was very impressive, a view of an empty box wasn't answering any questions about whether it was getting visited.

The solution was to set-up motion detection and save still images whenever something happened.

The code is based on the Image processing tutorial here.

By installing the libraries, you get a Camera object that you can use to quickly grab and manipulate images. Import it using the imgproc library.

The motion detector code can then be build using a small python file: 

import subprocess
from imgproc import *

cam = Camera(320, 240)
continue_processing = True

last_frame_colour = 0
index = 1
savecount = 0
threshold = 40

try:
    while continue_processing:
        average_red = 0
        average_green = 0
        average_blue = 0

        image = cam.grabImage()
        
        total_red = 0
        total_green = 0
        total_blue = 0
       
        # Only check central 40 x 40 box  
        pixel_count = 1600

        for x in range(140, 180):
            for y in range(100, 140):
                red, green, blue = image[x,y]
                total_red += red
                total_green += green
                total_blue += blue

        # average rgb per pixel
        average_red = total_red / pixel_count
        average_green = total_green / pixel_count
        average_blue = total_blue / pixel_count

        frame_colour = average_red + average_green + average_blue

        filename = "image" + str(index) + ".jpg"
                
        if frame_colour > last_frame_colour + threshold:
            del cam
            subprocess.call(["raspistill", "-o", filename])
            savecount += 1
            cam = Camera(320, 240)
       
        if frame_colour < last_frame_colour - threshold:
            del cam
            subprocess.call(["raspistill", "-o", filename])
            savecount += 1
            cam = Camera(320, 240)

        if savecount > 20:
            continue_processing = False

        last_frame_colour = frame_colour

        index += 1

finally:
    print "Finished"


 The code does the following
  1. Create a fairly low resolution camera 320x240 pixels
  2. Enter a loop and grab an image  image = cam.grabImage()
  3. Take the pixels in the central 40x40 box and build up a representative average colour
  4. Compare this with the average from the previous iteration. If the difference exceeds a threshold, in this case set at 40 after some experimentation, then take a still image
  5. To save the still I call out to raspistill using subprocess. The problem here is I need to kill the Camera running the detection. Unfortunately at this point I've called del on that object, which doesn't really play nicely with python and Garbage collection. This is certainly something to improve in future.
  6. Finally, I set a limit of saving 20 images before exiting the loop. This is a conservative limit intended to prevent the SD card filling up. The images are just named with an index based on the iteration through the loop. Again something more sophisticated would improve things here.
I wanted to run this process continuously while I'm not logged on so I used the  following command:

nohup python BirdDetector.py > /dev/null &
  • nohup keeps the process running even after logging out of the session
  • & runs the process in the background
  • > /dev/null redirects the output to the null device
So, did I detect a bird?

Yes!

Was the bird (A great tit) concerned about being spied on?

Who knows!

No comments:

Post a Comment