Flexible module system for Camera and Gui implementations added
This commit is contained in:
@@ -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):
|
||||||
|
|||||||
@@ -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):
|
||||||
@@ -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):
|
||||||
@@ -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):
|
||||||
@@ -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):
|
||||||
@@ -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()
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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')
|
||||||
@@ -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):
|
||||||
Reference in New Issue
Block a user