Flexible module system for Camera and Gui implementations added

This commit is contained in:
Balthasar Reuter
2018-04-17 23:45:17 +02:00
parent cf9e687102
commit cb5c2d6870
9 changed files with 73 additions and 46 deletions

View File

@@ -1,20 +1,19 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from Config import Config
from PictureList import PictureList
from PictureDimensions import PictureDimensions
import Gui
from PyQt5Gui import PyQt5Gui
from PIL import Image, ImageOps
from multiprocessing import Pipe, Process from multiprocessing import Pipe, Process
from time import time, sleep, localtime, strftime from time import time, sleep, localtime, strftime
import importlib
from PIL import Image, ImageOps
from Config import Config
from PictureList import PictureList
from PictureDimensions import PictureDimensions
import camera, gui
class Photobooth: class Photobooth:
@@ -88,7 +87,7 @@ class Photobooth:
self.trigger() self.trigger()
except RuntimeError as e: except RuntimeError as e:
print('Camera error: ' + str(e)) print('Camera error: ' + str(e))
self._send.send( Gui.ErrorState('Camera error', str(e)) ) self._send.send( gui.ErrorState('Camera error', str(e)) )
return 0 return 0
@@ -109,7 +108,7 @@ class Photobooth:
tic, toc = time(), 0 tic, toc = time(), 0
while toc < self.countdownTime: while toc < self.countdownTime:
self._send.send( Gui.PreviewState( self._send.send( gui.PreviewState(
message = str(self.countdownTime - int(toc)), message = str(self.countdownTime - int(toc)),
picture = ImageOps.mirror(self._cap.getPreview()) ) ) picture = ImageOps.mirror(self._cap.getPreview()) ) )
toc = time() - tic toc = time() - tic
@@ -118,7 +117,7 @@ class Photobooth:
def showCounterNoPreview(self): def showCounterNoPreview(self):
for i in range(self.countdownTime): for i in range(self.countdownTime):
self._send.send( Gui.PreviewState( self._send.send( gui.PreviewState(
message = str(i), message = str(i),
picture = Image.new('RGB', (1,1), 'white') ) ) picture = Image.new('RGB', (1,1), 'white') ) )
sleep(1) sleep(1)
@@ -126,7 +125,7 @@ class Photobooth:
def showPose(self): def showPose(self):
self._send.send( Gui.PoseState() ) self._send.send( gui.PoseState() )
def captureSinglePicture(self): def captureSinglePicture(self):
@@ -155,43 +154,52 @@ class Photobooth:
def trigger(self): def trigger(self):
self._send.send(Gui.GreeterState()) self._send.send(gui.GreeterState())
self.setCameraActive() self.setCameraActive()
sleep(self.greeterTime) sleep(self.greeterTime)
img = self.capturePictures() img = self.capturePictures()
img.save(self.getNextFilename(), 'JPEG') img.save(self.getNextFilename(), 'JPEG')
self._send.send(Gui.PictureState(img)) self._send.send(gui.PictureState(img))
self.setCameraIdle() self.setCameraIdle()
sleep(self.displayTime) sleep(self.displayTime)
self._send.send(Gui.IdleState()) self._send.send(gui.IdleState())
def lookup_and_import(module_list, name, package=None):
result = next(((mod_name, class_name)
for config_name, mod_name, class_name in module_list
if name == config_name), None)
print(result)
if package == None:
import_module = importlib.import_module(result[0])
else:
import_module = importlib.import_module('.' + result[0], package)
if result[1] == None:
return import_module
else:
return getattr(import_module, result[1])
def main_photobooth(config, send, recv): def main_photobooth(config, send, recv):
while True: while True:
try: try:
if config.get('Camera', 'module') == 'python-gphoto2': Camera = lookup_and_import(camera.modules, config.get('Camera', 'module'), 'camera')
from CameraGphoto2 import CameraGphoto2 as Camera
elif config.get('Camera', 'module') == 'gphoto2-cffi':
from CameraGphoto2Cffi import CameraGphoto2Cffi as Camera
elif config.get('Camera', 'module') == 'gphoto2-commandline':
from CameraGphoto2CommandLine import CameraGphoto2CommandLine as Camera
elif config.get('Camera', 'module') == 'opencv':
from CameraOpenCV import CameraOpenCV as Camera
else:
raise ModuleNotFoundError('Unknown camera module "' + config.get('Camera', 'module') + '"')
with Camera() as cap: with Camera() as cap:
photobooth = Photobooth(config, cap) photobooth = Photobooth(config, cap)
return photobooth.run(send, recv) return photobooth.run(send, recv)
except BaseException as e: except BaseException as e:
send.send( Gui.ErrorState('Camera error', str(e), True) ) send.send( gui.ErrorState('Camera error', str(e)) )
event = recv.recv() event = recv.recv()
if str(event) != 'ack': if str(event) != 'ack':
print('Unknown event received: ' + str(event)) print('Unknown event received: ' + str(event))
@@ -208,8 +216,8 @@ def run(argv):
photobooth = Process(target=main_photobooth, args=(config, gui_send, event_recv), daemon=True) photobooth = Process(target=main_photobooth, args=(config, gui_send, event_recv), daemon=True)
photobooth.start() photobooth.start()
gui = PyQt5Gui(argv, config) Gui = lookup_and_import(gui.modules, config.get('Gui', 'module'), 'gui')
return gui.run(event_send, gui_recv) return Gui(argv, config).run(event_send, gui_recv)
def main(argv): def main(argv):

View File

@@ -7,7 +7,7 @@ from PIL import Image
import gphoto2 as gp import gphoto2 as gp
from Camera import Camera from . import Camera
class CameraGphoto2(Camera): class CameraGphoto2(Camera):

View File

@@ -7,7 +7,7 @@ from PIL import Image
import gphoto2cffi as gp import gphoto2cffi as gp
from Camera import Camera from . import Camera
class CameraGphoto2Cffi(Camera): class CameraGphoto2Cffi(Camera):

View File

@@ -1,11 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from Camera import Camera
from PIL import Image from PIL import Image
import os, subprocess import os, subprocess
from . import Camera
class CameraGphoto2CommandLine(Camera): class CameraGphoto2CommandLine(Camera):
def __init__(self): def __init__(self):

View File

@@ -1,11 +1,12 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from Camera import Camera
from PIL import Image from PIL import Image
import cv2 import cv2
from . import Camera
class CameraOpenCV(Camera): class CameraOpenCV(Camera):
def __init__(self): def __init__(self):

View File

@@ -1,6 +1,15 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Available camera modules as tuples of (config name, module name, class name)
modules = (
('python-gphoto2', 'CameraGphoto2', 'CameraGphoto2'),
('gphoto2-cffi', 'CameraGphoto2Cffi', 'CameraGphoto2Cffi'),
('gphoto2-commandline', 'CameraGphoto2CommandLine', 'CameraGphoto2CommandLine'),
('opencv', 'CameraOpenCV', 'CameraOpenCV') )
class Camera: class Camera:
def __init__(self): def __init__(self):
@@ -87,4 +96,4 @@ class Camera:
if not self.hasIdle: if not self.hasIdle:
raise RuntimeError('Camera does not support idle state') raise RuntimeError('Camera does not support idle state')
raise NotImplementedError() raise NotImplementedError()

View File

@@ -1,4 +1,6 @@
[Gui] [Gui]
# Gui module to use (qt5)
module = qt5
# Start Photobooth in fullscreen mode (True/False) # Start Photobooth in fullscreen mode (True/False)
fullscreen = False fullscreen = False
# Width of Photobooth (if not fullscreen) # Width of Photobooth (if not fullscreen)

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import Gui # import Gui
from PIL import ImageQt from PIL import ImageQt
@@ -9,7 +9,9 @@ from PyQt5.QtCore import Qt, QObject, QThread, pyqtSignal
from PyQt5.QtWidgets import (QApplication, QCheckBox, QComboBox, QFormLayout, QFrame, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLayout, QLineEdit, QMainWindow, QMessageBox, QPushButton, QVBoxLayout) from PyQt5.QtWidgets import (QApplication, QCheckBox, QComboBox, QFormLayout, QFrame, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLayout, QLineEdit, QMainWindow, QMessageBox, QPushButton, QVBoxLayout)
from PyQt5.QtGui import QImage, QPainter, QPixmap from PyQt5.QtGui import QImage, QPainter, QPixmap
class PyQt5Gui(Gui.Gui): from . import *
class PyQt5Gui(Gui):
def __init__(self, argv, config): def __init__(self, argv, config):
@@ -67,26 +69,26 @@ class PyQt5Gui(Gui.Gui):
def handleState(self, state): def handleState(self, state):
if not isinstance(state, Gui.GuiState): if not isinstance(state, GuiState):
raise ValueError('Invalid data received') raise ValueError('Invalid data received')
if isinstance(state, Gui.IdleState): if isinstance(state, IdleState):
self.showIdle() self.showIdle()
elif isinstance(state, Gui.GreeterState): elif isinstance(state, GreeterState):
global cfg global cfg
num_pictures = ( cfg.getInt('Picture', 'num_x') * num_pictures = ( cfg.getInt('Picture', 'num_x') *
cfg.getInt('Picture', 'num_y') ) cfg.getInt('Picture', 'num_y') )
self._p.setCentralWidget( self._p.setCentralWidget(
PyQt5PictureMessage('Will capture {} pictures!'.format(num_pictures))) PyQt5PictureMessage('Will capture {} pictures!'.format(num_pictures)))
elif isinstance(state, Gui.PreviewState): elif isinstance(state, PreviewState):
img = ImageQt.ImageQt(state.picture) img = ImageQt.ImageQt(state.picture)
self._p.setCentralWidget(PyQt5PictureMessage(state.message, img)) self._p.setCentralWidget(PyQt5PictureMessage(state.message, img))
elif isinstance(state, Gui.PoseState): elif isinstance(state, PoseState):
self._p.setCentralWidget(PyQt5PictureMessage('Pose!')) self._p.setCentralWidget(PyQt5PictureMessage('Pose!'))
elif isinstance(state, Gui.PictureState): elif isinstance(state, PictureState):
img = ImageQt.ImageQt(state.picture) img = ImageQt.ImageQt(state.picture)
self._p.setCentralWidget(PyQt5PictureMessage('', img)) self._p.setCentralWidget(PyQt5PictureMessage('', img))
elif isinstance(state, Gui.ErrorState): elif isinstance(state, ErrorState):
self.showError(state.title, state.message) self.showError(state.title, state.message)
else: else:
raise ValueError('Unknown state') raise ValueError('Unknown state')

View File

@@ -1,6 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Available gui modules as tuples of (config name, module name, class name)
modules = ( ('qt5', 'PyQt5Gui', 'PyQt5Gui'), )
class Gui: class Gui:
def __init__(self): def __init__(self):