tvoverbeek
Posts: 98
Joined: Mon Feb 04, 2013 9:50 am
Location: Fieberbrunn, Austria

Re: Lightweight python motion detection

Thu Aug 29, 2013 5:48 am

ShaunVW wrote:
tvoverbeek wrote:
ShaunVW wrote:With regards to the preview issue, I found that by adding the switch -n for no preview, my captured images were very dark. Initially I thought it was to do with the low light conditions, and so added the switch -ex night, but this had no effect. Then taking off the -n switch again, the picture was nice and bright again.
The "dark images without preview" issue was fixed in a recent update of raspistill. Update your firmware to the latest using rpi-update and see if the dark images have gone when using no preview.
I did a sudo apt-get update & sudo apt-get upgrade, this issue still exists with the -n switch.
I tried sudo rpi-update, the command wasn't recognised.
You have to install it first:

Code: Select all

sudo apt-get install rpi-update
See https://github.com/Hexxeh/rpi-update for details.

ShaunVW
Posts: 37
Joined: Tue Aug 28, 2012 5:11 pm

Re: Lightweight python motion detection

Thu Aug 29, 2013 7:05 am

tvoverbeek wrote:You have to install it first:

Code: Select all

sudo apt-get install rpi-update
See https://github.com/Hexxeh/rpi-update for details.
Thank you, I'll try that later this evening when home.

ShaunVW
Posts: 37
Joined: Tue Aug 28, 2012 5:11 pm

Re: Lightweight python motion detection

Fri Aug 30, 2013 3:18 pm

I installed rpi-update and then did a firmware update.
For good measure, I also did apt-get update and upgrade, but the Pi was already fully updated.
After rebooting, I then also did raspi-config and enabled the camera again (I read on a different post someone having to do that).
I again rebooted, but my setup now no longer does motion detection and uploading the pictures?
It still takes a picture every 15 minutes (this is my force capture time interval) and uploads it fine.
The other problem is that the photos are now dark without the -n switch (I did a firmware update to sort this dark capture picture issue with the -n switch). Now it is permanently dark. By dark I mean as if very low light conditions!
I seem to have gone backwards by this firmware update.
I am accessing it headless, so I can't actually see if it does a preview without the -n switch.

JiriW
Posts: 2
Joined: Sat Aug 24, 2013 4:51 pm

Re: Lightweight python motion detection

Fri Sep 06, 2013 8:15 am

JiriW wrote:Hello, thank you brainflakes, pageauc, peewee2 and Kesthal for nice python script!!! Works fine for me. I have only one problem. After 24-48 hours of running the script, raspberrypi completly freeze. Maybe the internal memory is filled or something. I have still a lot freespace on sdcard so not sure where is the issue.

:idea: Could someone implement some clearing internal memory after a few hours of running or restarting? I have raspberrypi only a week so its all new for me. Thank you!
I solve this problem with uploading everything on FTP (and deleting)
here's script (you will need wput install for this):

Code: Select all

import time
import subprocess
import os

while (True):
    time.sleep(600)
    os.chdir("/home/pi/Desktop/cam/img/")
    os.system('wput ftp://USERNAME:[email protected]/ -R')

motocoder
Posts: 29
Joined: Fri Sep 06, 2013 4:13 pm

Re: Lightweight python motion detection

Fri Sep 06, 2013 4:18 pm

Brainflakes - I just wanted to thank you for posting this code. After reading your code and seeing how simple the technique was, I leveraged it in my Raspberry Pi powered cat treat dispenser (videos below).

Video of the motion detect feature here:
http://youtu.be/Ua2BANU7uzA

Video of the physical interface:
http://youtu.be/KexCIS8uCzU

Video of an enhancement that counts the number of treats dispensed:
https://www.facebook.com/photo.php?v=10 ... 1752912327
https://www.facebook.com/photo.php?v=10 ... 7763378792

bongdw
Posts: 3
Joined: Thu Aug 08, 2013 7:43 pm

Re: Lightweight python motion detection

Thu Sep 19, 2013 3:24 am

Thanks for this awesome script!

I'm just wondering if there's any way to get this to sync with Dropbox or enable remote accessibility outside of FTP? *cough* trying to make things easier for my wife... *cough*

User avatar
leol
Posts: 147
Joined: Fri Jan 13, 2012 4:27 pm
Location: Haute-Vienne, France

Re: Lightweight python motion detection

Thu Sep 26, 2013 1:19 pm

Have a look at DropBox Uploader - bash script http://www.andreafabrizi.it/?dropbox_uploader

Works for me.

Leo

bdacasc
Posts: 2
Joined: Thu Sep 26, 2013 3:37 pm

Re: Lightweight python motion detection

Thu Sep 26, 2013 3:44 pm

Great !
I got this to work

But I would like to run this via Cron. Is that possible ?

I would like the camera to take pictures for one hour then stop.
Then I would like Cron to send the file to a sftp server that I have on my LAN
Then I would like the camera to continue the work
Then sftp
...and so on..

Any advice for a n00b like me? :oops:

aquadat0r
Posts: 7
Joined: Sun Jul 15, 2012 10:25 am

Re: Lightweight python motion detection

Sat Sep 28, 2013 3:23 pm

Sorry it that has been answered before, but is there any assistance available in hardware for motion detection? If so, it it used in this solution?

XAPBob
Posts: 91
Joined: Tue Jan 03, 2012 2:40 pm

Re: Lightweight python motion detection

Mon Sep 30, 2013 10:34 am

This solution just takes low res pictures, and checks the difference between them, green pixel by green pixel, before taking a high res photo if there enough changes.

Nothing hardware - but it's only using: ~15% CPU, occasionally 20%, an 4% RAM (on a 1st gen Pi)
I'm just about to integrate the drop box uploader, making a directory per day, and then pictures as needed under that.

I can also then delete the files locally on success.

My plan then is to use a tmpfs for the storage - and if the dropbox upload fails then drop the file to SD card instead.
A daily cronjob to scrape those from the SD card an try again can have email alerts if I need it to.

ArhPos
Posts: 13
Joined: Wed Oct 02, 2013 9:54 am

Re: Lightweight python motion detection

Fri Oct 11, 2013 7:25 pm

Hi everybody, first time poster here.
I've been fiddling with motion detectors for a few weeks, but couldn't get what I wanted so I started to do something, that suits me better.
So here's my approach to a motion detection with python - yapimotion as 'yet another pi motion'
Idea is to run raspistill all the time as a background process updating image to a tmpfs folder, this way it's fast as tmpfs is in memory and there's no excessive wear on sd-card.

Hand drawn black&white mask image can be used, just take a snapshot with raspistill, colour parts of the image you want to mask black and the areas of interest white. Save as a (rgb) mask.jpg
If you want to give it a go, here's code and how to get it running (PIL is mandatory)

First, create folder and mount it as a tmpfs

Code: Select all

sudo mkdir /media/capture
Add following line at the end of /etc/fstab

Code: Select all

tmpfs   	/media/capture 	tmpfs   nodev,nosuid      0   	  0
Then, install pip

Code: Select all

wget https://raw.github.com/pypa/pip/master/contrib/get-pip.py && python get-pip.py
jpeg-dev (Don't know if this is necessary if you already have older libjpeg)

Code: Select all

sudo apt-get install libjpeg8-dev
Then to get jpg working, symbolic link must be set.

Code: Select all

find /usr/lib -name libjpeg.so
Couple lines pops up.
> /usr/lib/arm-linux-gnueabihf/libjpeg.so
> /usr/lib/jvm/jdk-7-oracle-armhf/jre/lib/arm/libjpeg.so
We have to make symbolic link to first one.

Code: Select all

sudo ln -s /usr/lib/arm-linux-gnueabihf/libjpeg.so /usr/lib/
The install PIL

Code: Select all

sudo pip install PIL
At this point reboot raspberry, so the /media/capture becomes mounted and ready to use.

Code: Select all

import os
import shutil
import time, datetime
import signal, sys
import numpy as np
from PIL import Image, ImageChops

SRCFILE = '/media/capture/still.jpg'
DSTDIR = '/home/pi/mymotion/motion_gallery/'
MASKFILE = '/home/pi/mymotion/mask.jpg'
USE_MASK = False
resize = (100, 100)
# yet another pi motion
class yaPiMotion():
    def __init__(self):
        # Take current time as a timestamp and get the first image
        self.snapshot_timestamp = time.time()
        self.img1 = self.loadImage(SRCFILE)			
        self.snapshot_timestamp2 = None
        self.img2 = None
                  
        if USE_MASK: 
            self.marr = np.array( self.loadImage( MASKFILE ) )  # Mask numpy array           
            self.img1 = self.applyMask(self.img1)
            #self.img1.save('test_nmask.jpg')   # Uncomment for mask testing

    def applyMask(self, image):
        arr = np.array(image)    # Convert image to numpy array
        arr[self.marr==0] = 0    # Copy black colour (zeros) from mask array to image array
        return Image.fromarray(arr)  # Convert array back to an image and return it
    
    def signalHandler(self, signal, frame):
        # Clean stuff here, if needed     
        sys.exit(0)
    
    # Get files modification time
    def modificationDate(self, filename):
        try:
            t = os.path.getmtime(filename)
        except OSError:
            t = None		    
        return t

    def loadImage(self, image_file):
        try:     
            im = Image.open(image_file) 
            im.thumbnail( resize )
            gray = im.convert('L')    # Convert to grayscale
            #im = gray.convert('RGB')  # Convert back, so we have a rgb grayscale image (duh?)
        except IOError:
            im = None
        return im
    
    # http://stackoverflow.com/questions/5524179/how-to-detect-motion-between-two-pil-images-wxpython-webcam-integration-example
    def imageEntropy(self, img1, img2):
        try:
            img = ImageChops.difference(img1, img2)
        except AttributeError:
			return 0
        
        w,h = img.size
        a = np.array(img).reshape((w*h,3))                        # Figure out, how to do this to grayscale image
        h,e = np.histogramdd(a, bins=(16,)*3, range=((0,256),)*3) # image, it could be a little faster 
        prob = h/np.sum(h) # normalize
        prob = prob[prob>0] # remove zeros
        
        ret = -np.sum(prob*np.log2(prob)) * 100
        #if ret > 0: img.save('./diff/diff_' + self.timeStamp()) # Uncomment this line, if you want to see triggered motion    
        
        return ret

    def timeStamp(self):
        ts = time.time()
        timestp = datetime.datetime.fromtimestamp(ts).strftime('%H:%M:%S.jpg')
        print timestp
        return timestp        

    def detect(self):
        ret = 0
        # Take timestamp from file, so we can check if there's any change
        self.snapshot_timestamp2 = self.modificationDate(SRCFILE)
        if self.snapshot_timestamp2 is not None or self.img1 is not None:
            # There's an image available, but check if it's new			
            if self.snapshot_timestamp2 is not self.snapshot_timestamp:
                self.img2 = self.loadImage(SRCFILE)
                if USE_MASK: self.img2 = self.applyMask(self.img2)
                
                ret = self.imageEntropy(self.img1, self.img2)
                self.img1 = self.img2
                self.snapshot_timestamp = self.snapshot_timestamp2 

        else: # No image available, try again
            self.snapshot_timestamp = time.time()
            self.img1 = self.loadImage(SRCFILE)			            
            if USE_MASK: self.img1 = self.applyMask(self.img1)
        
        return ret    

if __name__ == "__main__":
    y = yaPiMotion()

    while (True):
        m = y.detect()
        print("Detect: " + str( m ) )
        if m > 5: # There's been detected motion, do something
            shutil.copy2(SRCFILE, DSTDIR + y.timeStamp())  # Copy image to a safe place
        time.sleep(1)
Save code as yapimotion.py
Change paths to fit your setup, create folders etc.
Launch raspistill in timelapse mode into background

Code: Select all

raspistill -tl 1000 -t -1 -w 960 -h 720 -o /media/capture/still.jpg -n -q 50 &
And start yapimotion

Code: Select all

python yapimotion.py
There's still much to approve in the code, python is not my native language, this is in fact my second try with python :oops:
Just improve it, optimize it more, it can be never too light or fast (now it's running approx %cpu <13 and mem ~2.8 %)
Play with the return value from detect function to find value that fits the movement.
Also, there's a reason why I made this as a class, I want this to only for motion, no any fancy stuff, like email warnings/uploading, these can be made in other classes (or am I just too deep in the C world ?)

PIMaster3.14
Posts: 1
Joined: Sun Oct 20, 2013 9:52 pm

Re: Lightweight python motion detection

Sun Oct 20, 2013 9:59 pm

Just wondering if some peoples' problems are having not enabled the pi cam

Code: Select all

sudo raspi-config
and enable the pi camera if this has not been done.

renhzhang2
Posts: 1
Joined: Mon Oct 28, 2013 3:21 am

Re: Lightweight python motion detection

Mon Oct 28, 2013 3:31 am

Hi, your work is brilliant. But when I run it on my RPi, there is an error at the line
command = "raspistill -w %s -h %s -t 0 -e bmp -o -" % (100, 75).
It says: SyntaxError: invalid syntax. Could you please tell me what's wrong with it because I am a beginner. Thanks very much :D

marcoleonardi
Posts: 2
Joined: Sun Nov 10, 2013 2:22 pm

Re: Lightweight python motion detection

Sun Nov 10, 2013 2:56 pm

very strange thing:
the raspistill executable with the option -t 0 go to infinite loop and non get the snapshot, tried also from command line, the preview stay on screen but no snapshot.
If I set the command with -t >0 it work, the value must be >4 otherwise I get black frames (with suggested resolution), but I've too much delay on first frame.
I would like to recompile raspistill with embedded setting and on activation timelapse for 4-5 frames. The goal is to get 4-5 frames of a car that passing on the road @40-50Km/h, in order to read the plate no.

current config:
rpi model b
kernel: Linux raspberrypi 3.10.18+ #585 Thu Nov 7 15:16:15 GMT 2013 armv6l GNU/Linux
SD: kingstom 8Gb cl10

jamesh
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 23078
Joined: Sat Jul 30, 2011 7:41 pm

Re: Lightweight python motion detection

Sun Nov 10, 2013 7:20 pm

marcoleonardi wrote:very strange thing:
the raspistill executable with the option -t 0 go to infinite loop and non get the snapshot, tried also from command line, the preview stay on screen but no snapshot.
If I set the command with -t >0 it work, the value must be >4 otherwise I get black frames (with suggested resolution), but I've too much delay on first frame.
I would like to recompile raspistill with embedded setting and on activation timelapse for 4-5 frames. The goal is to get 4-5 frames of a car that passing on the road @40-50Km/h, in order to read the plate no.

current config:
rpi model b
kernel: Linux raspberrypi 3.10.18+ #585 Thu Nov 7 15:16:15 GMT 2013 armv6l GNU/Linux
SD: kingstom 8Gb cl10
You should really have posted a new topic for this, its not relate to the original thread...but...

-t 0 is the setting for run forever.
The t value is in milliseconds, and you need about 750 minimum for the camera to start up and get a decent picture. (it needs time for the exposure calculation to stabilise)

The best option to use for your requirements is signal mode. You start the camera and its waits for a signal from another process to tell it to initiate the capture. This is much quicker that starting raspistill from scratch, as the camera is already running. But you won't be able to take mode than about 2-3 frames per second unless you reduce the frame size.
Principal Software Engineer at Raspberry Pi (Trading) Ltd.
Contrary to popular belief, humorous signatures are allowed. Here's an example...
"My grief counseller just died, luckily, he was so good, I didn't care."

marcoleonardi
Posts: 2
Joined: Sun Nov 10, 2013 2:22 pm

Re: Lightweight python motion detection

Mon Nov 11, 2013 10:39 am

Thank you so much for your prompt reply and sorry to be going a bit offtopic.

hobbyfarm
Posts: 1
Joined: Wed Nov 13, 2013 1:54 am

Re: Lightweight python motion detection

Wed Nov 13, 2013 3:35 am

piabpiab wrote:
pageauc wrote: You can modify motiondetect script to record video instead for a specific time duration per raspivid parameters. Just be aware that these files are in H264 format and as such cannot be viewed directly with a media player. They can be streamed to another computer for viewing. See last part of this video for some details
http://www.youtube.com/watch?v=H1jSudsIJfA
I've been uploading the h264 file from the Pi to dropbox and then viewing them directly on my PC using VLC.
To: pageauc or anybody else,
I would like to see this system configured to be used autonomously in an outdoor environment (rural farm). It would be nice to be able to upload the video/images via a 4G/LTE link (e.g., using Verizon Jetpack). Since detection of the camera by cattle/copper thieves would result in immediate theft or destruction of said camera, it would be nice to have at least some of the video already stored on my home storage and/or dropbox. As a "turn-key" package, probably a lot of farmers would be extremely grateful for a low cost solution to help abate the significant increase in farm crimes. PS: I am new to programming, etc.

User avatar
KLL
Posts: 1453
Joined: Wed Jan 09, 2013 3:05 pm
Location: thailand
Contact: Website

Re: Lightweight python motion detection

Sun Nov 17, 2013 8:20 am

i try this first time and get error
from line
# Get first image
image1, buffer1 = captureTestImage()
stuck at
def captureTestImage():
imageData.write(subprocess.check_output(command, shell=True))

ERROR MSG:

Code: Select all

[email protected] ~ $ sudo python  /home/pi/python_cam/picam4_motionV2.py
^CTraceback (most recent call last):
  File "/home/pi/python_cam/picam4_motionV2.py", line 76, in <module>
    image1, buffer1 = captureTestImage()
  File "/home/pi/python_cam/picam4_motionV2.py", line 40, in captureTestImage
    imageData.write(subprocess.check_output(command, shell=True))
  File "/usr/lib/python2.7/subprocess.py", line 538, in check_output
    output, unused_err = process.communicate()
  File "/usr/lib/python2.7/subprocess.py", line 746, in communicate
    stdout = _eintr_retry_call(self.stdout.read)
  File "/usr/lib/python2.7/subprocess.py", line 478, in _eintr_retry_call
    return func(*args)
KeyboardInterrupt
[email protected] ~ $
any idea what i do wrong?
( i try both versions i found here )

horus1988
Posts: 1
Joined: Fri Dec 13, 2013 10:12 pm

Re: Lightweight python motion detection

Fri Dec 13, 2013 10:14 pm

i have the same problem!

HerrJemineh
Posts: 10
Joined: Tue Aug 13, 2013 1:35 pm

Re: Lightweight python motion detection

Mon Dec 16, 2013 9:36 am

Hello everybody,

I'm using this picam-script by Kesthal and it's working fine:

Code: Select all

    #!/usr/bin/python

    # original script by brainflakes, improved by pageauc, peewee2 and Kesthal
    # www.raspberrypi.org/phpBB3/viewtopic.php?f=43&t=45235

    # You need to install PIL to run this script
    # type "sudo apt-get install python-imaging-tk" in an terminal window to do this

    import StringIO
    import subprocess
    import os
    import time
    from datetime import datetime
    from PIL import Image

    # Motion detection settings:
    # Threshold          - how much a pixel has to change by to be marked as "changed"
    # Sensitivity        - how many changed pixels before capturing an image, needs to be higher if noisy view
    # ForceCapture       - whether to force an image to be captured every forceCaptureTime seconds, values True or False
    # filepath           - location of folder to save photos
    # filenamePrefix     - string that prefixes the file name for easier identification of files.
    # diskSpaceToReserve - Delete oldest images to avoid filling disk. How much byte to keep free on disk.
    # cameraSettings     - "" = no extra settings; "-hf" = Set horizontal flip of image; "-vf" = Set vertical flip; "-hf -vf" = both horizontal and vertical flip
    threshold = 10
    sensitivity = 20
    forceCapture = True
    forceCaptureTime = 60 * 60 # Once an hour
    filepath = "/home/pi/picam"
    filenamePrefix = "capture"
    diskSpaceToReserve = 40 * 1024 * 1024 # Keep 40 mb free on disk
    cameraSettings = ""

    # settings of the photos to save
    saveWidth   = 1296
    saveHeight  = 972
    saveQuality = 15 # Set jpeg quality (0 to 100)

    # Test-Image settings
    testWidth = 100
    testHeight = 75

    # this is the default setting, if the whole image should be scanned for changed pixel
    testAreaCount = 1
    testBorders = [ [[1,testWidth],[1,testHeight]] ]  # [ [[start pixel on left side,end pixel on right side],[start pixel on top side,stop pixel on bottom side]] ]
    # testBorders are NOT zero-based, the first pixel is 1 and the last pixel is testWith or testHeight

    # with "testBorders", you can define areas, where the script should scan for changed pixel
    # for example, if your picture looks like this:
    #
    #     ....XXXX
    #     ........
    #     ........
    #
    # "." is a street or a house, "X" are trees which move arround like crazy when the wind is blowing
    # because of the wind in the trees, there will be taken photos all the time. to prevent this, your setting might look like this:

    # testAreaCount = 2
    # testBorders = [ [[1,50],[1,75]], [[51,100],[26,75]] ] # area y=1 to 25 not scanned in x=51 to 100

    # even more complex example
    # testAreaCount = 4
    # testBorders = [ [[1,39],[1,75]], [[40,67],[43,75]], [[68,85],[48,75]], [[86,100],[41,75]] ]

    # in debug mode, a file debug.bmp is written to disk with marked changed pixel an with marked border of scan-area
    # debug mode should only be turned on while testing the parameters above
    debugMode = False # False or True

    # Capture a small test image (for motion detection)
    def captureTestImage(settings, width, height):
        command = "raspistill %s -w %s -h %s -t 200 -e bmp -n -o -" % (settings, width, height)
        imageData = StringIO.StringIO()
        imageData.write(subprocess.check_output(command, shell=True))
        imageData.seek(0)
        im = Image.open(imageData)
        buffer = im.load()
        imageData.close()
        return im, buffer

    # Save a full size image to disk
    def saveImage(settings, width, height, quality, diskSpaceToReserve):
        keepDiskSpaceFree(diskSpaceToReserve)
        time = datetime.now()
        filename = filepath + "/" + filenamePrefix + "-%04d%02d%02d-%02d%02d%02d.jpg" % (time.year, time.month, time.day, time.hour, time.minute, time.second)
        subprocess.call("raspistill %s -w %s -h %s -t 200 -e jpg -q %s -n -o %s" % (settings, width, height, quality, filename), shell=True)
        print "Captured %s" % filename

    # Keep free space above given level
    def keepDiskSpaceFree(bytesToReserve):
        if (getFreeSpace() < bytesToReserve):
            for filename in sorted(os.listdir(filepath + "/")):
                if filename.startswith(filenamePrefix) and filename.endswith(".jpg"):
                    os.remove(filepath + "/" + filename)
                    print "Deleted %s/%s to avoid filling disk" % (filepath,filename)
                    if (getFreeSpace() > bytesToReserve):
                        return

    # Get available disk space
    def getFreeSpace():
        st = os.statvfs(filepath + "/")
        du = st.f_bavail * st.f_frsize
        return du

    # Get first image
    image1, buffer1 = captureTestImage(cameraSettings, testWidth, testHeight)

    # Reset last capture time
    lastCapture = time.time()

    while (True):

        # Get comparison image
        image2, buffer2 = captureTestImage(cameraSettings, testWidth, testHeight)

        # Count changed pixels
        changedPixels = 0
        takePicture = False

        if (debugMode): # in debug mode, save a bitmap-file with marked changed pixels and with visible testarea-borders
            debugimage = Image.new("RGB",(testWidth, testHeight))
            debugim = debugimage.load()

        for z in xrange(0, testAreaCount): # = xrange(0,1) with default-values = z will only have the value of 0 = only one scan-area = whole picture
            for x in xrange(testBorders[z][0][0]-1, testBorders[z][0][1]): # = xrange(0,100) with default-values
                for y in xrange(testBorders[z][1][0]-1, testBorders[z][1][1]):   # = xrange(0,75) with default-values; testBorders are NOT zero-based, buffer1[x,y] are zero-based (0,0 is top left of image, testWidth-1,testHeight-1 is botton right)
                    if (debugMode):
                        debugim[x,y] = buffer2[x,y]
                        if ((x == testBorders[z][0][0]-1) or (x == testBorders[z][0][1]-1) or (y == testBorders[z][1][0]-1) or (y == testBorders[z][1][1]-1)):
                            # print "Border %s %s" % (x,y)
                            debugim[x,y] = (0, 0, 255) # in debug mode, mark all border pixel to blue
                    # Just check green channel as it's the highest quality channel
                    pixdiff = abs(buffer1[x,y][1] - buffer2[x,y][1])
                    if pixdiff > threshold:
                        changedPixels += 1
                        if (debugMode):
                            debugim[x,y] = (0, 255, 0) # in debug mode, mark all changed pixel to green
                    # Save an image if pixels changed
                    if (changedPixels > sensitivity):
                        takePicture = True # will shoot the photo later
                    if ((debugMode == False) and (changedPixels > sensitivity)):
                        break  # break the y loop
                if ((debugMode == False) and (changedPixels > sensitivity)):
                    break  # break the x loop
            if ((debugMode == False) and (changedPixels > sensitivity)):
                break  # break the z loop

        if (debugMode):
            debugimage.save(filepath + "/debug.bmp") # save debug image as bmp
            print "debug.bmp saved, %s changed pixel" % changedPixels
        # else:
        #     print "%s changed pixel" % changedPixels

        # Check force capture
        if forceCapture:
            if time.time() - lastCapture > forceCaptureTime:
                takePicture = True

        if takePicture:
            lastCapture = time.time()
            saveImage(cameraSettings, saveWidth, saveHeight, saveQuality, diskSpaceToReserve)

        # Swap comparison buffers
        image1 = image2
        buffer1 = buffer2
Now I want my raspberry pi to upload the taken fotos to my Dropbox-Account.
I've already managed to upload files to my Dropbox by the following command:

Code: Select all

/home/pi/Dropbox-Uploader/dropbox_uploader.sh -s upload /home/pi/picam
That command uploads all files in /home/pi/picam to my Dropbox and skips already uploaded files.
By adding a filename to this commad it will only upload that one file.
My question:
Is there a way to add this command to the picam-script? So the taken foto is going to be uploaded directly after taken?
That's possibly a quite easy job for someone knowing how to write in python... but for me it isn't.
It would be very nice if someone could help me.

kindest regards
Simon

User avatar
KLL
Posts: 1453
Joined: Wed Jan 09, 2013 3:05 pm
Location: thailand
Contact: Website

Re: Lightweight python motion detection

Wed Dec 18, 2013 2:27 am

HerrJemineh wrote: Is there a way to add this command to the picam-script? So the taken foto is going to be uploaded directly after taken?
Simon
http://kll.engineering-news.org/kllfusi ... picam4.txt
here you can see my test example with options
- dropbox,
- ftp,
- email,
- symlink to last picture

have fun

HerrJemineh
Posts: 10
Joined: Tue Aug 13, 2013 1:35 pm

Re: Lightweight python motion detection

Wed Dec 18, 2013 8:20 am

That is exactly what I was looking for!

Thank you very much!

MagoDeOz
Posts: 1
Joined: Mon Dec 23, 2013 11:20 pm

Re: Lightweight python motion detection

Mon Dec 23, 2013 11:28 pm

Hi,
This post is really cool, I just wanted to shared with you guys that I've develop a lightweight motion detection too, is a little more efficient because in stead of processing the image (which is performance exhaustive) I've added a low-price(5$) motion sensor device which triggers the motion action, and using GPIO you get an event detected, the performance is really good and the CPU is free in order to leave space for some other complex tasks. The drawback of my approach is that you cannot know if the object in motion is actually moving up/down/left or right, have you guys tried to detect the direction of the object moving?

Anyway here is the video that demonstrates what I did:
http://www.youtube.com/watch?v=ulqJBI2lj8U

And here is the source code in case you guys want to give it a try:
http://www.doepiccoding.com/blog/?p=105

Regards!

hoggerz
Posts: 8
Joined: Sun Dec 29, 2013 1:05 am

Re: Lightweight python motion detection

Mon Dec 30, 2013 2:56 pm

Hi
Great script, I've modified it to call raspivid for a 65 second H264 clip instead of raspistill for a full high res photo, but it seems to always record a second video immediately after the first one even If there is absolutely no motion present. I'm wondering If anyone else has tried this and encountered the same problem and maybe knew of a solution? Here's the script I'm using:

Code: Select all

#!/usr/bin/python
# original script by brainflakes, improved by pageauc, peewee2 and Kesthal
# www.raspberrypi.org/phpBB3/viewtopic.php?f=43&t=45235
# You need to install PIL to run this script
# type "sudo apt-get install python-imaging-tk" in an terminal window to do this

import StringIO
import subprocess
import os
import time
from datetime import datetime
from PIL import Image

# Motion detection settings:
# Threshold          - how much a pixel has to change by to be marked as "changed"
# Sensitivity        - how many changed pixels before capturing an image, needs to be higher if noisy view
# ForceCapture       - whether to force an image to be captured every forceCaptureTime seconds, values True or False
# filepath           - location of folder to save photos
# filenamePrefix     - string that prefixes the file name for easier identification of files.
# diskSpaceToReserve - Delete oldest images to avoid filling disk. How much byte to keep free on disk.
# cameraSettings     - "" = no extra settings; "-hf" = Set horizontal flip of image; "-vf" = Set vertical flip; "-hf -vf" = both horizontal and vertical flip
threshold = 80 # default 10
sensitivity = 80 # default 20
forceCapture = False
forceCaptureTime = 60 * 60 # Once an hour
filepath = "/home/pi/picam"
filenamePrefix = "capture"
diskSpaceToReserve = 40 * 1024 * 1024 # Keep 40 mb free on disk
cameraSettings = ""

# settings of the photos to save
saveWidth   = 1296
saveHeight  = 972
saveQuality = 15 # Set jpeg quality (0 to 100)

# Test-Image settings
testWidth = 100
testHeight = 75

# this is the default setting, if the whole image should be scanned for changed pixel
testAreaCount = 1
testBorders = [ [[1,testWidth],[1,testHeight]] ]  # [ [[start pixel on left side,end pixel on right side],[start pixel on top side,stop pixel on bottom side]] ]
# testBorders are NOT zero-based, the first pixel is 1 and the last pixel is testWith or testHeight

# with "testBorders", you can define areas, where the script should scan for changed pixel
# for example, if your picture looks like this:
#
#     ....XXXX
#     ........
#     ........
#
# "." is a street or a house, "X" are trees which move arround like crazy when the wind is blowing
# because of the wind in the trees, there will be taken photos all the time. to prevent this, your setting might look like this:

# testAreaCount = 2
# testBorders = [ [[1,50],[1,75]], [[51,100],[26,75]] ] # area y=1 to 25 not scanned in x=51 to 100

# even more complex example
# testAreaCount = 4
# testBorders = [ [[1,39],[1,75]], [[40,67],[43,75]], [[68,85],[48,75]], [[86,100],[41,75]] ]

# in debug mode, a file debug.bmp is written to disk with marked changed pixel an with marked border of scan-area
# debug mode should only be turned on while testing the parameters above
debugMode = False # False or True

# Capture a small test image (for motion detection)
def captureTestImage(settings, width, height):
    command = "raspistill %s -w %s -h %s -t 200 -e bmp -n -o -" % (settings, width, height)
    imageData = StringIO.StringIO()
    imageData.write(subprocess.check_output(command, shell=True))
    imageData.seek(0)
    im = Image.open(imageData)
    buffer = im.load()
    imageData.close()
    return im, buffer

# Save a full size image to disk
def saveImage(settings, width, height, quality, diskSpaceToReserve):
    keepDiskSpaceFree(diskSpaceToReserve)
    time = datetime.now()
    filename = filepath + "/" + filenamePrefix + "-%04d%02d%02d-%02d%02d%02d.h264" % (time.year, time.month, time.day, time.hour, time.minute, time.second)
#    subprocess.call("raspistill %s -w %s -h %s -t 200 -e jpg -q %s -n -o %s" % (settings, width, height, quality, filename), shell=True)
    subprocess.call("raspivid %s -w 1280 -h 720 -t 65000 -n -o %s" % (settings, filename), shell=True)
    print "Captured %s" % filename

# Keep free space above given level
def keepDiskSpaceFree(bytesToReserve):
    if (getFreeSpace() < bytesToReserve):
        for filename in sorted(os.listdir(filepath + "/")):
            if filename.startswith(filenamePrefix) and filename.endswith(".jpg"):
                os.remove(filepath + "/" + filename)
                print "Deleted %s/%s to avoid filling disk" % (filepath,filename)
                if (getFreeSpace() > bytesToReserve):
                    return

# Get available disk space
def getFreeSpace():
    st = os.statvfs(filepath + "/")
    du = st.f_bavail * st.f_frsize
    return du

# Get first image
image1, buffer1 = captureTestImage(cameraSettings, testWidth, testHeight)

# Reset last capture time
lastCapture = time.time()

while (True):

    # Get comparison image
    image2, buffer2 = captureTestImage(cameraSettings, testWidth, testHeight)

    # Count changed pixels
    changedPixels = 0
    takePicture = False

    if (debugMode): # in debug mode, save a bitmap-file with marked changed pixels and with visible testarea-borders
        debugimage = Image.new("RGB",(testWidth, testHeight))
        debugim = debugimage.load()

    for z in xrange(0, testAreaCount): # = xrange(0,1) with default-values = z will only have the value of 0 = only one scan-area = whole picture
        for x in xrange(testBorders[z][0][0]-1, testBorders[z][0][1]): # = xrange(0,100) with default-values
            for y in xrange(testBorders[z][1][0]-1, testBorders[z][1][1]):   # = xrange(0,75) with default-values; testBorders are NOT zero-based, buffer1[x,y] are zero-based (0,0 is top left of image, testWidth-1,testHeight-1 is botton right)
                if (debugMode):
                    debugim[x,y] = buffer2[x,y]
                    if ((x == testBorders[z][0][0]-1) or (x == testBorders[z][0][1]-1) or (y == testBorders[z][1][0]-1) or (y == testBorders[z][1][1]-1)):
                        # print "Border %s %s" % (x,y)
                        debugim[x,y] = (0, 0, 255) # in debug mode, mark all border pixel to blue
                # Just check green channel as it's the highest quality channel
                pixdiff = abs(buffer1[x,y][1] - buffer2[x,y][1])
                if pixdiff > threshold:
                    changedPixels += 1
                    if (debugMode):
                        debugim[x,y] = (0, 255, 0) # in debug mode, mark all changed pixel to green
                # Save an image if pixels changed
                if (changedPixels > sensitivity):
                    takePicture = True # will shoot the photo later
                if ((debugMode == False) and (changedPixels > sensitivity)):
                    break  # break the y loop
            if ((debugMode == False) and (changedPixels > sensitivity)):
                break  # break the x loop
        if ((debugMode == False) and (changedPixels > sensitivity)):
            break  # break the z loop

    if (debugMode):
        debugimage.save(filepath + "/debug.bmp") # save debug image as bmp
        print "debug.bmp saved, %s changed pixel" % changedPixels
    # else:
    #     print "%s changed pixel" % changedPixels

    # Check force capture
    if forceCapture:
        if time.time() - lastCapture > forceCaptureTime:
            takePicture = True

    if takePicture:
        lastCapture = time.time()
        saveImage(cameraSettings, saveWidth, saveHeight, saveQuality, diskSpaceToReserve)

    # Swap comparison buffers
    image1 = image2
    buffer1 = buffer2


Any help/suggestions would be greatly appreciated!

Thanks

Mark

User avatar
KLL
Posts: 1453
Joined: Wed Jan 09, 2013 3:05 pm
Location: thailand
Contact: Website

Re: Lightweight python motion detection

Tue Dec 31, 2013 1:36 am

i see with the usual MOTION detect same effect many time.
at the end of the script the old picture is replaced by the new picture
as reference for the next detection.

means if a fast object moves in it detects motion,
and after it moves out it detects motion again,
and records your "empty" background and you ask whats the motion there?
means at the end of any real motion you get one more picture
( or a x sec video... ) you don't want.

Return to “Camera board”