-
Notifications
You must be signed in to change notification settings - Fork 1
/
capture.py
135 lines (122 loc) · 5.83 KB
/
capture.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# Capture images one per second for 60 seconds.
# Can have multiple captures running simultaneously
import picamera
import io
import boto3
from threading import Timer
import datetime
import time
import os
import json
import botocore.config
# https://www.raspberrypi.org/documentation/usage/camera/python/README.md
cfg = botocore.config.Config(retries={"max_attempts": 0})
s3 = boto3.resource("s3")
client = boto3.client("lambda", config=cfg)
capture_file = "captures.json"
capture_file_path = "/var/tmpfs/"
lambdaarn = os.environ["LAMBDAARN"]
class Capture:
def __init__(self):
self.camera = picamera.PiCamera()
self.camera.rotation=270
self.camera.resolution=(1920,1080)# Max = (3280, 2464)
self.camera.sharpness=50#-100 to +100, 0 = default
self.camera.zoom = (0.149, 0.162, 0.728, 0.803)
self.activecaptures = {}
self.captureimages = {}
self.resize = (1089,434)
self.camera.start_preview() #Warm the camera up
self.bucket_name = os.environ["BUCKET"]
self.last_capture = {"filename": "", "time": None}
# Download captures file and cache locallycd procd
s3.Object(self.bucket_name, capture_file).download_file(capture_file_path + capture_file)
def get_last_capture(self):
return self.last_capture
def start(self, code, mmsi, details, captureSeconds=350):
'''Given an arbitrary code, captures images with that codename till told to stop'''
if code in self.activecaptures:
print "Already capturing!"
return False
print "Start capture"
self.captureimages[code] = []
self.activecaptures[code] = { "capture": True, "end": datetime.datetime.now() + datetime.timedelta(seconds = captureSeconds), "seq": 0, "timer": None, "mmsi": mmsi, "details": details }
self.capture_image(code)
def capture_image(self, code):
'''Capture an image provided the capture has not been stopped'''
if (self.activecaptures[code] and not self.activecaptures[code]["capture"]) \
or self.activecaptures[code]["end"] <= datetime.datetime.now(): # If this capture is finished
print "Capture finished"
self.activecaptures[code]["timer"].cancel()
cleanuptimer = Timer(15, self.capture_cleanup, [code])# Delay to ensure files finish uploading
cleanuptimer.start()
else:
self.activecaptures[code]["seq"] += 1
cur_seq = self.activecaptures[code]["seq"]
filename = "%s_%04d.jpg" % (code, self.activecaptures[code]["seq"])
self.captureimages[code].append(filename)
self.activecaptures[code]["timer"] = Timer(2, self.capture_image, [code])
self.activecaptures[code]["timer"].start()
self.capture_s3("img/"+filename)
print "Capture", code, ":", cur_seq
def capture_cleanup(self, code):
# Process images to video
print "Invoke lambda"
self.store_capture(code, self.activecaptures[code]["mmsi"], self.activecaptures[code]["details"])
lambdaparams = {"filelist": self.captureimages[code], "outfilename": str(code) + ".mp4"}
if "specialcapture" in self.activecaptures[code]["details"]:
lambdaparams["preservesource"] = True
del self.activecaptures[code] # Then delete the capture
client.invoke(FunctionName=lambdaarn,
InvocationType="Event",
Payload=json.dumps(lambdaparams))
def reprocess_capture(self, code):
if code in self.captureimages:
lambdaparams = {"filelist": self.captureimages[code], "outfilename": str(code) + ".mp4"}
if "specialcapture" in self.activecaptures[code]["details"]:
lambdaparams["preservesource"] = True
client.invoke(FunctionName=lambdaarn,
InvocationType="Event",
Payload=json.dumps(lambdaparams))
def store_snapshot(self):
capture_s3(self, snapshot)
return self.last_capture
def capture_s3(self, filename):
'''Capture image with camera and upload to s3 using given filename'''
# Create the in-memory stream
stream = io.BytesIO()
self.camera.capture(stream, format="jpeg")
# "Rewind" the stream to the beginning so we can read its content
stream.seek(0)
s3.Object(self.bucket_name, filename).put(Body=stream) #.upload_fileobj(stream)
stream.close()
self.last_capture["filename"] = filename
self.last_capture["time"] = int(time.time())
def capture_file(self, filename):
self.camera.capture(filename)
def stop(self, code):
'''Stop capture'''
if code in self.activecaptures:
print "Capture aborted!"
self.activecaptures[code]["capture"] = False
def get_images(self, code):
if code in self.captureimages:
return self.captureimages[code]
else:
return None
def store_capture(self, code, mmsi, details):
with open(capture_file_path + capture_file, "r+") as json_data:
d = json.load(json_data)
if "specialcapture" in details:
details["end"] = str(int(time.time()))
d["specialcaptures"].append({"code": code, "details": details})
else:
d["captures"].append(code)
if mmsi not in d["info"] and details["name"]:
d["info"][mmsi] = {"name": details["name"], "description": details["details"], "size": details["size"]}
json_data.seek(0)
json.dump(d, json_data)
json_data.truncate()
s3.Object(self.bucket_name, capture_file).upload_file(capture_file_path + capture_file, ExtraArgs={"ACL":"public-read"})
# Enhancements: Use the RPI capture instead of timer
# If after dark increase exposure