Simple photobooth logic implemented

This commit is contained in:
Balthasar Reuter
2018-03-30 23:11:16 +02:00
parent 2c279cbce2
commit 1ca0c4d322
5 changed files with 99 additions and 25 deletions

View File

@@ -1,2 +1,3 @@
pip install pyqt5
pip install opencv-python
pip install Pillow

View File

@@ -3,6 +3,7 @@
from Camera import Camera
from PIL import Image
import cv2
class CameraOpenCV(Camera):
@@ -14,9 +15,9 @@ class CameraOpenCV(Camera):
self.hasPreview = True
self.hasIdle = False
self._cap = cv2.VideoCapture(-1)
if not self._cap.isOpened():
raise RuntimeError('Camera could not be opened')
# self._cap = cv2.VideoCapture(0)
# if not self._cap.isOpened():
# raise RuntimeError('Camera could not be opened')
def getPreview(self):
@@ -25,9 +26,12 @@ class CameraOpenCV(Camera):
def getPicture(self):
status, frame = self._cap.read()
if not status:
raise RuntimeError('Failed to capture picture')
_, frame = self._cap.read()
# OpenCV yields frames in BGR format,
# see https://stackoverflow.com/a/32270308
return cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# OpenCV yields frames in BGR format, conversion to RGB necessary.
# (See https://stackoverflow.com/a/32270308)
return Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))

View File

@@ -6,11 +6,18 @@ 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
output_size = (1920, 1080)
min_distance = (10, 10)
num_pictures = (2, 2)
pose_time = 2
class Photobooth:
def __init__(self):
@@ -20,41 +27,87 @@ class Photobooth:
def run(self, send, recv):
self._send = send
while True:
try:
event = recv.recv()
except EOFError:
return 1
else:
self.trigger(send)
self.trigger()
return 0
def trigger(self, send):
send.send(Gui.PoseState())
sleep(2)
def showCounter(self):
if self._cap.hasPreview:
tic, toc = time(), 0
while toc < 3:
send.send( Gui.PreviewState(
message = str(3 - int(toc)),
while toc < pose_time:
self._send.send( Gui.PreviewState(
message = str(pose_time - int(toc)),
picture = self._cap.getPreview() ) )
toc = time() - tic
else:
for i in range(3):
send.send( Gui.PreviewState(str(i)) )
for i in range(pose_time):
self._send.send( Gui.PreviewState(str(i)) )
sleep(1)
send.send(Gui.PictureState(self._cap.getPicture()))
def captureSinglePicture(self):
self.showCounter()
return self._cap.getPicture()
def assemblePictures(self, pictures):
picture_size = pictures[0].size
resize_factor = min( ( (
( 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)
for i in range(2) )
output_picture_dist = tuple( int( ( 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))
idx = 0
for img in pictures:
pos = (idx % num_pictures[0], idx // num_pictures[0])
img = img.resize(output_picture_size)
offset = tuple( (pos[i] + 1) * output_picture_dist[i] +
pos[i] * output_picture_size[i] for i in range(2) )
output_image.paste(img, offset)
idx += 1
return output_image
def capturePictures(self):
pictures = [self.captureSinglePicture() for i in range(2) for _ in range(num_pictures[i])]
return self.assemblePictures(pictures)
def trigger(self):
self._send.send(Gui.PoseState())
sleep(2)
send.send(Gui.IdleState())
self._send.send(Gui.PictureState(self.capturePictures()))
sleep(5)
self._send.send(Gui.IdleState())
def main_photobooth(send, recv):

View File

@@ -3,6 +3,8 @@
import Gui
from PIL import ImageQt
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.QtGui import QImage, QPainter, QPixmap
@@ -56,13 +58,15 @@ class PyQt5Gui(Gui.Gui):
if isinstance(state, Gui.IdleState):
self.showIdle()
elif isinstance(state, Gui.PoseState):
self._p.setCentralWidget(PyQt5PictureMessage('Pose!'))
self._p.setCentralWidget(PyQt5PictureMessage('Will capture 4 pictures!'))
elif isinstance(state, Gui.PreviewState):
img = QImage(state.picture, state.picture.shape[1], state.picture.shape[0], QImage.Format_RGB888)
# img = QImage(state.picture, state.picture.shape[1], state.picture.shape[0], QImage.Format_RGB888)
img = ImageQt.ImageQt(state.picture)
self._p.setCentralWidget(PyQt5PictureMessage(state.message, img))
elif isinstance(state, Gui.PictureState):
img = QImage(state.picture, state.picture.shape[1], state.picture.shape[0], QImage.Format_RGB888)
self._p.setCentralWidget(PyQt5PictureMessage('', QPixmap.fromImage(img)))
# 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))
else:
raise ValueError('Unknown state')
@@ -402,7 +406,11 @@ class PyQt5PictureMessage(QFrame):
painter.begin(self)
if self._picture != None:
pix = QPixmap(self._picture).scaled(self.rect().size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
if isinstance(self._picture, QImage):
pix = QPixmap.fromImage(self._picture)
else:
pix = QPixmap(self._picture)
pix = pix.scaled(self.rect().size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
painter.drawPixmap(pix.rect(), pix, pix.rect())
painter.drawText(event.rect(), Qt.AlignCenter, self._message)

View File

@@ -19,3 +19,11 @@ exit_channel = 24
trigger_channel = 23
# Pin 7 (Channel 4) switches the lamp on and off
lamp_channel = 4
[Photobooth]
# Show preview while posing time (True/False)
preview = True
# Number of pictures in horizontal direction
num_pic_x = 2
# Number of pictures in vertical direction
num_pic_y = 2