Skip to content

Commit 31078c3

Browse files
committed
WIP changes to camera functions
1 parent 24fb6c1 commit 31078c3

File tree

13 files changed

+576
-83
lines changed

13 files changed

+576
-83
lines changed

camera.py

Lines changed: 122 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
from viz import camera, streamer, image, blob
1212
import config
1313

14+
import picamera
15+
import picamera.array
16+
import io
17+
1418
CAMERA_REFRESH_INTERVAL=0.1
1519
MAX_IMAGE_AGE = 0.0
1620
PHOTO_PATH = "./photos"
@@ -20,6 +24,10 @@
2024
PHOTO_THUMB_SUFFIX = "_thumb"
2125
PHOTO_THUMB_SIZE = (240,180)
2226
VIDEO_ELAPSE_MAX = 900
27+
PHOTO_FILE_EXT = ".jpg"
28+
FFMPEG_CMD = "MP4Box"
29+
VIDEO_FILE_EXT = ".mp4"
30+
VIDEO_FILE_EXT_H264 = ".h264"
2331

2432
class Camera(Thread):
2533

@@ -28,6 +36,8 @@ class Camera(Thread):
2836
_warp_corners_1 = [(0, -120), (640, -120), (380, 480), (260, 480)]
2937
_warp_corners_2 = [(0, -60), (320, -60), (190, 240), (130, 240)]
3038
_warp_corners_4 = [(0, -30), (160, -30), (95, 120), (65, 120)]
39+
_image_cache = None
40+
_image_cache_updated = False
3141
stream_port = 9080
3242

3343
@classmethod
@@ -39,19 +49,7 @@ def get_instance(cls):
3949

4050
def __init__(self):
4151
logging.info("starting camera")
42-
cam_props = {
43-
"width":640,
44-
"height":480,
45-
"exposure_mode": config.Config.get().get("camera_exposure_mode"),
46-
"rotation": config.Config.get().get("camera_rotation")
47-
}
48-
#try initialising the camera
49-
try:
50-
self._camera = camera.Camera(props=cam_props)
51-
except:
52-
self._camera = None
53-
logging.error("Unexpected error:" + str(sys.exc_info()[0]))
54-
pass
52+
self.init_camera()
5553

5654
self._streamer = streamer.JpegStreamer("0.0.0.0:"+str(self.stream_port), st=0.1)
5755
#self._cam_off_img.save(self._streamer)
@@ -70,39 +68,100 @@ def __init__(self):
7068

7169
super(Camera, self).__init__()
7270

71+
def init_camera(self):
72+
try:
73+
props = {
74+
"width":640,
75+
"height":480,
76+
"exposure_mode":config.Config.get().get("camera_exposure_mode"),
77+
"rotation":config.Config.get().get("camera_rotation")
78+
}
79+
self._camera = picamera.PiCamera()
80+
cam = self._camera
81+
res = (props.get("width",640), props.get("height",480))
82+
cam.resolution = res
83+
cam.framerate = 30
84+
cam.exposure_mode = props.get("exposure_mode")
85+
cam.rotation = props.get("rotation")
86+
self.out_jpeg = io.BytesIO()
87+
self.out_rgb = picamera.array.PiRGBArray(cam, size=res)
88+
self.h264_encoder = None
89+
self.recording = None
90+
self.video_filename = None
91+
except:
92+
self._camera = None
93+
logging.error("Could not initialise camera:" + str(sys.exc_info()[0]))
94+
pass
95+
96+
def grab_start(self):
97+
logging.debug("grab_start")
98+
camera_port_0, output_port_0 = self._camera._get_ports(True, 0)
99+
self.jpeg_encoder = self._camera._get_image_encoder(camera_port_0, output_port_0, 'jpeg', None, quality=40)
100+
camera_port_1, output_port_1 = self._camera._get_ports(True, 1)
101+
self.rgb_encoder = self._camera._get_image_encoder(camera_port_1, output_port_1, 'bgr', res)
102+
103+
with self._camera._encoders_lock:
104+
self._camera._encoders[0] = self.jpeg_encoder
105+
self._camera._encoders[1] = self.rgb_encoder
106+
107+
def grab_one(self):
108+
self.out_jpeg.seek(0)
109+
self.out_rgb.seek(0)
110+
self.jpeg_encoder.start(self.out_jpeg)
111+
self.rgb_encoder.start(self.out_rgb)
112+
if not self.jpeg_encoder.wait(10):
113+
raise picamera.PiCameraError('Timed Out')
114+
if not self.rgb_encoder.wait(10):
115+
raise picamera.PiCameraError('Timed Out')
116+
117+
def grab_stop(self):
118+
logging.debug("grab_stop")
119+
120+
with self._camera._encoders_lock:
121+
del self._camera._encoders[0]
122+
del self._camera._encoders[1]
123+
124+
self.jpeg_encoder.close()
125+
self.rgb_encoder.close()
126+
73127
def run(self):
74128
if self._camera is None:
75129
return
76130
try:
77-
self._camera.grab_start()
131+
self.grab_start()
78132
while self._run:
79133
sleep_time = CAMERA_REFRESH_INTERVAL - (time.time() - self._image_time)
80134
if sleep_time <= 0:
81135
ts = time.time()
82136
#print "run.1"
83137
self._image_lock.acquire()
84-
self._camera.grab_one()
138+
self.grab_one()
85139
self._image_lock.release()
86140
#print "run.2: " + str(time.time()-ts)
87141
#self.save_image(image.Image(self._camera.get_image_bgr()).open().binarize().to_jpeg())
88-
self.save_image(self._camera.get_image_jpeg())
142+
if self._image_cache_updated is True:
143+
self.save_image(self._image_cache.to_jpeg())
144+
self._image_cache_updated = False
145+
else:
146+
self.save_image(self.out_jpeg.getvalue())
89147
#print "run.3: " + str(time.time()-ts)
90148
else:
91149
time.sleep(sleep_time)
92150

93151
if self.recording and time.time() - self.video_start_time > VIDEO_ELAPSE_MAX:
94152
self.video_stop()
95153

96-
self._camera.grab_stop()
154+
self.grab_stop()
97155
except:
98156
logging.error("Unexpected error:" + str(sys.exc_info()[0]))
99157
raise
100158

101159
def get_image(self, maxage = MAX_IMAGE_AGE):
102160
if self._camera is None:
161+
print "get_image: Default image"
103162
return Image(cv2.imread(DEFAULT_IMAGE))
104163
else:
105-
return image.Image(self._camera.get_image_bgr())
164+
return image.Image(self.out_rgb.array)
106165

107166
def save_image(self, image_jpeg):
108167
self._streamer.set_image(image_jpeg)
@@ -111,13 +170,13 @@ def save_image(self, image_jpeg):
111170
def set_text(self, text):
112171
if self._camera is None:
113172
return
114-
self._camera.set_overlay_text(str(text))
173+
self._camera.annotate_text(str(text))
115174

116175
def get_next_photo_index(self):
117176
last_photo_index = 0
118177
for p in self._photos:
119178
try:
120-
index = int(p[len(PHOTO_PREFIX):-len(self._camera.PHOTO_FILE_EXT)])
179+
index = int(p[len(PHOTO_PREFIX):-len(self.PHOTO_FILE_EXT)])
121180
if index > last_photo_index:
122181
last_photo_index = index
123182
except:
@@ -127,21 +186,21 @@ def get_next_photo_index(self):
127186
def rotate(self):
128187
if self._camera is None:
129188
return
130-
rot = self._camera.camera.rotation
189+
rot = self._camera.rotation
131190
rot = rot + 90
132191
if rot > 271:
133192
rot = 0
134-
self._camera.camera.rotation = rot
193+
self._camera.rotation = rot
135194

136195
def photo_take(self):
137196
if self._camera is None:
138197
return
139198
photo_index = self.get_next_photo_index()
140-
filename = PHOTO_PREFIX + str(photo_index) + self._camera.PHOTO_FILE_EXT;
141-
filename_thumb = PHOTO_PREFIX + str(photo_index) + PHOTO_THUMB_SUFFIX + self._camera.PHOTO_FILE_EXT;
199+
filename = PHOTO_PREFIX + str(photo_index) + PHOTO_FILE_EXT;
200+
filename_thumb = PHOTO_PREFIX + str(photo_index) + PHOTO_THUMB_SUFFIX + PHOTO_FILE_EXT;
142201
of = open(PHOTO_PATH + "/" + filename, "w+")
143202
oft = open(PHOTO_PATH + "/" + filename_thumb, "w+")
144-
im_str = self._camera.get_image_jpeg()
203+
im_str = self.out_jpeg.getvalue()
145204
of.write(im_str)
146205
# thumb
147206
im_pil = PILImage.open(StringIO(im_str))
@@ -152,12 +211,11 @@ def is_recording(self):
152211
return self.recording
153212

154213
def video_rec(self, video_name=None):
155-
if self.is_recording():
214+
if self.recording:
156215
return
157-
self.recording = True
158216
if self._camera is None:
159217
return
160-
218+
self.recording = True
161219
if video_name is None:
162220
video_index = self.get_next_photo_index()
163221
filename = VIDEO_PREFIX + str(video_index) + self._camera.VIDEO_FILE_EXT;
@@ -328,29 +386,48 @@ def find_color(self, s_color):
328386
self._image_lock.acquire()
329387
img = self.get_image(0)
330388
self._image_lock.release()
389+
if img is None:
390+
print "Image from get_image is None!"
391+
return [0,0]
331392
bw = img.filter_color(color)
393+
contours, hierarchy = bw.find_contours()
394+
for contour in contours:
395+
img.draw_contour_bound_circle(contour)
396+
self._image_cache = img
397+
self._image_cache_updated = True
398+
if self._image_cache is None:
399+
print "Image cache is None!"
332400
#self.save_image(bw.to_jpeg())
333-
objects = bw.find_blobs(minsize=20, maxsize=1000)
334-
logging.debug("objects: " + str(objects))
335-
dist = -1
336-
angle = 180
337-
338-
if objects and len(objects):
339-
obj = objects[-1]
340-
bottom = obj.bottom
341-
logging.info("bottom: " + str(obj.center[0]) + " " +str(obj.bottom))
342-
coords = bw.transform([(obj.center[0], obj.bottom)])
343-
logging.info("coordinates: " + str(coords))
344-
x = coords[0][0]
345-
y = coords[0][1]
346-
dist = math.sqrt(math.pow(12 + (68 * (120 - y) / 100),2) + (math.pow((x-80)*60/160,2)))
347-
angle = math.atan2(x - 80, 120 - y) * 180 / math.pi
348-
logging.info("object found, dist: " + str(dist) + " angle: " + str(angle))
401+
#objects = bw.find_blobs(minsize=5, maxsize=100)
402+
#logging.debug("objects: " + str(objects))
403+
#dist = -1
404+
#angle = 180
405+
406+
#if objects and len(objects):
407+
#obj = objects[-1]
408+
#bottom = obj.bottom
409+
#logging.info("bottom: " + str(obj.center[0]) + " " +str(obj.bottom))
410+
#coords = bw.transform([(obj.center[0], obj.bottom)])
411+
#logging.info("coordinates: " + str(coords))
412+
#x = coords[0][0]
413+
#y = coords[0][1]
414+
#dist = math.sqrt(math.pow(12 + (68 * (120 - y) / 100),2) + (math.pow((x-80)*60/160,2)))
415+
#angle = math.atan2(x - 80, 120 - y) * 180 / math.pi
416+
#logging.info("object found, dist: " + str(dist) + " angle: " + str(angle))
349417
#self.save_image(img.to_jpeg())
350418
#print "object: " + str(time.time() - ts)
351-
return [dist, angle]
419+
#return [dist, angle]
420+
return [0,0]
421+
352422

353423
def sleep(self, elapse):
354424
logging.debug("sleep: " + str(elapse))
355425
time.sleep(elapse)
356426

427+
def drawCircle(self,colour,x,y):
428+
cv2.circle(self._camera.get_image_bgr(),(x,y),30,(0,0,255), -1)
429+
#cv2.circle(self.get_image(0)
430+
431+
432+
433+

0 commit comments

Comments
 (0)