简体   繁体   中英

How to change a variable inside of loop with button ? (Tkinter and python)

I am trying to make object tracking example with user interface. I need a few buttons for changing the way of code. But the code below does not working as I expected. The boolean variables must change because I can see the button fuctions forking when I press buttons but it does't effect the loop that works continiously. If there is someone knows what am I missing could you tell me? Thanks for your help.

import PIL
from PIL import Image, ImageTk
import Tkinter as tk
import argparse
import datetime
import cv2
import serial
import time
import os
import sys

#Start_Tracking = tk.BooleanVar
#Start_Tracking.set(False)
p1 = (310,230)
p2 = (330,250)

global Start_Tracking
Start_Tracking = False
tracker = cv2.TrackerKCF_create()

class Application:
    def __init__(self, output_path = "./"):
        self.vs = cv2.VideoCapture(0) 
    self.vs.set(3,640)
    self.vs.set(4,320)
        self.output_path = output_path
        self.current_image = None

        self.root = tk.Tk()  # initialize root window
        self.root.title("Object Tracking GUI")  # set window title
        # self.destructor function gets fired when the window is closed
        self.root.protocol('WM_DELETE_WINDOW', self.destructor)
        self.panel = tk.Label(self.root)  # initialize image panel
        self.panel.pack(padx=10, pady=10)
        self.root.config(cursor="arrow")

        # create a button, that when pressed, tracking will start
        sel_btn = tk.Button(self.root, text='Select A Target', command=self.select_target)
        sel_btn.pack(fill="both", expand=True, padx=10, pady=10)
        # create a button, that when pressed, tracking will end
        rel_btn = tk.Button(self.root, text="Release Selected Target", command=self.release_target)
        rel_btn.pack(fill="both", expand=True, padx=10, pady=10)

        # start a self.video_loop that constantly pools the video sensor
        # for the most recently read frame
        self.video_loop()


    def video_loop(self):
    if not Start_Tracking:
            ok, frame = self.vs.read()  # read frame from video stream
        cv2.rectangle(frame, p1, p2, (0,0,200))
#            frame = cv2.resize(frame, (1500,1000))
            if ok:  # frame captured without any errors
                cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)  # convert colors from BGR to RGBA
                self.current_image = Image.fromarray(cv2image)  # convert image for PIL
                #self.current_image= self.current_image.resize([1280,1024],PIL.Image.ANTIALIAS)
                imgtk = ImageTk.PhotoImage(image=self.current_image)  # convert image for tkinter 
                self.panel.imgtk = imgtk  # anchor imgtk so it does not be deleted by garbage-collector  
                self.panel.config(image=imgtk)  # show the image
                #self.root.attributes("-fullscreen",True)
    else:
            ok, frame = self.vs.read() # do nothing for now

        self.root.after(1, self.video_loop)

    def select_target(self):
        """ Take snapshot and save it to the file """
    Start_Tracking=True
    tracker = cv2.TrackerKCF_create()
    print("Start Pressed")

    def release_target(self):
        """ Take snapshot and save it to the file """
    Start_Tracking=False
    tracker.clear()
    print("Release Pressed")

    def destructor(self):
        """ Destroy the root object and release all resources """
        print("[INFO] closing...")
        self.root.destroy()
        self.vs.release()  # release web camera
        cv2.destroyAllWindows()  # it is not mandatory in this application

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-o", "--output", default="./",
    help="path to output directory to store snapshots (default: current folder")
args = vars(ap.parse_args())

# start the app
print("[INFO] starting...")
pba = Application(args["output"])
pba.root.mainloop()

When you assign Start_Tracking = True within your class, you're assigning it locally within the class as opposed to the global attribute as you expected. See this documentation for more details .

To update the global attribute, you have to first declare it is a global variable before assignment:

def select_target(self):
        """ Take snapshot and save it to the file """
    global Start_Tracking
    Start_Tracking = True
    tracker = cv2.TrackerKCF_create()
    print("Start Pressed")

def release_target(self):
        """ Take snapshot and save it to the file """
    global Start_Tracking
    Start_Tracking=False
    tracker.clear()
    print("Release Pressed")

However, I would argue it's not a good practice to have an instance method handle global attributes.

A better approach would be having the Start_Tracking as an instance attribute instead so you reference it within the scope of class Application as self.Start_Tracking , that way you have more control and avoid messy namespace handling. You can also define it as a class attribute instead of instance attribute , but that would give you a similar headache so personally I wouldn't do that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM