You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

函数内使用cv2.VideoCapture()导致tkinter窗口冻结无报错如何解决

问题根因
  • Tkinter采用单线程事件驱动模型,所有界面更新、事件响应都依赖root.mainloop()主循环调度执行。你代码中的无限while循环直接抢占了主线程资源,导致主循环永远无法执行,因此窗口会直接冻结无响应。
  • 原有代码还存在隐含问题:没有保留ImageTk.PhotoImage对象的引用,Python垃圾回收机制会销毁局部变量img,就算窗口不冻结也会出现画面空白的问题。
修复实现方案

以下是符合你需求的可运行代码:点击主窗口按钮唤起Toplevel子窗口显示摄像头实时画面,所有子窗口逻辑全部封装在触发函数内,不会出现窗口冻结问题:

import tkinter as tk
import cv2
from PIL import Image, ImageTk

root = tk.Tk()
root.configure(bg='#3d3d3d')
root.geometry('300x200')

def open_camera_window():
    # 子窗口全部逻辑封装在当前触发函数内
    top = tk.Toplevel(root)
    top.title("人脸识别摄像头")
    f1 = tk.LabelFrame(top, bg='#3d3d3d')
    f1.pack(padx=10, pady=10)
    feed = tk.Label(f1)
    feed.pack()

    cap = cv2.VideoCapture(0)
    # 给Label绑定属性保存图像引用,避免被GC回收
    feed.curr_img = None

    def update_frame():
        if cap.isOpened():
            ret, img = cap.read()
            if not ret:
                return
            img = cv2.flip(img, 1)
            img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
            feed.curr_img = ImageTk.PhotoImage(Image.fromarray(img_rgb))
            feed.config(image=feed.curr_img)
            # 间隔30ms更新一次,对应约30fps,可自行调整间隔
            feed.after(30, update_frame)
    
    # 绑定子窗口关闭事件,释放摄像头资源
    def on_close_window():
        cap.release()
        cv2.destroyAllWindows()
        top.destroy()
    
    top.protocol("WM_DELETE_WINDOW", on_close_window)
    update_frame()

# 主窗口触发按钮
open_btn = tk.Button(root, text="启动人脸识别", command=open_camera_window)
open_btn.place(relx=0.5, rely=0.5, anchor=tk.CENTER)

root.mainloop()
关键改动说明
  • 移除无限while循环,改用Tkinter自带的after()方法,将帧更新操作插入到主事件队列中调度执行,不会阻塞主循环
  • 给显示画面的Label绑定属性存储PhotoImage对象,避免图像被垃圾回收导致空白
  • 绑定子窗口关闭回调,关闭时自动释放摄像头资源,避免设备被占用无法二次打开
  • 所有子窗口、摄像头调度逻辑都封装在按钮触发函数内,符合你的开发要求

内容的提问来源于stack exchange,提问作者NISH3003

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 06:06:03