I am trying to create different radio buttons for different methods of uploading an image. I created a function for running a camera and showcasing it with a button to take a picture. Whenever I call this function it works. But when I try to call it inside tk.radiobutton I get the following error.
_tkinter.TclError: image "pyimage77" doesn't exist
Here is my code. I try to create a function called camerachoice which creates a window for the camera. #
import tkinter as tk
from tkinter import filedialog
import cv2
import PIL.Image, PIL.ImageTk
import time
def camerachoice():
class App:
def __init__(self, window, window_title, video_source=0):
self.window = window
self.window.title(window_title)
self.video_source = video_source
self.vid = MyVideoCapture(self.video_source)
self.canvas = tk.Canvas(window, width = self.vid.width, height = self.vid.height)
self.canvas.pack()
self.btn_snapshot=tk.Button(window, text="Snapshot", width=50, command=self.snapshot)
self.btn_snapshot.pack(anchor=tk.CENTER, expand=True)
self.delay = 15
self.update()
self.window.mainloop()
def snapshot(self):
ret, frame = self.vid.get_frame()
if ret:
#cv2.imwrite("frame-" + time.strftime("%d-%m-%Y-%H-%M- br%S") + ".jpg", cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
cv2.imwrite("cancercheck.jpg", cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
def update(self):
ret, frame = self.vid.get_frame()
if ret:
self.photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(frame))
self.canvas.create_image(0, 0, image = self.photo, anchor = tk.NW)
self.window.after(self.delay, self.update)
class MyVideoCapture:
def __init__(self, video_source=0):
self.vid = cv2.VideoCapture(video_source)
if not self.vid.isOpened():
raise ValueError("Unable to open video source", video_source)
self.width = self.vid.get(cv2.CAP_PROP_FRAME_WIDTH)
self.height = self.vid.get(cv2.CAP_PROP_FRAME_HEIGHT)
def get_frame(self):
if self.vid.isOpened():
ret, frame = self.vid.read()
if ret:
return (ret, cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
else:
return (ret, None)
else:
return (ret, None)
def __del__(self):
if self.vid.isOpened():
self.vid.release()
#App()
App(tk.Tk(), "Tkinter and OpenCV")
root = tk.Tk()
v = tk.IntVar()
tk.Label(root,
text="""Choose method:""",
justify = tk.LEFT,
padx = 20).pack()
tk.Radiobutton(root,
text="Camera",
padx = 20,
variable=v,
command=camerachoice(),
value=2,
).pack(anchor=tk.W)
root.mainloop()
Related
I have a Tkinter multiFrame/pages application In one of the frames i have camera related work i.e when I go on the page the camera automatically start and start capturing 20 sec video recording with openCV that means when video gets 20 second long it saves video locally and then starts recording new video of 20 second now i want those videos to upload on aws when a video gets recorded and got saved locally how can i achieve that whenever a video gets record i want that video should upload to aws automatically and get deleted from local computer and than this process should again start when new 20 second video is recorded.
my code
class FrontCameraPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
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.stop= tk.Button(self.buttonFrame, text="END TRIP", font=small_Font, bg=dark_blue, fg="White")
self.stop.grid(row=2, column=0, ipadx=10, pady=(0, 5))
self.stop['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(go_to_some_page)
# setup callbacks for switching in and out events
self.bind('<<SwitchIn>>', self.start_capture)
self.bind('<<SwitchOut>>', self.stop_capture)
self.lmain = tk.Label(self.cameraFrame)
self.lmain.pack()
self.capture = None
def start_capture(self, event=None):
if self.capture is None:
#-----------------------------------
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)
# used instance variables for width and height
self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# initialize file rotation and frame counters
self.timer = 1 # file rotation counter
self.frames = 0 # frame counter
self.fourcc = cv2.VideoWriter_fourcc(*'XVID')
self.out = cv2.VideoWriter(
f'{self.timer}.avi', self.fourcc, 25, (self.width, self.height))
#-----------------------------------
self.show_frame()
print('capture started')
def stop_capture(self, event=None):
if self.capture:
self.after_cancel(self.capture)
#-----------------------------------
self.cap.release()
self.out.release()
#------------------------------
self.capture = None
print('capture stopped')
def show_frame(self):
ret, frame = self.cap.read()
if ret:
self.out.write(frame)
self.frames += 1
if self.frames >= 500:
self.out.release()
self.timer += 1
self.out.open(f'{self.timer}.avi', self.fourcc, 25, (self.width, self.height))
self.frames = 0
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)
I have a python application which have many frames/pages when I go to some some camera page I start the camera and after 20 second I want to close the video recording and start recording in a new file. basically splitting a the recording into 20 second videos.
now I have a function stop_20_seconds() function which stops the recording after 20 second and starts again. but right now I am getting multiple file without the 20 second break one after another.
my code
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.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(changepage)
# setup callbacks for switching in and out events
self.bind('<<SwitchIn>>', self.start_capture)
self.bind('<<SwitchOut>>', self.stop_capture)
self.capture = None
self.lmain = tk.Label(self.cameraFrame)
self.lmain.pack()
def start_capture(self, event=None):
if self.capture is None:
#-----------------------------------
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)
width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
self.fourcc = cv2.VideoWriter_fourcc(*'XVID')
self.out = cv2.VideoWriter('output.avi', self.fourcc, 25, (width, height))
#-----------------------------------
self.timer =0
self.show_frame()
print('capture started')
def stop_capture(self, event=None):
if self.capture:
self.after_cancel(self.capture)
#-----------------------------------
self.cap.release()
self.out.release()
#------------------------------
self.capture = None
print('capture stopped')
def show_frame(self):
ret, frame = self.cap.read()
if ret:
self.out.write(frame)
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.stop20Sec = self.after(5000, self.stop_20_seconds)
self.capture = self.after(10, self.show_frame)
def stop_20_seconds(self):
self.timer += 1
self.out.release()
width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
self.out = cv2.VideoWriter(f'{str(self.timer)}.avi', self.fourcc, 25, (width, height))
self.after_cancel(self.capture)
self.after_cancel(self.stop20Sec)
self.stop20Sec = None
self.capture = None
self.show_frame()
Actually you don't need stop_20_seconds(). Just do the output file rotation inside show_frame():
def start_capture(self, event=None):
if self.capture is None:
#-----------------------------------
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)
# used instance variables for width and height
self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# initialize file rotation and frame counters
self.timer = 1 # file rotation counter
self.frames = 0 # frame counter
self.fourcc = cv2.VideoWriter_fourcc(*'XVID')
self.out = cv2.VideoWriter(f'{self.timer}.avi', self.fourcc, 25, (self.width, self.height))
#-----------------------------------
self.show_frame()
print('capture started')
...
def show_frame(self):
ret, frame = self.cap.read()
if ret:
self.out.write(frame)
self.frames += 1 # update frame counter
if self.frames >= 500: # reach 20 seconds (20x25 frames)
self.out.release() # close current output file
self.timer += 1 # update file rotation counter
self.out.open(f'{self.timer}.avi', self.fourcc, 25, (self.width, self.height))
self.frames = 0 # reset frame counter
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)
Note: since the actual capture frame rate is not the same as the output frame rate, the actual time period in each video file may not be 20 seconds in real time.
I wrote a code in Tkinter that should execute the function of face recognition as soon as the user click on the button and simultaneously it should redirect to the next frame.
What the problem I am currently facing is, when the user clicks on the button, the face recognition function, that is in my code gen(), executes first and as soon as it terminates, it redirects to the next frame.
What I want is both should work at the same time.. Any suggestion please?
from tkinter import *
from PIL import Image, ImageTk
import cv2
import numpy as np
import os
import json
class tkinterApp(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
container = Frame(self)
container.pack(side = "top", fill = "both", expand = True)
self.frames = {}
for F in (StartPage, Page1, Page2):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky ="nsew")
self.update()
self.show_frame(StartPage)
def show_frame(self, cont):
if cont not in self.frames:
self.frames[cont] = cont(self.container, self)
frame = self.frames[cont]
frame.tkraise()
frame.event_generate("<<ShowFrame>>")
class StartPage(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
self.controller = controller
self.bind("<<ShowFrame>>", self.myStartPage)
def myStartPage(self,controller):
super(StartPage).__init__()
canvas = Canvas(self,width=2300, height=900, bd=0, highlightthickness=0, relief='ridge')
canvas.pack()
self.background = PhotoImage(file="Images/background.png")
canvas.create_image(525,425,image=self.background, tags="B")
self.bg = PhotoImage(file="Images/bg-top.png")
canvas.create_image(0,335,image=self.bg, anchor=NW)
self.my_pic1 = PhotoImage(file="Images/start000-befored.png")
obj1 = canvas.create_image(1200,290,image=self.my_pic1, anchor=NW)
recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.read('trainer/trainer.yml')
cascadePath = "Cascades/haarcascade_frontalface_default.xml"
faceCascade = cv2.CascadeClassifier(cascadePath)
font = cv2.FONT_HERSHEY_SIMPLEX
cam = cv2.VideoCapture(0)
cam.set(3, 640)
cam.set(4, 480)
minW = 0.1*cam.get(3)
minH = 0.1*cam.get(4)
def get_frame():
laebl = ""
names = ['None', 'Marcelo', 'Paula', 'Ilza', 'Z', 'W']
while True:
ret, img =cam.read()
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor = 1.2,
minNeighbors = 5,
minSize = (int(minW), int(minH)),
)
for(x,y,w,h) in faces:
cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)
label, confidence = recognizer.predict(gray[y:y+h,x:x+w])
if (confidence < 50):
label = names[label]
confidence = " {0}%".format(round(100 - confidence))
else:
label = "unknown"
confidence = " {0}%".format(round(100 - confidence))
cv2.putText(img, str(label), (x+5,y-5), font, 1, (255,255,255), 2)
cv2.putText(img, str(confidence), (x+5,y+h-5), font, 1, (255,255,0), 1)
#cv2.imshow('camera',img)
ret, jpeg = cv2.imencode('.jpg', img)
cv2.destroyAllWindows()
return label, jpeg.tobytes()
def gen():
flag = 1
while True:
label, frame = get_frame()
flag += 1
if label=="unknown" and flag > 70:
cam.release()
print("Unknown Face Detected!")
break
canvas.tag_bind(obj1, '<1>', lambda event=None : [self.controller.show_frame(Page1), gen()])
class Page1(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
self.controller = controller
self.bind("<<ShowFrame>>", self.myPage1)
def myPage1(self,controller):
super(Page1).__init__()
canvas = Canvas(self,width=2300, height=900, bd=0, highlightthickness=0, relief='ridge')
canvas.pack()
self.background = PhotoImage(file="Images/background.png")
canvas.create_image(525,425,image=self.background, tags="B")
self.bg = PhotoImage(file="Images/bg-top.png")
bg_tk = canvas.create_image(0,335,image=self.bg, anchor=NW)
self.bg1 = PhotoImage(file="Images/bg-bottom.png")
bg1_tk = canvas.create_image(0,335,image=self.bg1, anchor=NW)
self.after(3000, lambda event=None : self.controller.show_frame(Page2))
class Page2(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
self.controller = controller
self.bind("<<ShowFrame>>", self.myPage2)
def myPage2(self,controller):
super(Page1).__init__()
canvas = Canvas(self,width=2300, height=900, bd=0, highlightthickness=0, relief='ridge')
canvas.pack()
self.background = PhotoImage(file="Images/background.png")
canvas.create_image(525,425,image=self.background)
self.bg = PhotoImage(file="Images/bg-top.png")
bg_tk = canvas.create_image(0,70,image=self.bg, anchor=NW)
self.bg1 = PhotoImage(file="Images/bg-bottom.png")
bg1_tk = canvas.create_image(0,777,image=self.bg1, anchor=NW)
# Driver Code
app = tkinterApp()
app.title("My Project")
app.mainloop()
I recently started using opencv with tkinter, and I started to have some problems that I can't seem to fix by myself...
The following code is supposed to play a video file while being able to choose which sub-directory you want to sort the file in. The problems I started to have is that the number of frames per seconds seems to act weird, since some clip I play seems "lagging", or don't have the right fps.
Secondly, the code seems really messy, and thus buttons "disappear" after clicking on one for a moment.
And finally, I tried to do something so the buttons get as big as possible to fill the x axis on the bottom of the window, while the main frame, with the video playing, stays the same same size (so the video is supposed to stay in the middle, adapting his height and width to the frame size without changing the ratio) but that doesn't seems to work too.
Any help will be appreciated
PS: I am using Python 3.8 with openCV 4.1.2
Here is the code :
from tkinter import Tk, Button, Label, Frame
import os
import shutil
import cv2
from PIL import Image, ImageTk
x = 0
path = "path/to/folder"
def nbr():
global x
x += 1
text.config(text=files[x])
class ButtonX (Button):
def __init__ (self, *args, folder="", **kwargs):
super().__init__(*args, **kwargs)
self.folder = folder
self.config(command=self.moveTo)
def moveTo(self):
global x
global cap
global width
if cap.isOpened():
cap.release()
shutil.move(path + files[x], path + self.folder + "/" +files[x])
print(files[x] + " moved to " + self.folder)
nbr()
cap = cv2.VideoCapture(path+files[x])
ret, frame = cap.read()
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)*(height/cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
folders = [dI for dI in os.listdir(path) if os.path.isdir(os.path.join(path,dI))]
allfiles = os.listdir(path)
files = [ fname for fname in allfiles if fname.endswith('.webm')]
files.sort(key=len)
print(folders)
window = Tk()
window.resizable(0, 0)
window.geometry("1600x908")
back = Frame(window)
back.grid(row=1, column=1)
window.grid_rowconfigure(0, weight=1)
window.grid_rowconfigure(2, weight=1)
window.grid_columnconfigure(0, weight=1)
window.grid_columnconfigure(2, weight=1)
player = Frame(back)
player.grid(row = 0, column=0)
buttouns = Frame(back)
buttouns.grid(row = 1, column=0)
text = Label(player)
text.grid(row=0, columnspan=4, sticky='w,e,n,s', padx=5, pady=50)
cap = cv2.VideoCapture(path+files[x])
fps = cap.get(cv2.CAP_PROP_FPS)
cap.set(cv2.CAP_PROP_FPS, fps)
print(fps)
height = 600
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)*(height/cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
def show_frame():
global cap
global width
cap.set(cv2.CAP_PROP_FPS, fps)
ret, frame = cap.read()
if frame is None:
cap = cv2.VideoCapture(path+files[x])
ret, frame = cap.read()
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image).resize((width, height))
imgtk = ImageTk.PhotoImage(image = img)
text.imgtk = imgtk
text.configure(image=imgtk)
text.after(3, show_frame)
buttons = []
z = 1
y = 0
for i in range(len(folders)):
new_button = ButtonX(buttouns,text=folders[i], width=20, height=2, folder=folders[i])
buttons.append(new_button)
buttons[i].grid(row=z, column=y, sticky='w,e,n,s', padx=5, pady=5)
y += 1
if y == 4:
y = 0
z += 1
def deleted():
global cap
global width
print("deleted " + files[x])
if cap.isOpened():
cap.release()
shutil.move(path + files[x], "path/to/deleted" + files[x])
nbr()
cap = cv2.VideoCapture(path+files[x])
ret, frame = cap.read()
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)*(height/cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
def skipped():
global cap
global width
print(files[x] + " skipped")
if cap.isOpened():
cap.release()
nbr()
cap = cv2.VideoCapture(path+files[x])
ret, frame = cap.read()
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)*(height/cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
delete= Button(buttouns,text="Delete", width=20, height=2, command=deleted, foreground="red")
delete.grid(row=z+1,column=2, columnspan=2, sticky='w,e,n,s', padx=5, pady=5)
skip= Button(buttouns,text="Skip", width=20, height=2, command=skipped)
skip.grid(row=z+1, columnspan=2, sticky='w,e,n,s', padx=5, pady=5)
show_frame()
window.mainloop()
I am trying to delete a Tkinter label that is currently displaying a webcam stream made by OpenCV. I eventually made it to happen but not with the way I wanted because it just stops the stream but the last image outputted by the stream is still present. The code is this:
from Tkinter import *
import cv2
from PIL import Image, ImageTk
def Start():
width, height = 800, 600
cap = cv2.VideoCapture(0)
cap.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, width)
cap.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, height)
def show_frame():
_, frame = cap.read()
frame = cv2.flip(frame, 1)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
lmain.after(10, show_frame)
show_frame()
root = Tk()
lmain = Label(root)
lmain.pack(side = RIGHT)
Button1 = Button(root, text = "Start", command = Start)
Button1.pack(side = LEFT)
Button2 = Button(root, text = "Stop", command = Start)
Button2.pack(side = LEFT)
root.mainloop()
You may notice that the function I used to stop it is the same function I used to start it, that is because I am very clueless as on how to stop it.
The code is:
from Tkinter import *
import cv2
from PIL import Image, ImageTk
isrunning = 0
def Start():
global isrunning
if isrunning == 0:
global cap
cap = cv2.VideoCapture(0)
isrunning = 1
lmain.pack(side = RIGHT)
def show_frame():
_, frame = cap.read()
frame = cv2.flip(frame, 1)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
if isrunning == 1:
lmain.after(10, show_frame)
show_frame()
def Stop():
global isrunning
isrunning = 0
lmain.pack_forget()
def main():
Stop()
Button1.invoke()
Stop()
root = Tk()
lmain = Label(root)
Button1 = Button(root, text = "Start", command = Start)
Button1.pack(side = LEFT)
Button2 = Button(root, text = "Stop", command = main)
Button2.pack(side = LEFT)
root.mainloop()
I have tried your code, and I add some code here:
from Tkinter import *
import cv2
from PIL import Image, ImageTk
isrunning = 0
def Start():
global isrunning
if isrunning == 0:
width, height = 800, 600
cap = cv2.VideoCapture(0)
cap.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, width)
cap.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, height)
isrunning = 1
lmain.pack(side = RIGHT)
def show_frame():
_, frame = cap.read()
frame = cv2.flip(frame, 1)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
if isrunning == 1:
lmain.after(10, show_frame)
show_frame()
def Stop():
global isrunning
isrunning = 0
lmain.pack_forget()
root = Tk()
lmain = Label(root)
Button1 = Button(root, text = "Start", command = Start)
Button1.pack(side = LEFT)
Button2 = Button(root, text = "Stop", command = Stop)
Button2.pack(side = LEFT)
root.mainloop()
You can find that I add a global variable isrunning to let the function show_frame check every time. If the variable isrunning is equal to 0, the function will stop. And I also add the function Stop as the callback function of the "Stop" button which contains the code lmain.pack_forget() to remove the label.
Since the label will be removed every time when you click the "Stop" button, I move the code for adding the label to the Start function. Hope it helps.