【问题标题】:Why is loop not stopping in seperate thread?为什么循环不在单独的线程中停止?
【发布时间】:2021-05-06 04:25:50
【问题描述】:

我正在尝试使用 tkinter 并使用 OpenCV 构建一个简单的视频应用程序。我正在使用线程从相机捕获视频帧,将它们转换为 PIL 图像并将它们设置为 Tkinter 标签中的图像。该应用程序运行良好,包括按钮,尽管当我尝试关闭 Tkinter 窗口时出现问题。我使用协议来执行此操作,并将全局变量 enablecam 设置为 false,这应该会停止循环和摄像头,但相反,它只是关闭 Tkinter 窗口并且摄像机继续运行。我也尝试将变量记录到控制台,但是一旦关闭 Tkinter 窗口,程序就会停止将输出记录到控制台。我不确定为什么或如何发生这种情况,但我怀疑它可能与全局变量有关。我也尝试过root.quit() 而不是root.destroy(),但这只会使窗口崩溃。 这是应用程序的代码 -

import tkinter as tk
import threading
import cv2
from PIL import Image, ImageTk
import time
from imutils.video import VideoStream

img = cv2.imread('img_avatar.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img2 = Image.fromarray(img)
enablecam = True
print(img2)

root = tk.Tk()

label = tk.Label(root, text="Video Camera Application")
label.grid(row=0, column=0)

img3 = ImageTk.PhotoImage(img2)

image = tk.Label(root, image=img3)
image.grid(row=1, column=0)


def capture_video():
    video = VideoStream().start()
    time.sleep(2)

    global img2, enablecam, image, img3, img

    while enablecam:
        frame = video.read()

        try:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            img2 = Image.fromarray(frame)

            img3 = ImageTk.PhotoImage(img2)
            image.configure(image=img3)
            image.image = img3
        except Exception as e:
            video.stop()
            break
    img2 = Image.fromarray(img)

    img3 = ImageTk.PhotoImage(img2)
    image.configure(image=img3)
    image.image = img3
    video.stop()


use_camera = threading.Thread(target=capture_video)
use_camera.start()


def handleCam():
    global use_camera, enablecam, img3, img2, image, img
    if enablecam:
        enablecam = False
        img2 = Image.fromarray(img)

        img3 = ImageTk.PhotoImage(img2)
        image.configure(image=img3)
        image.image = img3
    else:
        enablecam = True
        use_camera = threading.Thread(target=capture_video)
        use_camera.start()


cambtn = tk.Button(text='Enable Cam', command=handleCam)
cambtn.grid(row=2, column=0)


def on_closing():
    global enablecam, img3, img2, image, img, root

    if enablecam:
        enablecam = False
        img2 = Image.fromarray(img)

        img3 = ImageTk.PhotoImage(img2)
        image.configure(image=img3)
        image.image = img3

    root.destroy()


root.protocol("WM_DELETE_WINDOW", on_closing)

root.mainloop()

如果您能帮我解决这个问题,那就太好了,在此先感谢。

【问题讨论】:

  • 您无法从主线程外部更新您的 UI。您需要使用root.after 在主线程中触发一个函数。在停止事情以确保线程退出后,您应该执行use_camera.join()。但实际上,你应该做的是扔掉Tkinter。它一直是一种 hack,Python 多年来一直试图摆脱它。使用真正的 UI 框架,例如 Qt 或 wxWidgets。
  • 但是上面的代码示例可以工作,我可以从一个单独的线程更新 Tkinter UI。当我尝试退出程序时出现问题,视频源没有停止
  • on_closing() 函数中将 root.destroy() 更改为 root.after(100, root.destroy) 以让 tkinter 处理未决事件。
  • 我试过了,还是不行
  • 它对我有用,可以将值 100 调整为更大的值,然后重试。

标签: python opencv tkinter python-multithreading


【解决方案1】:

发生这种情况是因为 while 循环没有收到任何命令 enablecam = False。保持循环,我认为它应该可以工作。

【讨论】:

  • 我可以在哪里添加这个循环?
  • 哎,我的错,我之前没看懂。但是 acw1668 的 root.after(100, root.destroy)root.update 都工作正常。
猜你喜欢
  • 1970-01-01
  • 2013-10-17
  • 2020-12-16
  • 1970-01-01
  • 2016-08-22
  • 1970-01-01
  • 1970-01-01
  • 2015-01-10
  • 1970-01-01
相关资源
最近更新 更多