【问题标题】:how to open camera in a tkinter frame and close only the frame/camera when needed如何在 tkinter 框架中打开相机并在需要时仅关闭框架/相机
【发布时间】:2022-01-08 14:54:05
【问题描述】:

我有一个 tkinter 多帧应用程序,该应用程序在一个页面中涉及多个页面/帧出现在屏幕上或焦点对准 当我导航到一个页面时框架正在启动,但是当我使用 frame.quit() 时它没有关闭并且始终在后台运行它会关闭整个应用程序,但我只想关闭那个相机

控制导航的主类

import tkinter as tk
import connectionPage
import startPage
// it has more than 15 pages but for example I have removed others

class tkinterApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        self.frames = {}
        self.geometry(geometry)
        self.attributes("-fullscreen", True)
        StartPage=startPage.StartPage
        ConnectionPage=connectionPage.connect_page
        FrontCameraPage = frontCameraPage.FrontCameraPage
        for F in (StartPage, ConnectionPage,FrontCameraPage):
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame(startPage.StartPage)
    def show_frame(self, cont):
        frame = self.frames[cont]
        if hasattr(frame, 'refresh'):
            frame.refresh()
        frame.tkraise()

    def get_page(self, page_class):
        return self.frames[page_class]


if __name__ == "__main__":
    app = tkinterApp()
    app.mainloop()

我的相机框架/页面

class FrontCameraPage(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller

        self.label = tk.Label(self, text="FRONT CAMERA", font=MediumFont, bg="white").grid(row = 0,column = 0,columnspan=2, sticky = "nsew")
        self.cameraFrame = tk.Frame(self, bg=gray)
        self.cameraFrame.grid(row = 1,column = 0, sticky = "nsew")
        self.buttonFrame  = tk.Frame(self,bg = "white")
        self.buttonFrame.grid(row = 1,column = 1, sticky = "nsew",padx = (10,0))

        def end_trip():
            self.cameraFrame.quit()# right now i am using quit but it is closing whole applicaiton i just want to close camera 



        self.Info = tk.Label(self.buttonFrame, text="FACE NOT\n DETECTED", font=MediumFont,bg = dark_red,fg ="white")
        self.Info.grid(row=0, column=0, ipadx=8,pady = (0,5))
        
        self.switchCamera = tk.Button(self.buttonFrame, text="SWITCH CAMERA", font=small_Font, bg=dark_blue, command=lambda: self.switch_camera(),fg ="white")
        self.switchCamera.grid(row=1, column=0, ipadx=5,pady = (0,5))

        self.endTrip = tk.Button(self.buttonFrame, text="END TRIP", font=small_Font, bg=dark_blue, command=pass = "White")
        self.endTrip.grid(row=2, column=0, ipadx=10,pady = (0,5))

        self.cancelButton = tk.Button(self.buttonFrame, text="Cancel", font=small_Font, bg=dark_blue, command=pass,fg="white")
        self.cancelButton.grid(row=3, column=0, ipadx=10)
        


    def refresh(self):
        time.sleep(1)
        width, height = 200, 200
        cap = cv2.VideoCapture(0)
        cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
        lmain = tk.Label(self.cameraFrame)
        lmain.pack()

        def show_frame():
            _, frame = cap.read()
            frame = cv2.flip(frame, 1)
            cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
            img = PIL.Image.fromarray(cv2image)
            imgtk = ImageTk.PhotoImage(image=img)
            lmain.imgtk = imgtk
            lmain.configure(image=imgtk)
            lmain.after(10, show_frame)
        show_frame()

当我更改帧并转到另一个帧或单击任何按钮时,相机应该关闭。

【问题讨论】:

  • 在所有 Pages 中,您应该创建函数 before()after() 并在主 show_frame() 中运行 frame.after() ,....旧代码,frame.before() - 所以每个当您更改页面时,页面可能会运行一些代码。而FrontCameraPage可以使用before()打开摄像头,after()可以关闭摄像头。

标签: python opencv tkinter


【解决方案1】:

其中一种方法是使用虚拟事件来通知相机框架何时被打开或关闭。

当相机框架接收到这些虚拟事件,它可以根据事件的类型开始或停止捕捉。

下面是修改后的FrontCameraPage

class FrontCameraPage(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller

        self.label = tk.Label(self, text="FRONT CAMERA", font=MediumFont, bg="white").grid(row = 0,column = 0,columnspan=2, sticky = "nsew")
        self.cameraFrame = tk.Frame(self, bg=gray)
        self.cameraFrame.grid(row = 1,column = 0, sticky = "nsew")
        self.buttonFrame  = tk.Frame(self,bg = "white")
        self.buttonFrame.grid(row = 1,column = 1, sticky = "nsew",padx = (10,0))

        self.Info = tk.Label(self.buttonFrame, text="FACE NOT\n DETECTED", font=MediumFont,bg = dark_red,fg ="white")
        self.Info.grid(row=0, column=0, ipadx=8,pady = (0,5))

        self.switchCamera = tk.Button(self.buttonFrame, text="SWITCH CAMERA", font=small_Font, bg=dark_blue, command=lambda: self.switch_camera(),fg ="white")
        self.switchCamera.grid(row=1, column=0, ipadx=5,pady = (0,5))

        self.endTrip = tk.Button(self.buttonFrame, text="END TRIP", font=small_Font, bg=dark_blue, fg = "White")
        self.endTrip.grid(row=2, column=0, ipadx=10,pady = (0,5))
        self.endTrip['command'] = self.stop_capture

        self.cancelButton = tk.Button(self.buttonFrame, text="Cancel", font=small_Font, bg=dark_blue, fg="white")
        self.cancelButton.grid(row=3, column=0, ipadx=10)
        self.cancelButton['command'] = lambda: controller.show_frame(startPage.StartPage)

        # setup callbacks for switching in and out events
        self.bind('<<SwitchIn>>', self.start_capture)
        self.bind('<<SwitchOut>>', self.stop_capture)

        self.capture = None  # task id for the capture loop

        # label for showing the captured image
        self.lmain = tk.Label(self.cameraFrame)
        self.lmain.pack()

    def start_capture(self, event=None):
        if self.capture is None:
            # create the capture object
            width, height = 200, 200
            self.cap = cv2.VideoCapture(0)
            self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
            self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
            # start the capture loop
            self.show_frame()
            print('capture started')

    def stop_capture(self, event=None):
        if self.capture:
            # stop the capture loop
            self.after_cancel(self.capture)
            self.capture = None
            # release the capture object
            self.cap.release()
            print('capture stopped')

    def show_frame(self):
        ret, frame = self.cap.read()
        if ret:
            frame = cv2.flip(frame, 1)
            cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
            img = Image.fromarray(cv2image)
            self.imgtk = ImageTk.PhotoImage(image=img)
            self.lmain.configure(image=self.imgtk)
        self.capture = self.after(10, self.show_frame)

以下是修改后的tkinterApp

class tkinterApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        ...

        self.frame = None # the current frame shown
        self.show_frame(startPage.StartPage)

    def show_frame(self, cont):
        if self.frame:
            # trigger the switching out handler of the frame
            self.frame.event_generate('<<SwitchOut>>')
        self.frame = self.frames[cont]
        self.frame.tkraise()
        # trigger the switching in handler of the frame
        self.frame.event_generate('<<SwitchIn>>')

    ...

更新:在start_capture() 中创建self.cap 并在stop_capture() 中释放它。

【讨论】:

  • 感谢您的努力和时间,但我收到了这个错误。我完全复制粘贴了您的代码,但在运行应用程序时得到了这个AttributeError: 'function' object has no attribute 'event_generate'
  • tkinterApp类里面好像有一个名为frame的类方法,否则不会出现这样的错误。哪一行导致错误?
  • 这一行导致错误self.frame.event_generate('&lt;&lt;SwitchOut&gt;&gt;'),我已经发布了tkinterApp的完整代码,你可以看到没有函数名称框架。
  • Traceback (most recent call last): File "d:tkinterApp.py", line 74, in &lt;module&gt; app = tkinterApp() File "d:tkinterApp.py", line 42, in __init__ frame = F(container, self) File "d:backCameraPage.py", line 42, in __init__ self.cancelButton = tk.Button(self.buttonFrame, text="CANCEL", font=small_Font, bg=dark_blue, command=controller.show_frame(dashboardPage.dashboard_page),fg="white") File "d:tkinterApp.py", line 58, in show_frame self.frame.event_generate('&lt;&lt;SwitchOut&gt;&gt;') AttributeError: 'function' object has no attribute 'event_generate
  • @stark 您需要在更新后的代码中添加我建议的更改和问题中的回溯。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多