Added saving of assembled pictures and more robust error handling

This commit is contained in:
Balthasar Reuter
2018-03-31 00:02:57 +02:00
parent 1ca0c4d322
commit fb62d2fdb2
4 changed files with 149 additions and 9 deletions

View File

@@ -21,6 +21,41 @@ class GuiState:
assert not kwargs
class ErrorState(GuiState):
def __init__(self, title, message, **kwargs):
super().__init__(**kwargs)
self.title = title
self.message = message
@property
def title(self):
return self._title
@title.setter
def title(self, title):
self._title = title
@property
def message(self):
return self._message
@message.setter
def message(self, message):
self._message = message
class IdleState(GuiState):
def __init__(self, **kwargs):
@@ -35,7 +70,7 @@ class PictureState(GuiState):
super().__init__(**kwargs)
self._pic = picture
self.picture = picture
@property
@@ -56,7 +91,7 @@ class MessageState(GuiState):
super().__init__(**kwargs)
self._msg = message
self.message = message
@property

View File

@@ -2,21 +2,26 @@
# -*- coding: utf-8 -*-
from Config import Config
from PictureList import PictureList
import Gui
from PyQt5Gui import PyQt5Gui
from CameraOpenCV import CameraOpenCV as Camera
from PIL import Image
from multiprocessing import Pipe, Process
from time import time, sleep
from time import time, sleep, localtime, strftime
output_size = (1920, 1080)
min_distance = (10, 10)
num_pictures = (2, 2)
pose_time = 2
picture_basename = strftime('%Y-%m-%d/photobooth', localtime())
class Photobooth:
@@ -25,6 +30,20 @@ class Photobooth:
self._cap = Camera()
@property
def getNextFilename(self):
return self._get_next_filename
@getNextFilename.setter
def getNextFilename(self, func):
if not callable(func):
raise ValueError('getNextFilename must be callable')
self._get_next_filename = func
def run(self, send, recv):
self._send = send
@@ -35,7 +54,11 @@ class Photobooth:
except EOFError:
return 1
else:
self.trigger()
try:
self.trigger()
except RuntimeError as e:
print('Camera error: ' + str(e))
self._send.send( Gui.ErrorState('Camera error', str(e)) )
return 0
@@ -71,10 +94,10 @@ class Photobooth:
( output_size[i] - (num_pictures[i] + 1) * min_distance[i] ) /
( num_pictures[i] * picture_size[i]) ) for i in range(2) ) )
output_picture_size = tuple( int(picture_size[0] * resize_factor)
output_picture_size = tuple( int(picture_size[i] * resize_factor)
for i in range(2) )
output_picture_dist = tuple( int( ( output_size[i] - num_pictures[i] *
output_picture_size[i] ) / (num_pictures[i] + 1) )
output_picture_dist = tuple( ( output_size[i] - num_pictures[i] *
output_picture_size[i] ) // (num_pictures[i] + 1)
for i in range(2) )
output_image = Image.new('RGB', output_size, (255, 255, 255))
@@ -93,7 +116,8 @@ class Photobooth:
def capturePictures(self):
pictures = [self.captureSinglePicture() for i in range(2) for _ in range(num_pictures[i])]
pictures = [self.captureSinglePicture()
for i in range(2) for _ in range(num_pictures[i])]
return self.assemblePictures(pictures)
@@ -103,7 +127,9 @@ class Photobooth:
sleep(2)
self._send.send(Gui.PictureState(self.capturePictures()))
img = self.capturePictures()
img.save(self.getNextFilename(), 'JPEG')
self._send.send(Gui.PictureState(img))
sleep(5)
@@ -112,7 +138,11 @@ class Photobooth:
def main_photobooth(send, recv):
picture_list = PictureList(picture_basename)
photobooth = Photobooth()
photobooth.getNextFilename = picture_list.getNext
return photobooth.run(send, recv)

66
photobooth/PictureList.py Normal file
View File

@@ -0,0 +1,66 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
from glob import glob
class PictureList:
"""A simple helper class.
It provides the filenames for the assembled pictures and keeps count
of taken and previously existing pictures.
"""
def __init__(self, basename):
"""Initialize filenames to the given basename and search for
existing files. Set the counter accordingly.
"""
# Set basename and suffix
self.basename = basename
self.suffix = '.jpg'
self.count_width = 5
# Ensure directory exists
dirname = os.path.dirname(self.basename)
if not os.path.exists(dirname):
os.makedirs(dirname)
self.findExistingFiles()
def findExistingFiles(self):
# Find existing files
count_pattern = '[0-9]' * self.count_width
pictures = glob(self.basename + count_pattern + self.suffix)
# Get number of latest file
if len(pictures) == 0:
self.counter = 0
else:
pictures.sort()
last_picture = pictures[-1]
self.counter = int(last_picture[-(self.count_width+len(self.suffix)):-len(self.suffix)])
# Print initial infos
print('Info: Number of last existing file: ' + str(self.counter))
print('Info: Saving assembled pictures as: ' + self.basename + (self.count_width * 'X') + '.jpg')
def getFilename(self, count):
return self.basename + str(count).zfill(self.count_width) + self.suffix
def getLast(self):
return self.getFilename(self.counter)
def getNext(self):
self.counter += 1
return self.getFilename(self.counter)

View File

@@ -67,6 +67,8 @@ class PyQt5Gui(Gui.Gui):
# img = QImage(state.picture, state.picture.shape[1], state.picture.shape[0], QImage.Format_RGB888)
img = ImageQt.ImageQt(state.picture)
self._p.setCentralWidget(PyQt5PictureMessage('', img))
elif isinstance(state, Gui.ErrorState):
self.showError(state.title, state.message)
else:
raise ValueError('Unknown state')
@@ -89,6 +91,13 @@ class PyQt5Gui(Gui.Gui):
self._p.setCentralWidget(PyQt5PictureMessage('Hit the button!', 'homer.jpg'))
def showError(self, title, message):
if QMessageBox.warning(self._p, title,message, QMessageBox.Ok,
QMessageBox.Ok) == QMessageBox.Ok:
self.showIdle()
class PyQt5Receiver(QThread):
notify = pyqtSignal(object)