Trying to close the camera with a button using opencv and tkinter

I have it so the camera is linked to the first button, and when you click that, it should open the camera. I’m also attempting to create another button that when you click that, it will close the camera. How is that suppose to work? I am using opencv, tkinter, and PIL.

Here is my code

import cv2
import numpy as np
from time import sleep
from tkinter import *
from PIL import Image
from PIL import ImageTk


white       = "#ffffff"
lightBlue2  = "#adc5ed"
font        = "Constantia"
WIDTH       = 1920
HEIGHT      = 1080
fontButtons = (font, 12)
maxWidth    = 1000
maxHeight   = 600
mainWindow = Tk()
mainWindow.title('RocketShip')
mainWindow.configure(width = WIDTH, height = HEIGHT, bg="black")
mainFrame = Frame(mainWindow, height = 640, width = 810)
mainFrame.place(x=350,y=0)
cameraFrame = Frame(mainWindow, height = 640, width = 405)
cameraFrame.place(x = 0, y = 0)
lmain = Label(mainFrame)

cap = cv2.VideoCapture(0)    

def show_frame():
    lmain = Label(mainFrame)
    ret, frame = cap.read()    
    cv2image   = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)    
    img   = Image.fromarray(cv2image).resize((810,640))
    imgtk = ImageTk.PhotoImage(image=img)    
    lmain.grid(row=0, column=0)    

    lmain.grid(row=0, column=0)    
    lmain.imgtk = imgtk    
    lmain.configure(image=imgtk)    
    lmain.after(10, show_frame)







#Buttons
TurnCameraOn = Button(cameraFrame, width = 405, height = 25, bg = "blue", command = show_frame)
TurnCameraOn.place(x = 0, y = 0)
TurnCameraOff = Button(cameraFrame, width = 405, height = 25, bg = "blue")
TurnCameraOff.place(x = 0, y = 300)

#file menu    
menubar = Menu(mainWindow)    
file = Menu(menubar, tearoff = 0)    
menubar.add_cascade(label ='Commands', menu = file)    
file.add_command(label ='Open Camera', command = show_frame)     
file.add_separator()    
file.add_command(label ='Exit', command = lambda:mainWindow.destroy())    
mainWindow.config(menu = menubar)    
mainWindow.mainloop()

Answer

You can use a flag. Set the flag to True when you want the camera to start and set it to False when you want to stop the loop, then use VideoCapture.release() to close the capturing device.

Here is an example

import cv2
from tkinter import *
from PIL import Image, ImageTk


cam_on = False
cap = None
mainWindow = Tk()


mainFrame = Frame(mainWindow, height = 640, width = 810)
mainFrame.place(x=350,y=0)

cameraFrame = Frame(mainWindow, height = 640, width = 405)
cameraFrame.place(x = 0, y = 0)
   

def show_frame():

    if cam_on:

        ret, frame = cap.read()    

        if ret:
            cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)    
            img = Image.fromarray(cv2image).resize((810,640))
            imgtk = ImageTk.PhotoImage(image=img)        
            vid_lbl.imgtk = imgtk    
            vid_lbl.configure(image=imgtk)    
        
        vid_lbl.after(10, show_frame)

def start_vid():
    global cam_on, cap
    stop_vid()
    cam_on = True
    cap = cv2.VideoCapture(0) 
    show_frame()

def stop_vid():
    global cam_on
    cam_on = False
    
    if cap:
        cap.release()

vid_lbl = Label(mainFrame)
vid_lbl.grid(row=0, column=0)

#Buttons
TurnCameraOn = Button(cameraFrame, text="start Video", bg = "blue", command=start_vid)
TurnCameraOn.place(x = 0, y = 0)
TurnCameraOff = Button(cameraFrame, text="stop Video", bg = "blue", command=stop_vid)
TurnCameraOff.place(x = 0, y = 300)

mainWindow.mainloop()