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.