树莓派Python实现相机控制,定时与画面变化捕捉拍照
Posted xuehu96
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树莓派Python实现相机控制,定时与画面变化捕捉拍照相关的知识,希望对你有一定的参考价值。
0. 功能实现
准备做一个摄像头定时拍照的程序,当一个监控,如果选择录像,会占用大量的存储空间,循环存储也存不了太久。
拍照可以节省空间,16G能循环半个月,一直拍照会有大量重复的照片,不好找关键照片,而且也会加大存储了。
因此使用python编写根据画面变化定时拍照程序
1. 准备
准备一个带CSI接口的树莓派摄像头,与树莓派连接,并启用摄像头
#启用摄像头
sudo raspi-config
#选择 interface ... camera ... enable ... yes
#测试
raspistill -o image.jpg
2. 代码
#!/usr/bin/python
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 = 256 * 1024 * 1024 # Keep 40 mb free on disk
cameraSettings = ""
# settings of the photos to save
saveWidth = 1600
saveHeight = 1200
saveQuality = 75 # 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 500 -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 1000 -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
3. 实物
以上是关于树莓派Python实现相机控制,定时与画面变化捕捉拍照的主要内容,如果未能解决你的问题,请参考以下文章