class Gamelist(): def __init__(self, drive, platform): GameListData.game_list_data_json = GameListData().get_game_list() self.json_game_list_data = GameListData.game_list_data_json if drive == 'USB(*)': self.drive_to_show = '/dev_' + drive.lower().replace('(*)', '') else: self.drive_to_show = '/dev_' + drive.lower() + '/' self.platform_to_show = platform + '_games' self.WCM_BASE_PATH = AppPaths.wcm_gui self.last_selection = (None, 0) self.list_of_items = [] self.selected_title_id = None self.selected_title = None self.selected_path = None self.selected_filename = None self.drive_system_path_array = None self.is_cleared = False def create_main_frame(self, entry_field_title_id, entry_field_title, entry_field_filename, entry_field_iso_path, entry_field_platform, drive_system_array): self.entry_field_title_id = entry_field_title_id self.entry_field_title = entry_field_title self.entry_field_filename = entry_field_filename self.entry_field_iso_path = entry_field_iso_path self.entry_field_platform = entry_field_platform self.drive_system_path_array = drive_system_array self.corrected_index = [] self.main_frame = Frame() self.popup_menu = Menu(self.main_frame, tearoff=0) self.popup_menu.add_command(label="Delete", command=self.delete_selected) self.popup_menu.add_command(label="Rename", command=self.rename_selected) # self.popup_menu.add_command(label="Refetch", # command=self.refetch) # self.popup_menu.add_command(label="Select All", # command=self.select_all) s = Scrollbar(self.main_frame) self._listbox = Listbox(self.main_frame, width=465) self._listbox.bind('<Enter>', self._bound_to_mousewheel) self._listbox.bind('<Leave>', self._unbound_to_mousewheel) self._listbox.bind("<Button-3>", self.popup) # Button-2 on Aqua s.pack(side=RIGHT, fill=Y) self._listbox.pack(side=LEFT, fill=Y) s['command'] = self._listbox.yview self._listbox['yscrollcommand'] = s.set # default filters if 'ALL_games' == self.platform_to_show: # iterate all platforms for platform in self.json_game_list_data: for list_game in self.json_game_list_data[platform]: # titles in the list has been designed to be unique if '/dev_all/' == self.drive_to_show or self.drive_to_show in list_game['path']: self.add_item(list_game['title']) else: for list_game in self.json_game_list_data[self.platform_to_show]: if '/dev_all/' == self.drive_to_show or self.drive_to_show in list_game['path']: self.add_item(list_game['title']) for x in range(19 - self._listbox.size()): self.add_item('') # adding shade to every other row of the list for x in range(0, self._listbox.size()): if x % 2 == 0: self._listbox.itemconfig(x, {'fg': 'white'}, background='#001738') else: self._listbox.itemconfig(x, {'fg': 'white'}, background='#001F4C') self.label = Label(self.main_frame) self.selection_poller() return self.main_frame def selection_poller(self): self.label.after(200, self.selection_poller) self.new_selection = self._listbox.curselection() # cursor har been initiated if self._listbox.curselection() is not (): if self.new_selection[0] is not self.last_selection[0] or self.is_cleared: self.entry_fields_update(self.new_selection) self.is_cleared = False self.last_selection = self.new_selection def entry_fields_update(self, new_selection): for platform in self.json_game_list_data: for list_game in self.json_game_list_data[platform]: self.selected_title = self._listbox.get(new_selection[0]) tmp_title = list_game['title'] match = self.selected_title == str(tmp_title) if match: self.selected_title_id = str(list_game['title_id']).replace('-', '') self.selected_title = str(list_game['title']) self.selected_path = str(list_game['path']) self.selected_filename = str(list_game['filename']) self.selected_platform = str(list_game['platform']) # parse drive and system from json data path_array = filter(None, self.selected_path.split('/')) self.drive_system_path_array[0] = path_array[0] self.drive_system_path_array[1] = path_array[1] self.drive_system_path_array[2] = '/'.join(path_array[2:len(path_array)]).replace('//', '') self.entry_field_title_id.delete(0, len(self.entry_field_title_id.get())-1) self.entry_field_title_id.delete(0, END) self.entry_field_title_id.insert(0, self.selected_title_id) self.entry_field_title.delete(0, END) self.entry_field_title.insert(0, self.selected_title) self.entry_field_filename.delete(0, END) self.entry_field_filename.insert(0, self.selected_filename) self.entry_field_platform.delete(0, END) self.entry_field_platform.insert(0, self.selected_platform) return True def get_selected_path(self): return self.current_iso_path def get_listbox(self): return self._listbox def get_ascending_index(self, list_of_items, item, ignore_case=True): lo = 0 hi = len(list_of_items) if ignore_case: item = item.lower() while lo < hi: mid = (lo + hi) // 2 if item < list_of_items[mid].lower(): hi = mid else: lo = mid + 1 else: while lo < hi: mid = (lo + hi) // 2 if item < list_of_items[mid]: hi = mid else: lo = mid + 1 return lo def add_item(self, item): if item != '': self.list_of_items = self._listbox.get(0, END) # getting ascending index in order to sort alphabetically index = self.get_ascending_index(self.list_of_items, item) self._listbox.insert(index, item) else: self._listbox.insert(END, item) def get_items(self): return self.list_of_items def _bound_to_mousewheel(self, event): self._listbox.bind_all("<MouseWheel>", self._on_mousewheel) def _unbound_to_mousewheel(self, event): self._listbox.unbind_all("<MouseWheel>") def _on_mousewheel(self, event): self._listbox.yview_scroll(int(-1*(event.delta/30)), "units") def popup(self, event): try: self._listbox.selection_clear(0, END) self._listbox.selection_set(self._listbox.nearest(event.y)) self._listbox.activate(self._listbox.nearest(event.y)) finally: if self._listbox.get(self._listbox.curselection()[0]) is not '': self.popup_menu.tk_popup(event.x_root + 43, event.y_root + 12, 0) self.popup_menu.grab_release() self.popup_menu.focus_set() def delete_selected(self): import tkMessageBox game_folder_path = os.path.join(AppPaths.game_work_dir, '..') response = tkMessageBox.askyesno('Delete game folder', 'Delete \'' + self.entry_field_title.get() + '\'?\n\nFolder path: ' + os.path.realpath(game_folder_path)) # yes if response: # remove game from visual game list for i in self._listbox.curselection()[::-1]: self._listbox.delete(i) removed_index = i # remove game from json game list platform_key = self.entry_field_platform.get() + '_games' self.json_game_list_data[platform_key] = [x for x in self.json_game_list_data[platform_key] if x['title'] != self.selected_title] # update the json game list file with open(GameListData.GAME_LIST_DATA_PATH, 'w') as newFile: json_text = json.dumps(self.json_game_list_data, indent=4, separators=(",", ":")) newFile.write(json_text) # remove the game build folder too if AppPaths.game_work_dir != os.path.join(AppPaths.wcm_gui, 'work_dir'): if os.path.isdir(game_folder_path): if 'webman-classics-maker' in game_folder_path: shutil.rmtree(game_folder_path) # clear entry_fields self.clear_entries_and_path() # set cursor self._listbox.select_set(removed_index) #This only sets focus on the first item. def rename_selected(self): self.entry_field_title.selection_range(0, END) self.entry_field_title.focus_set() def select_all(self): self._listbox.selection_set(0, 'end') def clear_entries_and_path(self): self.entry_field_title_id.delete(0, len(self.entry_field_title_id.get())-1) self.entry_field_title_id.delete(0, END) self.entry_field_title.delete(0, END) self.entry_field_platform.delete(0, END) self.entry_field_filename.delete(0, END) self.is_cleared = True def get_selected_build_dir_path(self): self.build_dir_path = '' if self.selected_filename not in {'', None}: filename = self.selected_filename title_id = self.selected_title_id.replace('-', '') build_base_path = AppPaths.builds tmp_filename = filename # removes the file extension from tmp_filename for file_ext in GlobalVar.file_extensions: if filename.upper().endswith(file_ext): tmp_filename = filename[0:len(filename)-len(file_ext)] break game_folder_name = tmp_filename.replace(' ', '_') + '_(' + title_id.replace('-', '') + ')' self.build_dir_path = os.path.join(build_base_path, game_folder_name) return self.build_dir_path
class IviGui: def __init__(self, master): self.master = master master.title("U2001A power measurement") # Label and Entry for inputting relative/attenuator value self.atten = Label(master, text="Relative (dB):") self.atten.grid(row=1, column=1) self.entry = Entry(master) self.entry.insert(0, '0') self.entry.grid(row=1, column=2) # Main display label. Shows relative measurement with dot during updates self.label = Label(master, text=" \n-NaN dBm", font=("Arial", 32), height=3, width=20) self.label.grid(row=2, column=1, columnspan=2) # Smaller secondary display to show real measurement by device self.label2 = Label(master, text=" \n-NaN dBm", font=("Arial", 16)) self.label2.grid(row=3, column=1, columnspan=2) print usbtmc.list_resources() # List USBTMC resources to connect to. self.instr = usbtmc.Instrument( 'USB::10893::11032::INSTR' ) # Your device to connect to. Pick from the list. self.instr.timeout = 60 * 1000 # Some devices are slow, some configurations are slow, timeout in ms. print self.instr.ask( "*IDN?" ) # Print out what device itself thinks its name is for validation. # Keysight U2001A trigger setup - free running trigger self.instr.write("INIT[1]:CONT 1") self.instr.write("TRIG[1]:SOUR IMM") # Init the variables self.measurement = -100 self.original_background = self.entry.cget("background") # Start first measurement self.update() # This method polls the device and updates display. Polling can take long time. def update(self): self.measurement = self.instr.ask("MEAS?") #print "%.2f" % float(self.measurement) # Debug printout to check the connection. self.update_number(True) self.label.after(100, self.remove_dot) # 100 ms after getting a measurement from the device, remove the dot above the measurement. # This provided clear indication to user about when the data was updated. def remove_dot(self): self.update_number(False) self.label.after(100, self.update) # Deal with getting the relative number from the Entry and updating all the displays. def update_number(self, dot=False): try: relative_value = float(self.entry.get()) self.entry.config(background=self.original_background) if dot: self.label.config(text=".\n%.2f dBm" % (float(self.measurement) - relative_value)) else: self.label.config(text=" \n%.2f dBm" % (float(self.measurement) - relative_value)) # If the relative box shows gibberish, just display the measurement. except ValueError: self.entry.config(background="#A44") if dot: self.label.config(text=".\n%.2f dBm" % float(self.measurement)) else: self.label.config(text=" \n%.2f dBm" % float(self.measurement)) self.label2.config(text="%.2f dBm" % float(self.measurement))
class DroneGUI: def __init__(self, master): self.master = master master.title("Drone GUI") ## Initialising framework of GUI self.frame1 = Frame(master, height=480, width=200, bd=2, relief="sunken") self.frame1.grid(row=3, column=1, rowspan=15) self.frame1.grid_propagate(False) explanation_label = Label( master, justify='left', text= "How you control the drone \nW - move forwards \nS - move down \nA - move let \nD - move right \nI - move up \nK - move down \nJ - rotate counterclockwise \nL - rotate clockwise \nENTER - Takeoff/Land" ) explanation_label.grid(row=4, column=1, rowspan=15) self.abort_button = Button(master, text="ABORT", command=self.abort_auto_flight, bg="grey", fg="lightgrey", state="disabled") self.abort_button.grid(row=17, column=1) frame2 = Frame(master, height=480, width=200, bd=2, relief="sunken") frame2.grid(row=3, column=3, rowspan=15) frame2.grid_propagate(False) self.select_target_button = Button(master, text="Select target", command=self.select_target) self.select_target_button.grid(row=4, column=3) self.distance_label = Label(master, text="Distance: NA") self.distance_label.grid(row=6, column=3) self.battery_label = Label(master, text="Battery level: NA") self.battery_label.grid(row=8, column=3) header_label = Label(master, text="Choosing target for drone") header_label.grid(row=1, column=8) self.close_button = Button(master, text="Close", command=master.quit) self.close_button.grid(row=1, column=20) self.image_label = Label(text="", height=480, width=640) self.image_label.grid(row=3, column=6, columnspan=15, rowspan=15) ## Initialising variables for selecting target self.imgClick = False self.bridge = CvBridge() self.enable_video_stream = None self.prev_img = None self.select_target_bool = False self.circle_center = [None, None] ## Initialising variables for autonoumous flight self.flying = False self.auto_flying = False self.abort_bool = False ## Enabling keyboard control of drone self.master.bind("<Key>", self.move_drone) self.master.bind("<KeyRelease>", self.key_release) self.master.bind("<Return>", self.return_key_pressed) ## Initialising of publishers and subscribers self.distance_sub = rospy.Subscriber('distance', Pose, self.update_distance_label) self.pid_enable_sub = rospy.Subscriber('pid_enable', Bool, self.pid_enabled) self.battery_sub = rospy.Subscriber( 'bebop/CommonStates/BatteryLevelChanged', UInt8, self.update_battery_label) self.target_sub = rospy.Subscriber("target", Pose, self.draw_target) self.image_sub = rospy.Subscriber('/webcam/image_raw', SensorImage, self.image_subscriber_callback) self.gui_target_pub = rospy.Publisher('gui_target', Pose, queue_size=10) self.abort_pub = rospy.Publisher('abort', Bool, queue_size=10) self.drone_vel_pub = rospy.Publisher('bebop/cmd_vel', Twist, queue_size=10) self.takeoff_pub = rospy.Publisher('bebop/takeoff', Empty, queue_size=10) self.land_pub = rospy.Publisher('bebop/land', Empty, queue_size=10) rospy.init_node('gui', anonymous=True) self.rate = rospy.Rate(10) rospy.loginfo("GUI initialised") self.abort_pub.publish(self.abort_bool) def image_subscriber_callback(self, image): cv_image = CvBridge().imgmsg_to_cv2(image, "rgb8") # cv_image = cv2.cvtColor(cv_image, cv2.COLOR_BGR2RGB) if self.circle_center[0] != None: cv2.circle( cv_image, (int(self.circle_center[0]), int(self.circle_center[1])), 3, (0, 255, 0), 10) self.img = Image.fromarray(cv_image) # print("got image") def draw_target(self, data): self.circle_center = [data.position.x, data.position.y] def update_image(self): ## Updating the image from the 'drone_cam_sub.py', if it's new. The update is automatic with a frequency 20 Hz (50 ms) frequency = 20 try: if self.img != self.prev_img: self.imgtk = ImageTk.PhotoImage(self.img) self.image_label.pic = self.imgtk self.image_label.configure(image=self.imgtk) self.prev_img = self.img except: print("Image not updated") self.enable_video_stream = self.image_label.after( int(1000 / frequency), self.update_image) def select_target(self): ## Allows the user to select target, and interrupt selection if wanted if not self.select_target_bool: rospy.loginfo("User is selecting target") self.select_target_bool = True self.imgClick = True self.select_target_button.configure(text="Cancel") self.image_label.bind("<Button-1>", self.target_selected) self.image_label.configure(cursor="dotbox") else: rospy.loginfo("User cancelled selection") self.select_target_bool = False self.imgClick = False self.select_target_button.configure(text="Select target") self.image_label.unbind("<Button-1>") self.image_label.configure(cursor="") def target_selected(self, event): ## Once target has been selected, variables and functions need to be reset. ## By un-commenting line 158 control will be disabled, once autonomous flight is enabled ## (For now it is possible to interfere with the drone by using the keyboard) self.select_target_bool = False rospy.loginfo("User selected target") self.imgClick = False save_pos(event) self.publish_pos() self.update_image() self.select_target_button.configure(text="Select target") self.image_label.unbind("<Button-1>") self.image_label.configure(cursor="") #self.auto_flying = True def move_drone(self, event): ## if auto_flying = True no other option than pressing 'g' is possible if self.flying and not self.auto_flying: cmd = Twist() factor = 0.5 rospy.loginfo("User pressed " + repr(event.char)) if event.char == 'a': cmd.linear.y = factor elif event.char == 'd': cmd.linear.y = -factor elif event.char == 'w': cmd.linear.x = factor elif event.char == 's': cmd.linear.x = -factor elif event.char == 'j': cmd.angular.z = factor elif event.char == 'l': cmd.angular.z = -factor elif event.char == 'i': cmd.linear.z = factor elif event.char == 'k': cmd.linear.z = -factor elif event.char == 'g': if not self.abort_bool: self.abort_auto_flight() cmd.linear.x = -factor self.drone_vel_pub.publish(cmd) elif self.flying: if event.char == 'g': if not self.abort_bool: self.abort_auto_flight() cmd.linear.x = -factor self.drone_vel_pub.publish(cmd) def key_release(self, event): cmd = Twist() cmd.linear.x = 0 cmd.linear.y = 0 cmd.linear.z = 0 cmd.angular.z = 0 self.drone_vel_pub.publish(cmd) def return_key_pressed(self, event): ## enabling takeoff and landing if not self.flying: self.flying = True e = Empty() self.takeoff_pub.publish(e) else: self.abort_pub.publish(True) self.flying = False e = Empty() self.land_pub.publish(e) def abort_auto_flight(self): ## aborting autonousmous flight and allowing the user the have full control of the drone again rospy.loginfo("Aborting") self.abort_bool = True self.abort_pub.publish(self.abort_bool) cmd = Twist() cmd.linear.x = 0 cmd.linear.y = 0 cmd.linear.z = 0 cmd.angular.z = 0 self.drone_vel_pub.publish(cmd) def pid_enabled(self, data): ## cheching whether the move_to_target program is running data = str(data) if data == 'data: True': self.abort_button.configure(state="active", bg="grey", fg="black") if data == False and self.abort_bool == True: self.abort_bool = False self.abort_pub.publish(self.abort_bool) def update_distance_label(self, data): self.distance_label.configure( text='Distance: {:02.2f} m'.format(data.position.x)) def update_battery_label(self, data): self.battery_label.configure(text='Battery level: {}'.format(data)) def publish_pos(self): #publishing the position of the target position in pixels if not rospy.is_shutdown(): p = Pose() p.position.x = pos_x p.position.y = pos_y self.gui_target_pub.publish(p) self.rate.sleep()
class DroneGUI: def __init__(self, master): self.master = master master.title("Drone GUI") ## Initialising framework of GUI frame1 = Frame(master, height=350, width=210, bd=2, relief="sunken") frame1.grid(row=10, column=2, rowspan=6) frame1.grid_propagate(False) ## Buttons self.select_target_button = Button(master, text="Select target", command=self.select_target) self.select_target_button.grid(row=4, column=2) self.start_auto_button = Button(master, text="Start autonomous flight", command=self.start_autonomous) self.start_auto_button.grid(row=5, column=2) self.approach_button = Button(master, text="Approach target", command=self.set_approach) self.approach_button.grid(row=6, column=2) self.e1 = Entry(master) self.e1.grid(row=7, column=2) self.e1.bind("<Return>", self.get_target_distance) self.close_button = Button(master, text="Close", command=self.close_gui) self.close_button.grid(row=8, column=2) self.battery_label = Label(master, text="Battery level: NA") self.battery_label.grid(row=10, column=2) self.x_distance_label = Label(master, text="X Distance: NA") self.x_distance_label.grid(row=11, column=2) self.y_distance_label = Label(master, text="Y Distance: NA") self.y_distance_label.grid(row=12, column=2) self.z_distance_label = Label(master, text="Z Distance: NA") self.z_distance_label.grid(row=13, column=2) self.yaw_distance_label = Label(master, text="Yaw angle: NA") self.yaw_distance_label.grid(row=14, column=2) self.flight_status_label = Label(master, text="Autonomous mode: 0") self.flight_status_label.grid(row=15, column=2) header_label = Label(master, text="Choosing target for drone") header_label.grid(row=1, column=5) self.bb_data = (None, None, None, None) self.image_label = Label(text="", height=720, width=1280) # self.image_label = Label(text = "", height = 480, width = 640) # self.image_label = Label(text = "", height = 448, width = 800) # self.image_label = Label(text = "", height = 1200, width = 1600) self.image_label.grid(row=3, column=5, columnspan=15, rowspan=15) self.control_status = 0 self.xTarget = 0 ## Initialising variables for selecting target self.imgClick = False self.bridge = CvBridge() self.enable_video_stream = None self.prev_img = None self.select_target_bool = False self.circle_center = [None, None] self.pos_x = -1 self.pos_y = -1 # Subscribers self.battery_sub = rospy.Subscriber('/dji_sdk/battery_state', BatteryState, self.update_battery_label) self.target_sub = rospy.Subscriber("/visual_tracker/target", Twist, self.draw_target) self.distance_error_sub = rospy.Subscriber( "/visual_tracker/distance_error", Point, self.update_distance_error) self.image_sub = rospy.Subscriber('/camera/image_decompressed', SensorImage, self.image_subscriber_callback) self.distance_sub = rospy.Subscriber('/laser_wall/wall_position', Float32MultiArray, self.update_distance_label) # Publishers self.gui_target_pub = rospy.Publisher('/visual_tracker/gui_target', Point, queue_size=1) self.frame_pub = rospy.Publisher('/visual_tracker/frame_num', UInt8, queue_size=1) self.control_status_msg = rospy.Publisher( '/visual_tracker/target_tracking_msg', UInt8, queue_size=1) rospy.init_node('gui_v2', anonymous=False) rospy.Timer(rospy.Duration(1.0 / 30.0), self.control_status_publish_callback) rospy.loginfo("GUI initialised") def save_pos(self, event): ## updating the position of the target point from position of mouse click on image self.pos_x = event.x self.pos_y = event.y def get_target_distance(self, entry): val = int(eval(self.e1.get())) if (val < 1 or val > 5): self.e1.delete(0, 10) self.e1.insert("Invalid value") else: self.xTarget = val def close_gui(self): self.control_status = 0 msg = UInt8() for i in range(1, 10): msg.data = self.control_status self.control_status_msg.publish(msg) rospy.sleep(rospy.Duration(0.05)) self.master.quit() def control_status_publish_callback(self, time_event): self.flight_status_label.configure( text="Autonomous mode: {}".format(self.control_status)) msg = UInt8() msg.data = self.control_status self.control_status_msg.publish(msg) def start_autonomous(self): if (self.control_status < 1 and self.circle_center[0] != None): self.control_status = 1 rospy.loginfo("Autonomous tracking started") else: rospy.loginfo("No target selected") def set_approach(self): if (self.control_status > 0 and self.xTarget != 0): self.control_status = 1 + self.xTarget elif (self.xTarget == 0): rospy.loginfo("Approach distance not set") else: rospy.loginfo("No target selected or autonomous control not set") def image_subscriber_callback(self, image): cv_image = CvBridge().imgmsg_to_cv2(image, "rgb8") cv2.circle(cv_image, (640, 360), 1, (255, 0, 0), 10) if self.circle_center[0] != None: cv2.circle( cv_image, (int(self.circle_center[0]), int(self.circle_center[1])), 3, self.circ_color, 10) if self.bb_data[0] != None: cv2.rectangle(cv_image, (self.bb_data[0], self.bb_data[1]), (self.bb_data[0] + self.bb_data[2], self.bb_data[1] + self.bb_data[3]), self.circ_color, 2) self.img = Image.fromarray(cv_image) def draw_target(self, data): self.circle_center = [data.linear.x, data.linear.y] if data.linear.z: self.circ_color = (0, 255, 0) else: self.circ_color = (255, 0, 0) if data.angular.z: self.bb_data = (int(data.linear.x - data.angular.x / 2), int(data.linear.y - data.angular.y / 2), int(data.angular.x), int(data.angular.y)) else: self.bb_data = (None, None, None, None) def update_image(self): ## Updating the image from the 'drone_cam_sub.py', if it's new. The update is automatic with a frequency 20 Hz (50 ms) frequency = 30.0 try: if self.img != self.prev_img: self.imgtk = ImageTk.PhotoImage(self.img) self.image_label.pic = self.imgtk self.image_label.configure(image=self.imgtk) self.prev_img = self.img except: print("Image not updated") self.enable_video_stream = self.image_label.after( int(1000 / frequency), self.update_image) def select_target(self): ## Allows the user to select target, and interrupt selection if wanted if not self.select_target_bool: rospy.loginfo("User is selecting target") self.select_target_bool = True self.imgClick = True self.select_target_button.configure(text="Cancel") self.image_label.bind("<Button-1>", self.target_selected) self.image_label.configure(cursor="dotbox") else: rospy.loginfo("User cancelled selection") self.select_target_bool = False self.imgClick = False self.select_target_button.configure(text="Select target") self.image_label.unbind("<Button-1>") self.image_label.configure(cursor="") def target_selected(self, event): ## Once target has been selected, variables and functions need to be reset. ## By un-commenting line 158 control will be disabled, once autonomous flight is enabled ## (For now it is possible to interfere with the drone by using the keyboard) self.select_target_bool = False rospy.loginfo("User selected target") self.imgClick = False self.save_pos(event) self.publish_pos() self.update_image() self.select_target_button.configure(text="Select target") self.image_label.unbind("<Button-1>") self.image_label.configure(cursor="") def update_distance_label(self, data): self.x_distance_label.configure( text='X Distance:\n{:02.2f} m'.format(data.data[4])) self.yaw_distance_label.configure( text='Yaw angle:\n{:02.2f} deg'.format(data.data[2])) def update_distance_error(self, data): # self.x_distance_label.configure( text = 'X Distance:\n{:02.2f} m'.format(data.x)) self.y_distance_label.configure( text='Y Distance:\n{:02.2f} m'.format(data.y)) self.z_distance_label.configure( text='Z Distance:\n{:02.2f} m'.format(data.z)) def update_battery_label(self, data): self.battery_label.configure( text='Battery level:\n{} %'.format(data.percentage)) def publish_pos(self): #publishing the position of the target position in pixels if not rospy.is_shutdown(): p = Point() p.x = self.pos_x p.y = self.pos_y p.z = 0 self.gui_target_pub.publish(p) rospy.loginfo("New Gui target published (%d, %d)", self.pos_x, self.pos_y)
class ROIApp(object): def __init__(self, source_dir): self.state = "Selecting" self.image_types = ["ppm", "jpg", "jpeg", "png", "bmp"] # Add more self.source_dir = source_dir self.gt_filename = os.path.join(self.source_dir, "gt.txt") images = self.get_images() self.image_fullpaths = ( os.path.join(self.source_dir, image_filename) for image_filename in images) self.current_image_fullpath = None self.gt_file = open(self.gt_filename, 'a') self.gt_writer = csv.writer(self.gt_file, delimiter=";") self.root = Tk() self.root.bind("<Escape>", lambda e: self.quit()) self.root.bind("<KP_Enter>", self.on_kp_enter) self.root.bind("<Return>", self.on_kp_enter) self.root.wm_title("ROI Tool") self.root.protocol("WM_DELETE_WINDOW", self.quit) # Confirm? # Frame for the input field and buttons self.input_frame = Frame(self.root) self.input_frame.pack(side="top") self.label = Label(self.input_frame, text="Class:") self.label.pack(side="left") self.entry_field = Entry(self.input_frame) self.entry_field.pack(side="left") self.image_label = Label(self.root) self.image_label.pack(side="bottom") self.image_label.bind("<ButtonPress-1>", self.on_button_press) self.image_label.bind("<ButtonRelease-1>", self.on_button_release) self.image = None self.imagetk = None self.draw = None self.ref_pts = [] self.ref_start = None self.ref_pts_iter = None self.current_ref_pt = None self.gt_rows = [] try: self.next_image() except StopIteration: print("No images were found (extensions %s) " "or all the images found were already parsed, check file " "%s" % (", ".join(self.image_types), self.gt_filename)) self.quit() sys.exit(1) self.show_frame() def quit(self): self.gt_file.close() self.root.quit() def ask_for_next_category(self): """Ask for next category if another ref point exists, else move onto next image""" try: self.current_ref_pt = self.ref_pts_iter.next() self.draw.rectangle(self.current_ref_pt, outline="red") self.entry_field.select_range(0, "end") self.entry_field.focus() except StopIteration: self.state = "Selecting" try: self.next_image() except StopIteration: print( "Done, regions of interest written in %s" % self.gt_filename) self.quit() def on_kp_enter(self, event): if self.state == "Categorizing": category = self.entry_field.get() image_path = self.current_image_fullpath.split("/")[-1] data = ((image_path,) + self.current_ref_pt[0] + self.current_ref_pt[1] + (category,)) self.gt_rows.append(data) self.draw.rectangle(self.current_ref_pt, outline="blue") self.ask_for_next_category() else: self.state = "Categorizing" self.ref_pts_iter = iter(self.ref_pts) self.ref_pts = [] self.ask_for_next_category() def get_images(self): try: gt_file = open(self.gt_filename, 'r') reader = csv.reader(gt_file, delimiter=";") already_parsed = [row[0] for row in reader] except IOError: already_parsed = [] return [filename for filename in os.listdir(self.source_dir) if (filename.split(".")[-1] in self.image_types and filename not in already_parsed)] def next_image(self): self.gt_writer.writerows(self.gt_rows) self.gt_rows = [] self.current_image_fullpath = self.image_fullpaths.next() self.image = Image.open(self.current_image_fullpath) self.draw = ImageDraw.Draw(self.image) def show_frame(self): self.imagetk = ImageTk.PhotoImage(image=self.image) self.image_label.configure(image=self.imagetk) self.image_label.after(10, self.show_frame) def on_button_press(self, event): if self.state == "Selecting": self.ref_start = (event.x, event.y) def on_button_release(self, event): if self.state == "Selecting": # Make sure ROI doesn't exceed pixture coordinates and that # the corners go from top left to bottom right ref_end = (event.x, event.y) ref_pt = self.top_left_to_bottom_right(ref_end) self.ref_pts.append(ref_pt) # Draw rectangle around ROI self.draw.rectangle( self.ref_pts[-1], outline="green") def top_left_to_bottom_right(self, ref_end): """Returns the tuple: (top_left, bottom_right) where top_left and bottom_right are coordinate tuples""" x1 = max(0, min(self.ref_start[0], ref_end[0])) x2 = min(max(self.ref_start[0], ref_end[0]), self.image.size[0]) y1 = max(0, min(self.ref_start[1], ref_end[1])) y2 = min(max(self.ref_start[1], ref_end[1]), self.image.size[1]) return ((x1, y1), (x2, y2))