python - 使用带有 python 的 imagemagick 合成多组图像时的线程延迟
问题描述
我正在树莓派中构建一个应用程序,用户单击一个按钮,该应用程序在倒计时后拍摄 3 张照片,并将这 3 张照片放入照片模板中。第一次点击按预期工作,但如果我第二次点击它,它会倒计时,但直到几秒钟后才会拍照,而且我点击按钮越多,这种延迟就会越长。问题是当应用程序将 3 张照片合成到模板中时,这需要一些时间来处理,并且会延迟用于捕获照片的线程。这是因为ImageService.py的createPhotoboothImage函数中的 bash 命令无法异步执行,还是我对线程做错了什么?任何帮助或建议都会很棒!
GUIApp.py
class GUIApp:
def __init__(self):
self.root = tk.Tk()
self.root.attributes('-zoomed', True)
self.buttonCountDown = tk.Button(text='Count Down', command=self.capturePhotos)
self.buttonCountDown.pack()
self.label = tk.Label(text='Ready!', bg='#3D434F', fg='white', font=('Helvetica', 100, 'bold'))
self.label.pack(side='top', fill='both', expand=True)
self.queue = queue.Queue()
self.captureQueue = queue.Queue()
self.imageProcessQueue = queue.Queue()
self.imageService = imageService.ImageService()
self.cameraService = cameraService.CameraService()
self.imageCount = 0
self.images = []
threading.Thread(target=self.listenToCaptureQueue).start()
threading.Thread(target=self.listenToQueue).start()
threading.Thread(target=self.listenToImageProcessQueue).start()
self.root.mainloop()
def countDown(self, seconds):
for i in range(seconds, 0, -1):
self.queue.put(i)
time.sleep(1)
self.queue.put('SMILE!')
time.sleep(1)
self.captureQueue.put(True)
def listenToQueue(self):
while True:
try:
if self.queue.empty() == False:
s = self.queue.get(0)
self.label['text'] = s
elif self.queue.empty() == True:
pass
except queue.Empty:
pass
def listenToCaptureQueue(self):
while True:
try:
if self.captureQueue.empty() == False:
if self.captureQueue.get(0):
## Take a photo
self.label['text'] = 'Please wait...'
filePath = self.cameraService.captureImage()
self.images.append("%r"%filePath)
self.imageCount += 1
if self.imageCount < 3:
# Start timer again to take photo
threading.Thread(target=self.countDown, args=(3,)).start()
else:
self.buttonCountDown['state'] = 'normal'
self.label['text'] = 'Ready!'
self.imageProcessQueue.put(self.images)
elif self.captureQueue.empty() == True:
pass
except queue.Empty:
pass
def listenToImageProcessQueue(self):
while True:
try:
if self.imageProcessQueue.empty() == False:
# Composite the 3 photos to the template
images = self.imageProcessQueue.get(0)
templatePath = '/home/pi/Documents/Test/template.jpg'
destinationPath = '/home/pi/Documents/Test/compositeImage.jpg'
self.imageService.createPhotoboothImage(images, templatePath, destinationPath)
elif self.imageProcessQueue.empty() == True:
pass
except queue.Empty:
pass
def capturePhotos(self):
self.images = []
self.imageCount = 0
self.buttonCountDown['state'] = 'disabled'
threading.Thread(target=self.countDown, args=(5,)).start()
图像服务.py
class ImageService:
def createPhotoboothImage(self, images, templatePath, destinationPath):
cmd = 'convert ' + templatePath + ' \( ' + images[0] + ' -scale "18.5%" \) -geometry +53+401 -composite \( ' + images[1] + ' -scale "9.02%" \) -geometry +1205.5+401 -composite \( ' + images[2] + ' -scale "9.02%" \) -geometry +1205.5+790 -composite ' + destinationPath
subprocess.call(cmd, shell=True)
解决方案
由于全局解释器锁,线程不会在 Python 中并行运行,如果您想要并行执行,请使用进程。参见例如多处理模块。
推荐阅读
- vba - VBA - 页脚修改 - 取消链接到上一个
- python-3.x - 在 Python 中动态加载模块
- python - Python:将小于(<)运算符与“and”关键字结合使用?
- html - 隐藏元素引导程序 4.1
- iis - 无法启动 Windows 进程激活服务。错误 2
- selenium-webdriver - 自动 Chrome 隐藏 CodeceptJS WebdriverIO 测试中的文本
- sql - 如何更改 APEX 5.1 中的单行值?
- javascript - HTML 输入按钮 JS onClick
- unity3d - 根据游戏对象大小移动相机
- c# - 在页脚中显示数据库名称