Advertisement
Guest User

Lightweight python motion detection

a guest
Jul 27th, 2013
15,992
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.21 KB | None | 0 0
  1. #!/usr/bin/python
  2.  
  3. # original script by brainflakes, improved by pageauc, peewee2 and Kesthal
  4. # www.raspberrypi.org/phpBB3/viewtopic.php?f=43&t=45235
  5.  
  6. # You need to install PIL to run this script
  7. # type "sudo apt-get install python-imaging-tk" in an terminal window to do this
  8.  
  9. import StringIO
  10. import subprocess
  11. import os
  12. import time
  13. from datetime import datetime
  14. from PIL import Image
  15.  
  16. # Motion detection settings:
  17. # Threshold          - how much a pixel has to change by to be marked as "changed"
  18. # Sensitivity        - how many changed pixels before capturing an image, needs to be higher if noisy view
  19. # ForceCapture       - whether to force an image to be captured every forceCaptureTime seconds, values True or False
  20. # filepath           - location of folder to save photos
  21. # filenamePrefix     - string that prefixes the file name for easier identification of files.
  22. # diskSpaceToReserve - Delete oldest images to avoid filling disk. How much byte to keep free on disk.
  23. # cameraSettings     - "" = no extra settings; "-hf" = Set horizontal flip of image; "-vf" = Set vertical flip; "-hf -vf" = both horizontal and vertical flip
  24. threshold = 10
  25. sensitivity = 20
  26. forceCapture = True
  27. forceCaptureTime = 60 * 60 # Once an hour
  28. filepath = "/home/pi/picam"
  29. filenamePrefix = "capture"
  30. diskSpaceToReserve = 40 * 1024 * 1024 # Keep 40 mb free on disk
  31. cameraSettings = ""
  32.  
  33. # settings of the photos to save
  34. saveWidth   = 1296
  35. saveHeight  = 972
  36. saveQuality = 15 # Set jpeg quality (0 to 100)
  37.  
  38. # Test-Image settings
  39. testWidth = 100
  40. testHeight = 75
  41.  
  42. # this is the default setting, if the whole image should be scanned for changed pixel
  43. testAreaCount = 1
  44. 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]] ]
  45. # testBorders are NOT zero-based, the first pixel is 1 and the last pixel is testWith or testHeight
  46.  
  47. # with "testBorders", you can define areas, where the script should scan for changed pixel
  48. # for example, if your picture looks like this:
  49. #
  50. #     ....XXXX
  51. #     ........
  52. #     ........
  53. #
  54. # "." is a street or a house, "X" are trees which move arround like crazy when the wind is blowing
  55. # because of the wind in the trees, there will be taken photos all the time. to prevent this, your setting might look like this:
  56.  
  57. # testAreaCount = 2
  58. # testBorders = [ [[1,50],[1,75]], [[51,100],[26,75]] ] # area y=1 to 25 not scanned in x=51 to 100
  59.  
  60. # even more complex example
  61. # testAreaCount = 4
  62. # testBorders = [ [[1,39],[1,75]], [[40,67],[43,75]], [[68,85],[48,75]], [[86,100],[41,75]] ]
  63.  
  64. # in debug mode, a file debug.bmp is written to disk with marked changed pixel an with marked border of scan-area
  65. # debug mode should only be turned on while testing the parameters above
  66. debugMode = False # False or True
  67.  
  68. # Capture a small test image (for motion detection)
  69. def captureTestImage(settings, width, height):
  70.     command = "raspistill %s -w %s -h %s -t 200 -e bmp -n -o -" % (settings, width, height)
  71.     imageData = StringIO.StringIO()
  72.     imageData.write(subprocess.check_output(command, shell=True))
  73.     imageData.seek(0)
  74.     im = Image.open(imageData)
  75.     buffer = im.load()
  76.     imageData.close()
  77.     return im, buffer
  78.  
  79. # Save a full size image to disk
  80. def saveImage(settings, width, height, quality, diskSpaceToReserve):
  81.     keepDiskSpaceFree(diskSpaceToReserve)
  82.     time = datetime.now()
  83.     filename = filepath + "/" + filenamePrefix + "-%04d%02d%02d-%02d%02d%02d.jpg" % (time.year, time.month, time.day, time.hour, time.minute, time.second)
  84.     subprocess.call("raspistill %s -w %s -h %s -t 200 -e jpg -q %s -n -o %s" % (settings, width, height, quality, filename), shell=True)
  85.     print "Captured %s" % filename
  86.  
  87. # Keep free space above given level
  88. def keepDiskSpaceFree(bytesToReserve):
  89.     if (getFreeSpace() < bytesToReserve):
  90.         for filename in sorted(os.listdir(filepath + "/")):
  91.             if filename.startswith(filenamePrefix) and filename.endswith(".jpg"):
  92.                 os.remove(filepath + "/" + filename)
  93.                 print "Deleted %s/%s to avoid filling disk" % (filepath,filename)
  94.                 if (getFreeSpace() > bytesToReserve):
  95.                     return
  96.  
  97. # Get available disk space
  98. def getFreeSpace():
  99.     st = os.statvfs(filepath + "/")
  100.     du = st.f_bavail * st.f_frsize
  101.     return du
  102.  
  103. # Get first image
  104. image1, buffer1 = captureTestImage(cameraSettings, testWidth, testHeight)
  105.  
  106. # Reset last capture time
  107. lastCapture = time.time()
  108.  
  109. while (True):
  110.  
  111.     # Get comparison image
  112.     image2, buffer2 = captureTestImage(cameraSettings, testWidth, testHeight)
  113.  
  114.     # Count changed pixels
  115.     changedPixels = 0
  116.     takePicture = False
  117.  
  118.     if (debugMode): # in debug mode, save a bitmap-file with marked changed pixels and with visible testarea-borders
  119.         debugimage = Image.new("RGB",(testWidth, testHeight))
  120.         debugim = debugimage.load()
  121.  
  122.     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
  123.         for x in xrange(testBorders[z][0][0]-1, testBorders[z][0][1]): # = xrange(0,100) with default-values
  124.             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)
  125.                 if (debugMode):
  126.                     debugim[x,y] = buffer2[x,y]
  127.                     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)):
  128.                         # print "Border %s %s" % (x,y)
  129.                         debugim[x,y] = (0, 0, 255) # in debug mode, mark all border pixel to blue
  130.                 # Just check green channel as it's the highest quality channel
  131.                 pixdiff = abs(buffer1[x,y][1] - buffer2[x,y][1])
  132.                 if pixdiff > threshold:
  133.                     changedPixels += 1
  134.                     if (debugMode):
  135.                         debugim[x,y] = (0, 255, 0) # in debug mode, mark all changed pixel to green
  136.                 # Save an image if pixels changed
  137.                 if (changedPixels > sensitivity):
  138.                     takePicture = True # will shoot the photo later
  139.                 if ((debugMode == False) and (changedPixels > sensitivity)):
  140.                     break  # break the y loop
  141.             if ((debugMode == False) and (changedPixels > sensitivity)):
  142.                 break  # break the x loop
  143.         if ((debugMode == False) and (changedPixels > sensitivity)):
  144.             break  # break the z loop
  145.  
  146.     if (debugMode):
  147.         debugimage.save(filepath + "/debug.bmp") # save debug image as bmp
  148.         print "debug.bmp saved, %s changed pixel" % changedPixels
  149.     # else:
  150.     #     print "%s changed pixel" % changedPixels
  151.  
  152.     # Check force capture
  153.     if forceCapture:
  154.         if time.time() - lastCapture > forceCaptureTime:
  155.             takePicture = True
  156.  
  157.     if takePicture:
  158.         lastCapture = time.time()
  159.         saveImage(cameraSettings, saveWidth, saveHeight, saveQuality, diskSpaceToReserve)
  160.  
  161.     # Swap comparison buffers
  162.     image1 = image2
  163.     buffer1 = buffer2
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement