Simple photobooth logic implemented
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
pip install pyqt5
|
||||
pip install opencv-python
|
||||
pip install Pillow
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user