def init_gui(self, cim):
        """Make a new tkinter window"""
        root = Tk()
        root.grid_rowconfigure(0, weight=1)
        root.columnconfigure(0, weight=1)
        root.title(cim)
        root.resizable(False, True)
        frame_main = Frame(root)
        frame_main.grid(sticky='news')

        # Create a frame for the canvas with non-zero row&column weights
        frame_canvas = Frame(frame_main)
        frame_canvas.grid(row=0, column=0)
        frame_canvas.grid_rowconfigure(0, weight=1)
        frame_canvas.grid_columnconfigure(0, weight=1)
        # Set grid_propagate to False to allow 5-by-5 buttons resizing later
        frame_canvas.grid_propagate(False)

        # Add a canvas in that frame
        canvas = Canvas(frame_canvas)
        canvas.grid(row=0, column=0)
        canvas.pack(fill="both", expand=True)

        # Link a scrollbar to the canvas
        vsb = Scrollbar(frame_canvas, orient="vertical", command=canvas.yview)
        vsb.grid(row=0, column=1, sticky='ns')
        canvas.configure(yscrollcommand=vsb.set)

        # Create a frame to contain the scrollable content
        frame_progress = Frame(canvas)
        canvas.create_window((0, 0), window=frame_progress, anchor='nw')
        self.canvas = canvas
        self.frame_main = frame_main

        for process in self.process_list:
            self.init_new_progressbar(frame_progress,
                                      p_length=300,
                                      p_process=process)
        frame_progress.update_idletasks()
        p = self.process_list[0]
        frame_width = p['task_label'].winfo_width(
        ) + p['progressbar'].winfo_width() + p['status_label'].winfo_width()
        rows = 20 if len(self.process_list) > 20 else len(self.process_list)
        frame_height = (p['progressbar'].winfo_height() * rows)
        frame_canvas.config(width=frame_width + vsb.winfo_width(),
                            height=frame_height)
        canvas.config(width=frame_width + vsb.winfo_width(),
                      height=frame_height)
        canvas.config(scrollregion=canvas.bbox("all"))
        canvas.update()

        self.frame_main.bind("<Configure>", self.configure)

        return root
Exemplo n.º 2
0
class ToolBox(ttk.Labelframe):
	def __init__(self, *args, **kwargs):
		ttk.Labelframe.__init__(self, *args, text = "Tools")
		self.config(height = 200, width = 200)
		self.bind("<MouseWheel>", self._on_mouse_wheel)
		self.eyedropper_symbol = load_tk_image_from_bytes_array(eyedropper_symbol_gray_bytes)
		self.pencil_symbol = load_tk_image_from_bytes_array(pencil_symbol_gray_bytes)
		self.updownleftright = load_tk_image_from_bytes_array(updownleftright_symbol_gray_bytes)
		self.updownarrow_symbol = load_tk_image_from_bytes_array(updownarrow_symbol_gray_bytes)
		self.leftrightarrow_symbol = load_tk_image_from_bytes_array(leftrightarrow_symbol_gray_bytes)
		self.bucket_symbol = load_tk_image_from_bytes_array(bucket_symbol_gray_bytes)
		self.eraser_symbol = load_tk_image_from_bytes_array(eraser_symbol_gray_bytes)
		self.line_symbol = load_tk_image_from_bytes_array(line_symbol_gray_bytes)
		self.rectangle_symbol = load_tk_image_from_bytes_array(rectangle_symbol_bytes)
		self.filled_rectangle_symbol = load_tk_image_from_bytes_array(filled_rectangle_bytes)
		self.select_box_symbol = load_tk_image_from_bytes_array(select_box_symbol_bytes)
		self.ellipse_symbol = load_tk_image_from_bytes_array(ellipse_symbol_bytes)
		self.filled_ellipse_symbol = load_tk_image_from_bytes_array(filled_ellipse_symbol_bytes)
		self.move_selection_symbol = load_tk_image_from_bytes_array(move_selection_symbol_bytes)
		self.paste_symbol = load_tk_image_from_bytes_array(paste_symbol_bytes)

		self.tool_symbol_map = {
			TOOLCONST.DRAW : self.pencil_symbol,
			TOOLCONST.LINE : self.line_symbol,
			TOOLCONST.SELECT_BOX : self.select_box_symbol,
			TOOLCONST.MOVE_SELECTION : self.move_selection_symbol,
			TOOLCONST.RECTANGLE : self.rectangle_symbol,
			TOOLCONST.FILLED_RECTANGLE: self.filled_rectangle_symbol,
			TOOLCONST.ELLIPSE : self.ellipse_symbol,
			TOOLCONST.FILLED_ELLIPSE : self.filled_ellipse_symbol,
			TOOLCONST.BUCKET : self.bucket_symbol,
			TOOLCONST.DRAW_ROW : self.leftrightarrow_symbol,
			TOOLCONST.DRAW_COLUMN : self.updownarrow_symbol,
			# TOOLCONST.EYEDROPPER : self.eyedropper_symbol,
			TOOLCONST.ERASE : self.eraser_symbol,
			TOOLCONST.PASTE : self.paste_symbol,
		}

		self.thumbnails = []
		self.tiles = []
		self.canvas_height = 200
		self.canvas = ResizableCanvas(self, relief="sunken")
		self.canvas.config(width = 200, height = 200, highlightthickness=0)

		self.scrollbar = Scrollbar(self)
		self.scrollbar.config(command=self.on_scroll_bar)      

		self.canvas.config(yscrollcommand=self.scrollbar.set) 
		self.scrollbar.pack(side="right", fill="y")
		self.canvas.pack(side = "right", expand=True, fill="both")
		self.canvas_frame = Frame(self.canvas, border = 0, highlightthickness = 0)
		self.canvas_frame.bind("<MouseWheel>", self._on_mouse_wheel)
		self.canvas_frame.config(width= 200, height = self.canvas_height)
		self.canvas.create_window(0,0, window=self.canvas_frame, anchor='nw')
		self.canvas.bind("<MouseWheel>", self._on_mouse_wheel)
		self.canvas.config(scrollregion=(0,0, 200, self.canvas_height))
		self.canvas.bind("<Enter>", self.mouse_enter)
		self.canvas.bind("<Leave>", self.mouse_leave)
		self.canvas.bind("<Motion>", self.on_mouse_move)
		self.canvas.bind("<Button-1>", self.on_click)
		self.canvas.bind("<Configure>", self.on_configure)

		if kwargs.get("controller"): self.controller = kwargs.pop("controller")
		else: self.controller = ToolController
		self.canvas.after_idle(self.refresh)

	def on_configure(self, event = None):
		self.refresh()
		self.canvas.config(
			width=self.winfo_width(),
			height=self.winfo_height(),
			highlightthickness=0)

	def mouse_enter(self, event): pass
	def mouse_leave(self, event): pass
	def on_click(self, event):
		y = int(event.y + (float(self.canvas.yview()[0]) * self.canvas_height))
		x = event.x
		for t in self.tiles:
			if t.is_in_range(x,y):
				ToolController.set_tool(t.tool)
				self.refresh()
			else: t.deactivate()

	def on_mouse_move(self, event):
		y = int(event.y + (float(self.canvas.yview()[0]) * self.canvas_height))
		x = event.x
		for t in self.tiles:
			if t.is_in_range(x,y):
				if t.active: continue
				else: t.activate()
			else: t.deactivate()

	def refresh(self, event = None):
		self.canvas.delete("all")
		self.thumbnails = []
		self.tiles = []

		self.canvas.delete("all")
		BUTTONWIDTH = 25.0
		padding = 10.0
					   
		x_spacing = BUTTONWIDTH + padding
		y_spacing = BUTTONWIDTH + padding
		y_space_offset = padding
		#Set the width 
		_framewidth = self.canvas.winfo_width() - self.scrollbar.winfo_width()
		self.canvas_frame.config(width=_framewidth)
		#Get integer number of tiles fittable in the window
		_maxperrow = _framewidth // x_spacing
		#If there's not enough room to build anything
		if not _maxperrow:
			return
		empty_space = _framewidth - (_maxperrow * x_spacing)
		space_offset = empty_space / (_maxperrow + 1)
		_y = 0
		_x = 0
		for t in self.tool_symbol_map:
			base_y = _y * y_spacing + padding + (_y + 1) * (y_space_offset)
			base_x = _x * x_spacing + padding + (_x + 1) * (space_offset)

			tt = ToolTile(self, t, self.tool_symbol_map[t])
			self.tiles.append(tt)
			tt.set_dimensions(base_x,  base_y, x_spacing, y_spacing)
			self.place_tile(tt)
			_x += 1
			if _x == _maxperrow:
				_x = 0
				_y += 1
		_y += 1
		_canvasheight = _y * y_spacing + padding + (_y + 1) * (y_space_offset)
		if _canvasheight < self.winfo_height():
			_canvasheight = self.winfo_height()
		self.canvas_frame.config(height = _canvasheight,width= _framewidth)
		self.canvas.config(scrollregion=(0,0,_framewidth, _canvasheight))
		tool = TOOLS[ToolController.tool]["text"]
		self.configure(text = f"Tools - {tool}")
		

	def place_tile(self, tile):
		tn = tile.thumbnail
		self.thumbnails.append(tn)
		tile.references.append(self.canvas.create_image(tile.x + 4, tile.y + 4, anchor = "nw", image = tn))
		if tile.active: self.activate_tile()
		if tile.tool == ToolController.tool: self.select_tile(tile)

	def select_tile(self, tile):
		self.canvas.create_rectangle(tile.x, tile.y, tile.x + tile.width, tile.y + tile.height, outline="#000000", width = 2),
		
	def activate_tile(self, tile):
		tile.active_references.extend([
			self.canvas.create_rectangle(tile.x, tile.y, tile.x + tile.width, tile.y + tile.height, outline="#000000", width = 1),
		])

	def deactivate_tile(self, tile):
		for r in tile.active_references:
			self.canvas.delete(r)

	def _on_mouse_wheel(self, event):
		if platform.system() == 'Windows':
			self.canvas.yview_scroll(-1 * int(event.delta / 120), 'units')
		elif platform.system() == 'Darwin':
			self.canvas.yview_scroll(-1 * int(event.delta), 'units')
		else:
			if event.num == 4:
				self.canvas.yview_scroll(-1, 'units')
			elif event.num == 5:
				self.canvas.yview_scroll(1, 'units')

	def on_scroll_bar(self, move_type, move_units, __ = None):
		if move_type == "moveto":
			self.canvas.yview("moveto", move_units)
Exemplo n.º 3
0
class StartPage(Frame):
    def __init__(self, controller, *args, **kwargs):
        ttk.Frame.__init__(self, *args, **kwargs)
        self.controller = controller
        self.repos = []
        self.thumbnails = []
        self.tiles = []
        self.apppage = None

        canvas_container = Frame(self)
        canvas_container.pack(side="top", fill="both", expand=True)
        self.canvas_height = 720
        self.canvas_width = 1080
        self.canvas = ResizableCanvas(canvas_container,
                                      relief="sunken",
                                      background="#333333")
        self.canvas.config(width=self.canvas_width,
                           height=self.canvas_height,
                           highlightthickness=0)
        self.scrollbar = Scrollbar(canvas_container)
        self.scrollbar.config(command=self.on_scroll_bar)
        self.canvas.config(yscrollcommand=self.scrollbar.set)
        self.scrollbar.pack(side="right", fill="y")
        self.canvas.pack(side="right", expand=True, fill="both")
        self.canvas_frame = Frame(self.canvas, border=0, highlightthickness=0)
        self.canvas_frame.bind("<MouseWheel>", self._on_mouse_wheel)
        self.canvas_frame.config(width=self.canvas_width,
                                 height=self.canvas_height)
        self.canvas.create_window(0, 0, window=self.canvas_frame, anchor='nw')
        self.canvas.bind("<MouseWheel>", self._on_mouse_wheel)
        self.canvas.config(scrollregion=(0, 0, self.canvas_height,
                                         self.canvas_height))
        # self.canvas.bind("<Enter>", self.mouse_enter)
        # self.canvas.bind("<Leave>", self.mouse_leave)
        self.canvas.bind("<Motion>", self.mouse_move)
        self.canvas.bind("<Button-1>", self.on_click)
        self.canvas.bind("<Configure>", self.on_configure)
        self.bind("<MouseWheel>", self._on_mouse_wheel)
        self.refresh()

    def on_configure(self, event=None):
        self.refresh()
        self.canvas.config(width=self.winfo_width(),
                           height=self.winfo_height(),
                           highlightthickness=0)

    # def mouse_enter(self, event): pass
    # def mouse_leave(self, event): pass

    def load_repo(self, repo):
        waiting_frame = Frame(self, background="#333333")
        waiting_frame.place(relwidth=1, relheight=1)
        print(f"Loading repo {repo.name}")
        # waiting_text = Label(waiting_frame,
        # 	text = "Please wait while the repo loads...",
        # 	font = font.Font(size = 46, weight = "bold"),
        # 	background = "#333333",
        # 	foreground = "#CCCCCC",
        # )
        # waiting_text.place(
        # 	relwidth = 1,
        # 	relheight = 1
        # )
        waiting_text = Text(
            waiting_frame,
            wrap="word",
            background="#333333",
            foreground="#CCCCCC",
            borderwidth=0,
            highlightthickness=0,
            font=font.Font(size=46, weight="bold"),
        )
        waiting_text.tag_configure("center", justify='center')
        waiting_text.insert("end", "Please wait while the repo loads")
        waiting_text.tag_add("center", "1.0", "end")
        waiting_text.configure(state="disable")
        waiting_text.place(relwidth=1, relheight=1)

        def load_and_close_wait():
            repo.load_repo()
            self.apppage = AppPage(self.controller, repo, self)
            self.apppage.place(relwidth=1, relheight=1)
            waiting_frame.destroy()
            self.apppage.refresh()

        self.controller.threader.new_session()
        self.controller.threader.add(load_and_close_wait)

    def on_click(self, event):
        y = int(event.y + (float(self.canvas.yview()[0]) * self.canvas_height))
        x = event.x
        for t in self.tiles:
            if t.is_in_range(x, y):
                self.load_repo(t.repo)
            else:
                t.deactivate()

    def mouse_move(self, event):
        y = int(event.y + (float(self.canvas.yview()[0]) * self.canvas_height))
        x = event.x
        for t in self.tiles:
            if t.is_in_range(x, y):
                if t.active: continue
                else: t.activate()
            else: t.deactivate()

    def refresh(self, event=None):
        self.canvas.delete("all")
        self.thumbnails = []
        self.tiles = []
        self.canvas.delete("all")
        i = 0
        y_offset = 10
        y_padding = 50
        x_padding = 50
        tile_height = 200
        tile_width = 200
        framewidth = self.canvas.winfo_width() - self.scrollbar.winfo_width()
        self.canvas_frame.config(width=framewidth)
        # Get integer number of tiles fittable in the window
        maxperrow = framewidth // (tile_width + x_padding)
        #If there's not enough room to build anything stop
        if not maxperrow: return
        maxwidth = (maxperrow) * tile_width + maxperrow * x_padding
        filler_space = framewidth - maxwidth
        filler_space = filler_space / (maxperrow + 1)
        _x, _y = 0, 0  #vars to track where in grid we are placing
        for r in self.controller.repos:
            place_x = _x * tile_width + (_x + 1) * x_padding + (
                _x + 1) * filler_space
            place_y = _y * tile_height + y_offset + (_y + 1) * y_padding
            rt = Tile(self, r, load_image_object_from_bytes_array(r.image))
            self.tiles.append(rt)
            rt.set_dimensions(place_x, place_y, tile_width, tile_height)
            self.place_tile(rt)
            _x += 1
            if _x == maxperrow: _x, _y = 0, _y + 1
        _y += 1
        height = _y * tile_height + y_offset + (_y + 1) * y_padding
        frameheight = self.canvas_frame.winfo_height()
        height = height if height > frameheight else frameheight
        self.canvas_height = height
        self.canvas_frame.config(width=200, height=self.winfo_height())
        self.canvas.config(scrollregion=(0, 0, 200, self.canvas_height))

    def place_tile(self, tile):
        tile.references.append(
            self.canvas.create_rectangle(tile.x,
                                         tile.y,
                                         tile.x + tile.width,
                                         tile.y + tile.height - 1,
                                         fill="#7F7F7F"))

        if tile.thumbnail:
            maxwidth = tile.width - 8
            maxheight = tile.width - 8
            art_image = tile.thumbnail
            wpercent = (maxwidth / float(art_image.size[0]))
            hsize = int((float(art_image.size[1]) * float(wpercent)))
            new_image = art_image.resize((maxwidth, hsize), Image.ANTIALIAS)
            if new_image.size[1] > maxheight:
                hpercent = (maxheight / float(art_image.size[1]))
                wsize = int((float(art_image.size[0]) * float(hpercent)))
                new_image = art_image.resize((wsize, maxheight),
                                             Image.ANTIALIAS)
            thumbnail = ImageTk.PhotoImage(new_image)

            self.thumbnails.append(thumbnail)
            tile.references.append(
                self.canvas.create_image(tile.x + 4,
                                         tile.y + 4,
                                         anchor="nw",
                                         image=thumbnail))
        tile.references.extend([
            self.canvas.create_text(tile.x + 8,
                                    tile.y + 8,
                                    anchor="nw",
                                    text=tile.repo_name,
                                    font="bold",
                                    fill="#CCCCCC")
        ])
        if tile.active: self.activate_tile()

    def activate_tile(self, tile):
        tile.active_references.extend([
            self.canvas.create_rectangle(tile.x,
                                         tile.y,
                                         tile.x + tile.width - 1,
                                         tile.y + tile.height - 1,
                                         outline="#000000",
                                         width=4),
        ])

    def deactivate_tile(self, tile):
        for r in tile.active_references:
            self.canvas.delete(r)

    def _on_mouse_wheel(self, event):
        if platform.system() == 'Windows':
            self.canvas.yview_scroll(-1 * int(event.delta / 120), 'units')
        elif platform.system() == 'Darwin':
            self.canvas.yview_scroll(-1 * int(event.delta), 'units')
        else:
            if event.num == 4:
                self.canvas.yview_scroll(-1, 'units')
            elif event.num == 5:
                self.canvas.yview_scroll(1, 'units')

    def on_scroll_bar(self, move_type, move_units, __=None):
        if move_type == "moveto":
            self.canvas.yview("moveto", move_units)

    def exit(self, event=None):
        if self.apppage:
            try:
                self.apppage.exit()
            except:
                pass
Exemplo n.º 4
0
class vis_tool:

    def __init__(self):
        self.args = parse_args()
        cfg = mmcv.Config.fromfile(self.args.config)
        self.window = Tk()
        self.menubar = Menu(self.window)

        self.info = StringVar()
        self.info_label = Label(
            self.window, bg='yellow', width=4, textvariable=self.info)

        self.listBox_img = Listbox(
            self.window, width=50, height=25, font=('Times New Roman', 10))
        self.listBox_obj = Listbox(
            self.window, width=50, height=12, font=('Times New Roman', 10))

        self.scrollbar_img = Scrollbar(
            self.window, width=15, orient='vertical')
        self.scrollbar_obj = Scrollbar(
            self.window, width=15, orient='vertical')

        self.listBox_img_info = StringVar()
        self.listBox_img_label = Label(
            self.window,
            font=('Arial', 11),
            bg='yellow',
            width=4,
            height=1,
            textvariable=self.listBox_img_info)

        self.listBox_obj_info = StringVar()
        self.listBox_obj_label1 = Label(
            self.window,
            font=('Arial', 11),
            bg='yellow',
            width=4,
            height=1,
            textvariable=self.listBox_obj_info)
        self.listBox_obj_label2 = Label(
            self.window,
            font=('Arial', 11),
            bg='yellow',
            width=4,
            height=1,
            text='Object Class : Score (IoU)')


        if cfg.dataset_type == 'VOCDataset':
            self.data_info = VOC_dataset(cfg, self.args)
        elif cfg.dataset_type == 'CocoDataset':
            self.data_info = COCO_dataset(cfg, self.args)

        self.info.set('DATASET: {}'.format(self.data_info.dataset))

        # load image and show it on the window
        self.img = self.data_info.get_img_by_index(0)
        self.photo = ImageTk.PhotoImage(self.img)
        self.label_img = Label(self.window, image=self.photo)

        self.show_det_txt = IntVar(value=1)
        self.checkbn_det_txt = Checkbutton(
            self.window,
            text='Text',
            font=('Arial', 10, 'bold'),
            variable=self.show_det_txt,
            command=self.change_img,
            fg='#0000FF')

        self.show_dets = IntVar(value=1)
        self.checkbn_det = Checkbutton(
            self.window,
            text='Detections',
            font=('Arial', 10, 'bold'),
            variable=self.show_dets,
            command=self.change_img,
            fg='#0000FF')

        self.show_gt_txt = IntVar(value=1)
        self.checkbn_gt_txt = Checkbutton(
            self.window,
            text='Text',
            font=('Arial', 10, 'bold'),
            variable=self.show_gt_txt,
            command=self.change_img,
            fg='#FF8C00')

        self.show_gts = IntVar(value=1)
        self.checkbn_gt = Checkbutton(
            self.window,
            text='Groundtruth',
            font=('Arial', 10, 'bold'),
            variable=self.show_gts,
            command=self.change_img,
            fg='#FF8C00')

        self.combo_label = Label(
            self.window,
            bg='yellow',
            width=10,
            height=1,
            text='Show Category',
            font=('Arial', 11))
        self.combo_category = ttk.Combobox(
            self.window,
            font=('Arial', 11),
            values=self.data_info.aug_category.combo_list)
        self.combo_category.current(0)

        self.th_label = Label(
            self.window,
            font=('Arial', 11),
            bg='yellow',
            width=10,
            height=1,
            text='Score Threshold')
        self.threshold = np.float32(0.5)
        self.th_entry = Entry(
            self.window,
            font=('Arial', 11),
            width=10,
            textvariable=StringVar(self.window, value=str(self.threshold)))
        self.th_button = Button(
            self.window, text='Enter', height=1, command=self.change_threshold)

        self.iou_th_label = Label(
            self.window,
            font=('Arial', 11),
            bg='yellow',
            width=10,
            height=1,
            text='IoU Threshold')
        self.iou_threshold = np.float32(0.5)
        self.iou_th_entry = Entry(
            self.window,
            font=('Arial', 11),
            width=10,
            textvariable=StringVar(self.window, value=str(self.iou_threshold)))
        self.iou_th_button = Button(
            self.window, text='Enter', height=1, command=self.change_iou_threshold)

        self.find_label = Label(
            self.window,
            font=('Arial', 11),
            bg='yellow',
            width=10,
            height=1,
            text='find')
        self.find_name = ''
        self.find_entry = Entry(
            self.window,
            font=('Arial', 11),
            width=10,
            textvariable=StringVar(self.window, value=str(self.find_name)))
        self.find_button = Button(
            self.window, text='Enter', height=1, command=self.findname)

        self.listBox_img_idx = 0

        # ====== ohter attribute ======
        self.img_name = ''
        self.show_img = None

        self.output = self.args.output

        if not os.path.isdir(self.output):
            os.makedirs(self.output)

        self.img_list = self.data_info.img_list

        # flag for find/threshold button switch focused element
        self.button_clicked = False

    def change_threshold(self, event=None):
        try:
            self.threshold = np.float32(self.th_entry.get())
            self.change_img()

            # after changing threshold, focus on listBox for easy control
            if self.window.focus_get() == self.listBox_obj:
                self.listBox_obj.focus()
            else:
                self.listBox_img.focus()

            self.button_clicked = True

        except ValueError:
            self.window.title('Please enter a number as score threshold.')

    def change_iou_threshold(self, event=None):

        try:
            self.iou_threshold = np.float32(self.iou_th_entry.get())
            self.change_img()

            # after changing threshold, focus on listBox for easy control
            if self.window.focus_get() == self.listBox_obj:
                self.listBox_obj.focus()
            else:
                self.listBox_img.focus()

            self.button_clicked = True

        except ValueError:
            self.window.title("Please enter a number as IoU threshold.")

    # draw groundtruth
    def draw_gt_boxes(self, img, objs):
        for obj in objs:
            cls_name = obj[0]

            # according combobox to decide whether to plot this category
            if self.combo_category.get() == 'All':
                show_category = self.data_info.aug_category.category
            else:
                show_category = [self.combo_category.get()]

            if cls_name not in show_category:
                continue

            box = obj[1:]
            xmin = max(box[0], 0)
            ymin = max(box[1], 0)
            xmax = min(box[0] + box[2], self.img_width)
            ymax = min(box[1] + box[3], self.img_height)

            font = cv2.FONT_HERSHEY_SIMPLEX

            if self.show_gt_txt.get():
                if ymax + 30 >= self.img_height:
                    cv2.rectangle(img, (xmin, ymin),
                                  (xmin + len(cls_name) * 10, int(ymin - 20)),
                                  (255, 140, 0), cv2.FILLED)
                    cv2.putText(img, cls_name, (xmin, int(ymin - 5)), font,
                                0.5, (255, 255, 255), 1)
                else:
                    cv2.rectangle(img, (xmin, ymax),
                                  (xmin + len(cls_name) * 10, int(ymax + 20)),
                                  (255, 140, 0), cv2.FILLED)
                    cv2.putText(img, cls_name, (xmin, int(ymax + 15)), font,
                                0.5, (255, 255, 255), 1)

            cv2.rectangle(img, (xmin, ymin), (xmax, ymax),
                          self.args.gt_box_color, 1)

        return img


    def get_iou(self, det):

        iou = np.zeros_like(det)
        GT = self.data_info.get_singleImg_gt(self.img_name)
        
        for idx, cls_objs in enumerate(det):

            category = self.data_info.aug_category.category[idx]
            BBGT = []
            for t in GT:
                if not t[0] == category: continue
                BBGT.append([t[1], t[2], t[1] + t[3], t[2] + t[4]])
            BBGT = np.asarray(BBGT)
            d = [0] * len(BBGT)  # for check 1 GT map to several det

            confidence = cls_objs[:, 4]
            BB = cls_objs[:, 0:4]   # bounding box        
             
            # sort by confidence
            sorted_ind = np.argsort(-confidence)
            sorted_scores = np.sort(-confidence)
            BB = BB[sorted_ind, :]

            # for returning original order
            ind_table = {i: sorted_ind[i] for i in range(len(sorted_ind))}  

            iou[idx] = np.zeros(len(BB))

            if len(BBGT) > 0:
                for i in range(len(BB)): 
                    bb = BB[i, :]
            
                    # compute overlaps
                    # intersection
                    ixmin = np.maximum(BBGT[:, 0], bb[0])
                    iymin = np.maximum(BBGT[:, 1], bb[1])
                    ixmax = np.minimum(BBGT[:, 2], bb[2])
                    iymax = np.minimum(BBGT[:, 3], bb[3])
                    iw = np.maximum(ixmax - ixmin + 1., 0.)
                    ih = np.maximum(iymax - iymin + 1., 0.)
                    inters = iw * ih
    
                    # union
                    uni = ((bb[2] - bb[0] + 1.) * (bb[3] - bb[1] + 1.) +
                           (BBGT[:, 2] - BBGT[:, 0] + 1.) * (BBGT[:, 3] - BBGT[:, 1] + 1.) - 
                            inters)

                    overlaps = inters / uni
                    ovmax = np.max(overlaps) # max overlaps with all gt
                    jmax = np.argmax(overlaps)        
                    
                    if ovmax > self.iou_threshold:        
                        if not d[jmax]:
                            d[jmax] = 1
                        else: # multiple bounding boxes map to one gt
                            ovmax = -ovmax

                    iou[idx][ind_table[i]] = ovmax # return to unsorted order
        return iou



    def draw_all_det_boxes(self, img, single_detection):

        if self.data_info.has_anno:
            self.iou = self.get_iou(single_detection)

        for idx, cls_objs in enumerate(single_detection):
            category = self.data_info.aug_category.category[idx]

            if self.combo_category.get() == 'All':
                show_category = self.data_info.aug_category.category
            else:
                show_category = [self.combo_category.get()]

            if category not in show_category:
                continue

            for obj_idx, obj in enumerate(cls_objs):
                [score, box] = [round(obj[4], 2), obj[:4]]

                if score >= self.threshold:
                    box = list(map(int, list(map(round, box))))
                    xmin = max(box[0], 0)
                    ymin = max(box[1], 0)
                    xmax = min(box[2], self.img_width)
                    ymax = min(box[3], self.img_height)

                    if not self.data_info.has_anno or \
                        self.iou[idx][obj_idx] >= self.iou_threshold:
                        color = self.args.det_box_color
                    else: 
                        color = (255, 0, 0)

                    if self.show_det_txt.get():
                        font = cv2.FONT_HERSHEY_SIMPLEX
                        text = category + ' : ' + str(score)

                        if ymax + 30 >= self.img_height:
                            cv2.rectangle(
                                img, (xmin, ymin),
                                (xmin + len(text) * 9, int(ymin - 20)),
                                (0, 0, 255), cv2.FILLED)
                            cv2.putText(img, text, (xmin, int(ymin - 5)), font,
                                        0.5, (255, 255, 255), 1)
                        else:
                            cv2.rectangle(
                                img, (xmin, ymax),
                                (xmin + len(text) * 9, int(ymax + 20)),
                                (0, 0, 255), cv2.FILLED)
                            cv2.putText(img, text, (xmin, int(ymax + 15)),
                                        font, 0.5, (255, 255, 255), 1)

                    cv2.rectangle(img, (xmin, ymin), (xmax, ymax), color, 2)

        return img

    def draw_all_det_boxes_masks(self, img, single_detection):
        img = np.require(img, requirements=['W'])
        boxes, masks = single_detection

        # draw segmentation masks
        # reference mmdetection/mmdet/models/detectors/base.py
        if self.combo_category.get() != 'All':
            show_idx = self.data_info.aug_category.category.index(
                self.combo_category.get())
            masks = np.asarray([masks[show_idx]])
            boxes = np.asarray([boxes[show_idx]])
            category = self.data_info.aug_category.category[show_idx]

        segms = list(itertools.chain(*masks))
        bboxes = np.vstack(boxes)

        inds = np.where(np.round(bboxes[:, -1], 2) >= self.threshold)[0]

        self.color_list = []
        for i in inds:
            color_mask = np.random.randint(0, 256, (1, 3), dtype=np.uint8)
            mask = maskUtils.decode(segms[i]).astype(np.bool)
            img[mask] = img[mask] * 0.5 + color_mask * 0.5
            self.color_list.append('#%02x%02x%02x' % tuple(color_mask[0]))

        if self.data_info.has_anno:
            boxes2, _ = single_detection
            self.iou = self.get_iou(boxes2)
            if self.combo_category.get() != 'All':
                iou = np.asarray([self.iou[show_idx]])
            else:
                iou = self.iou
            
        # draw bounding box
        for idx, cls_objs in enumerate(boxes):
            if self.combo_category.get() == 'All':
                category = self.data_info.aug_category.category[idx]

            for obj_idx, obj in enumerate(cls_objs):
                [score, box] = [round(obj[4], 2), obj[:4]]

                if score >= self.threshold:
                    box = list(map(int, list(map(round, box))))
                    xmin = max(box[0], 0)
                    ymin = max(box[1], 0)
                    xmax = min(box[2], self.img_width)
                    ymax = min(box[3], self.img_height)

                    if not self.data_info.has_anno or \
                        iou[idx][obj_idx] >= self.iou_threshold:
                        color = self.args.det_box_color
                    else: 
                        color = (255, 0, 0)

                    if self.show_det_txt.get():
                        font = cv2.FONT_HERSHEY_SIMPLEX
                        text = category + ' : ' + str(score)

                        if ymax + 30 >= self.img_height:
                            cv2.rectangle(
                                img, (xmin, ymin),
                                (xmin + len(text) * 9, int(ymin - 20)),
                                (0, 0, 255), cv2.FILLED)
                            cv2.putText(img, text, (xmin, int(ymin - 5)), font,
                                        0.5, (255, 255, 255), 1)
                        else:
                            cv2.rectangle(
                                img, (xmin, ymax),
                                (xmin + len(text) * 9, int(ymax + 20)),
                                (0, 0, 255), cv2.FILLED)
                            cv2.putText(img, text, (xmin, int(ymax + 15)),
                                        font, 0.5, (255, 255, 255), 1)

                    cv2.rectangle(img, (xmin, ymin), (xmax, ymax), color, 2)

        return img

    def change_img(self, event=None):
        if len(self.listBox_img.curselection()) != 0:
            self.listBox_img_idx = self.listBox_img.curselection()[0]

        self.listBox_img_info.set('Image  {:6}  / {:6}'.format(
            self.listBox_img_idx + 1, self.listBox_img.size()))

        name = self.listBox_img.get(self.listBox_img_idx)
        self.window.title('DATASET : ' + self.data_info.dataset + '   ' + name)

        img = self.data_info.get_img_by_name(name)
        self.img_width, self.img_height = img.width, img.height

        img = np.asarray(img)

        self.img_name = name
        self.img = img

        if self.data_info.has_anno and self.show_gts.get():
            objs = self.data_info.get_singleImg_gt(name)
            img = self.draw_gt_boxes(img, objs)

        if self.data_info.results is not None and self.show_dets.get():
            if self.data_info.mask is False:
                dets = self.data_info.get_singleImg_dets(name)
                img = self.draw_all_det_boxes(img, dets)
            else:
                dets = self.data_info.get_singleImg_dets(name).transpose(
                    (1, 0))
                img = self.draw_all_det_boxes_masks(img, dets)

            self.clear_add_listBox_obj()

        self.show_img = img
        img = Image.fromarray(img)
        img = self.scale_img(img)
        self.photo = ImageTk.PhotoImage(img)
        self.label_img.config(image=self.photo)
        self.window.update_idletasks()

        if self.img_name in os.listdir(self.output):
            self.listBox_img_label.config(bg='#CCFF99')
        else:
            self.listBox_img_label.config(bg='yellow')

    def draw_one_det_boxes(self, img, single_detection, selected_idx=-1):
        idx_counter = 0
        for idx, cls_objs in enumerate(single_detection):

            category = self.data_info.aug_category.category[idx]
            if self.combo_category.get() == 'All':
                show_category = self.data_info.aug_category.category
            else:
                show_category = [self.combo_category.get()]

            if category not in show_category:
                continue

            for obj_idx, obj in enumerate(cls_objs):
                [score, box] = [round(obj[4], 2), obj[:4]]

                if score >= self.threshold:
                    if idx_counter == selected_idx:
                        box = list(map(int, list(map(round, box))))
                        xmin = max(box[0], 0)
                        ymin = max(box[1], 0)
                        xmax = min(box[2], self.img_width)
                        ymax = min(box[3], self.img_height)

                        if not self.data_info.has_anno or \
                            self.iou[idx][obj_idx] >= self.iou_threshold:
                            color = self.args.det_box_color
                        else: 
                            color = (255, 0, 0)

                        if self.show_det_txt.get():
                            font = cv2.FONT_HERSHEY_SIMPLEX
                            text = category + ' : ' + str(score)

                            if ymax + 30 >= self.img_height:
                                cv2.rectangle(
                                    img, (xmin, ymin),
                                    (xmin + len(text) * 9, int(ymin - 20)),
                                    (0, 0, 255), cv2.FILLED)
                                cv2.putText(img, text, (xmin, int(ymin - 5)),
                                            font, 0.5, (255, 255, 255), 1)
                            else:
                                cv2.rectangle(
                                    img, (xmin, ymax),
                                    (xmin + len(text) * 9, int(ymax + 20)),
                                    (0, 0, 255), cv2.FILLED)
                                cv2.putText(img, text, (xmin, int(ymax + 15)),
                                            font, 0.5, (255, 255, 255), 1)

                        cv2.rectangle(img, (xmin, ymin), (xmax, ymax), color, 2)

                        return img
                    else:
                        idx_counter += 1

    def draw_one_det_boxes_masks(self, img, single_detection, selected_idx=-1):
        img = np.require(img, requirements=['W'])
        boxes, masks = single_detection

        # draw segmentation masks
        # reference mmdetection/mmdet/models/detectors/base.py
        if self.combo_category.get() != 'All':
            show_idx = self.data_info.aug_category.category.index(
                self.combo_category.get())
            category = self.data_info.aug_category.category[
                show_idx]  # fixed category
            masks = np.asarray([masks[show_idx]])
            boxes = np.asarray([boxes[show_idx]])

        segms = list(itertools.chain(*masks))
        bboxes = np.vstack(boxes)

        inds = np.where(np.round(bboxes[:, -1], 2) >= self.threshold)[0]

        self.color_list = []
        for inds_idx, i in enumerate(inds):
            if inds_idx == selected_idx:
                color_mask = np.random.randint(0, 256, (1, 3), dtype=np.uint8)
                mask = maskUtils.decode(segms[i]).astype(np.bool)
                img[mask] = img[mask] * 0.5 + color_mask * 0.5
                self.color_list.append('#%02x%02x%02x' % tuple(color_mask[0]))

        if self.data_info.has_anno:
            if self.combo_category.get() != 'All':
                iou = np.asarray([self.iou[show_idx]])
            else:
                iou = self.iou
                
        # draw bounding box
        idx_counter = 0
        for idx, cls_objs in enumerate(boxes):
            if self.combo_category.get() == 'All':
                category = self.data_info.aug_category.category[idx]

            for obj_idx, obj in enumerate(cls_objs):
                [score, box] = [round(obj[4], 2), obj[:4]]

                if score >= self.threshold:
                    if idx_counter == selected_idx:
                        box = list(map(int, list(map(round, box))))
                        xmin = max(box[0], 0)
                        ymin = max(box[1], 0)
                        xmax = min(box[2], self.img_width)
                        ymax = min(box[3], self.img_height)

                        if not self.data_info.has_anno or \
                            iou[idx][obj_idx] >= self.iou_threshold:
                            color = self.args.det_box_color
                        else: 
                            color = (255, 0, 0)

                        if self.show_det_txt.get():
                            font = cv2.FONT_HERSHEY_SIMPLEX
                            text = category + ' : ' + str(score)

                            if ymax + 30 >= self.img_height:
                                cv2.rectangle(
                                    img, (xmin, ymin),
                                    (xmin + len(text) * 9, int(ymin - 20)),
                                    (0, 0, 255), cv2.FILLED)
                                cv2.putText(img, text, (xmin, int(ymin - 5)),
                                            font, 0.5, (255, 255, 255), 1)
                            else:
                                cv2.rectangle(
                                    img, (xmin, ymax),
                                    (xmin + len(text) * 9, int(ymax + 20)),
                                    (0, 0, 255), cv2.FILLED)
                                cv2.putText(img, text, (xmin, int(ymax + 15)),
                                            font, 0.5, (255, 255, 255), 1)

                        cv2.rectangle(img, (xmin, ymin), (xmax, ymax),
                                      color, 2)

                        return img
                    else:
                        idx_counter += 1

    # plot only one object
    def change_obj(self, event=None):
        if len(self.listBox_obj.curselection()) == 0:
            self.listBox_img.focus()
            return
        else:
            listBox_obj_idx = self.listBox_obj.curselection()[0]

        self.listBox_obj_info.set('Detected Object : {:4}  / {:4}'.format(
            listBox_obj_idx + 1, self.listBox_obj.size()))

        name = self.listBox_img.get(self.listBox_img_idx)
        img = self.data_info.get_img_by_name(name)
        self.img_width, self.img_height = img.width, img.height
        img = np.asarray(img)
        self.img_name = name
        self.img = img

        if self.data_info.has_anno and self.show_gts.get():
            objs = self.data_info.get_singleImg_gt(name)
            img = self.draw_gt_boxes(img, objs)

        if self.data_info.results is not None and self.show_dets.get():

            if self.data_info.mask is False:
                dets = self.data_info.get_singleImg_dets(name)
                img = self.draw_one_det_boxes(img, dets, listBox_obj_idx)
            else:
                dets = self.data_info.get_singleImg_dets(name).transpose(
                    (1, 0))
                img = self.draw_one_det_boxes_masks(img, dets, listBox_obj_idx)

        self.show_img = img
        img = Image.fromarray(img)
        img = self.scale_img(img)
        self.photo = ImageTk.PhotoImage(img)
        self.label_img.config(image=self.photo)
        self.window.update_idletasks()

        if self.img_name in os.listdir(self.output):
            self.listBox_img_label.config(bg='#CCFF99')
        else:
            self.listBox_img_label.config(bg='yellow')

    # ============================================

    def scale_img(self, img):
        [s_w, s_h] = [1, 1]

        # if window size is (1920, 1080),
        # the default max image size is (1440, 810)
        (fix_width, fix_height) = (1440, 810)

        # change image size according to window size
        if self.window.winfo_width() != 1:
            fix_width = (
                self.window.winfo_width() - self.listBox_img.winfo_width() -
                self.scrollbar_img.winfo_width() - 5)
            # fix_height = int(fix_width * 9 / 16)
            fix_height = 750

        # handle image size is too big
        if img.width > fix_width:
            s_w = fix_width / img.width
        if img.height > fix_height:
            s_h = fix_height / img.height

        scale = min(s_w, s_h)
        img = img.resize((int(img.width * scale), int(img.height * scale)),
                         Image.ANTIALIAS)
        return img

    def clear_add_listBox_obj(self):
        self.listBox_obj.delete(0, 'end')

        if self.data_info.mask is False:
            single_detection = self.data_info.get_singleImg_dets(
                self.img_list[self.listBox_img_idx])
        else:
            single_detection, single_mask = self.data_info.get_singleImg_dets(
                self.img_list[self.listBox_img_idx]).transpose((1, 0))

        if self.combo_category.get() == 'All':
            show_category = self.data_info.aug_category.category
        else:
            show_category = [self.combo_category.get()]

        num = 0
        for idx, cls_objs in enumerate(single_detection):
            category = self.data_info.aug_category.category[idx]

            if category not in show_category:
                continue

            for obj_idx, obj in enumerate(cls_objs):
                score = np.round(obj[4], 2)
                if score >= self.threshold:
                    if not self.data_info.has_anno:
                        self.listBox_obj.insert('end', 
                                                category + " : " + str(score))
                    elif self.iou[idx][obj_idx] > self.iou_threshold:
                        s = "{:15} : {:5.3} ( {:<6.3})".format(
                            category, score, abs(round(self.iou[idx][obj_idx], 2)))
                        self.listBox_obj.insert('end', s)
                        self.listBox_obj.itemconfig(num, fg="green")
                    else:
                        s = "{:15} : {:5.3} ( {:<6.3})".format(
                            category, score, abs(round(self.iou[idx][obj_idx], 2)))
                        self.listBox_obj.insert('end', s)
                        self.listBox_obj.itemconfig(num, fg="red")

                    num += 1

        self.listBox_obj_info.set('Detected Object : {:3}'.format(num))

    def change_threshold_button(self, v):
        self.threshold += v

        if self.threshold <= 0:
            self.threshold = 0
        elif self.threshold >= 1:
            self.threshold = 1

        self.th_entry.delete(0, END)
        self.th_entry.insert(0, str(round(self.threshold, 2)))
        self.change_threshold()

    def change_iou_threshold_button(self, v):
        self.iou_threshold += v

        if self.iou_threshold <= 0:
            self.iou_threshold = 0
        elif self.iou_threshold >= 1:
            self.iou_threshold = 1

        self.iou_th_entry.delete(0, END)
        self.iou_th_entry.insert(0, str(round(self.iou_threshold, 2)))
        self.change_iou_threshold()


    def save_img(self):
        print('Save image to ' + os.path.join(self.output, self.img_name))
        cv2.imwrite(
            os.path.join(self.output, self.img_name),
            cv2.cvtColor(self.show_img, cv2.COLOR_BGR2RGB))
        self.listBox_img_label.config(bg='#CCFF99')

    def eventhandler(self, event):
        entry_list = [self.find_entry, self.th_entry, self.iou_th_entry]
        if self.window.focus_get() not in entry_list:
            if platform.system() == 'Windows':
                state_1key = 8
                state_2key = 12
            else:  # 'Linux'
                state_1key = 16
                state_2key = 20
          
            if event.state == state_2key and event.keysym == 'Left':
                self.change_iou_threshold_button(-0.1)
            elif event.state == state_2key and event.keysym == 'Right':
                self.change_iou_threshold_button(0.1) 

            elif event.state == state_1key and event.keysym == 'Left':
                self.change_threshold_button(-0.1)
            elif event.state == state_1key and event.keysym == 'Right':
                self.change_threshold_button(0.1)
            elif event.keysym == 'q':
                self.window.quit()
            elif event.keysym == 's':
                self.save_img()

            if self.button_clicked:
                self.button_clicked = False
            else:
                if event.keysym in ['KP_Enter', 'Return']:
                    self.listBox_obj.focus()
                    self.listBox_obj.select_set(0)
                elif event.keysym == 'Escape':
                    self.change_img()
                    self.listBox_img.focus()

    def combobox_change(self, event=None):
        self.listBox_img.focus()
        self.change_img()

    def clear_add_listBox_img(self):
        self.listBox_img.delete(0, 'end')  # delete listBox_img 0 ~ end items

        # add image name to listBox_img
        for item in self.img_list:
            self.listBox_img.insert('end', item)

        self.listBox_img.select_set(0)
        self.listBox_img.focus()
        self.change_img()

    def findname(self, event=None):
        self.find_name = self.find_entry.get()
        new_list = []

        if self.find_name == '':
            new_list = self.data_info.img_list
        else:
            for img_name in self.data_info.img_list:
                if self.find_name[0] == '!':
                    if self.find_name[1:] not in img_name:
                        new_list.append(img_name)
                else:
                    if self.find_name in img_name:
                        new_list.append(img_name)

        if len(new_list) != 0:
            self.img_list = new_list
            self.clear_add_listBox_img()
            self.clear_add_listBox_obj()
            self.button_clicked = True
        else:
            self.window.title("Can't find any image about '{}'".format(
                self.find_name))

    def run(self):
        self.window.title('DATASET : ' + self.data_info.dataset)
        self.window.geometry('1280x800+350+100')

        # self.menubar.add_command(label='QUIT', command=self.window.quit)
        self.window.config(menu=self.menubar)  # display the menu
        self.scrollbar_img.config(command=self.listBox_img.yview)
        self.listBox_img.config(yscrollcommand=self.scrollbar_img.set)
        self.scrollbar_obj.config(command=self.listBox_obj.yview)
        self.listBox_obj.config(yscrollcommand=self.scrollbar_obj.set)

        layer1 = 0
        layer2 = 50

        # ======================= layer 1 =========================

        # combobox
        self.combo_label.grid(
            row=layer1 + 30,
            column=0,
            sticky=W + E + N + S,
            padx=3,
            pady=3,
            columnspan=6)
        self.combo_category.grid(
            row=layer1 + 30,
            column=6,
            sticky=W + E + N + S,
            padx=3,
            pady=3,
            columnspan=6)

        # show det
        self.checkbn_det.grid(
            row=layer1 + 40,
            column=0,
            sticky=N + S,
            padx=3,
            pady=3,
            columnspan=4)
        # show det text
        self.checkbn_det_txt.grid(
            row=layer1 + 40,
            column=4,
            sticky=N + S,
            padx=3,
            pady=3,
            columnspan=2)
        if self.data_info.has_anno != False:
            # show gt
            self.checkbn_gt.grid(
                row=layer1 + 40,
                column=6,
                sticky=N + S,
                padx=3,
                pady=3,
                columnspan=4)
            # show gt text
            self.checkbn_gt_txt.grid(
                row=layer1 + 40,
                column=10,
                sticky=N + S,
                padx=3,
                pady=3,
                columnspan=2)

        # ======================= layer 2 =========================

        self.listBox_img_label.grid(
            row=layer2 + 0, column=0, sticky=N + S + E + W, columnspan=12)

        # find name
        self.find_label.grid(
            row=layer2 + 20, column=0, sticky=E + W, columnspan=4)
        self.find_entry.grid(
            row=layer2 + 20, column=4, sticky=E + W, columnspan=4)
        self.find_button.grid(
            row=layer2 + 20, column=8, sticky=E + W, pady=3, columnspan=4)

        self.scrollbar_img.grid(row=layer2 + 30, column=11, sticky=N + S + W)
        self.label_img.grid(
            row=layer1 + 30,
            column=12,
            sticky=N + E,
            padx=3,
            pady=3,
            rowspan=110)
        self.listBox_img.grid(
            row=layer2 + 30,
            column=0,
            sticky=N + S + E + W,
            pady=3,
            columnspan=11)

        if self.data_info.det_file != '':
            self.th_label.grid(
                row=layer2 + 40, column=0, sticky=E + W, columnspan=6)
            self.th_entry.grid(
                row=layer2 + 40, column=6, sticky=E + W, columnspan=3)
            self.th_button.grid(
                row=layer2 + 40, column=9, sticky=E + W, columnspan=3)

            if self.data_info.has_anno != False:
                self.iou_th_label.grid(
                    row=layer2 + 50, column=0, sticky=E + W, columnspan=6)
                self.iou_th_entry.grid(
                    row=layer2 + 50, column=6, sticky=E + W, columnspan=3)
                self.iou_th_button.grid(
                    row=layer2 + 50, column=9, sticky=E + W, columnspan=3)

            self.listBox_obj_label1.grid(
                row=layer2 + 60, column=0, sticky=E + W, pady=3, columnspan=12)

            if self.data_info.has_anno != False:
                self.listBox_obj_label2.grid(
                    row=layer2 + 70, 
                    column=0, 
                    sticky=E + W, 
                    pady=2, 
                    columnspan=12)

            self.scrollbar_obj.grid(
                row=layer2 + 80, column=11, sticky=N + S + W, pady=3)
            self.listBox_obj.grid(
                row=layer2 + 80,
                column=0,
                sticky=N + S + E + W,
                pady=3,
                columnspan=11)

        self.clear_add_listBox_img()
        self.listBox_img.bind('<<ListboxSelect>>', self.change_img)
        self.listBox_img.bind_all('<KeyRelease>', self.eventhandler)

        self.listBox_obj.bind('<<ListboxSelect>>', self.change_obj)

        self.th_entry.bind('<Return>', self.change_threshold)
        self.th_entry.bind('<KP_Enter>', self.change_threshold)
        self.iou_th_entry.bind('<Return>', self.change_iou_threshold)
        self.iou_th_entry.bind('<KP_Enter>', self.change_iou_threshold)
        self.find_entry.bind('<Return>', self.findname)
        self.find_entry.bind('<KP_Enter>', self.findname)

        self.combo_category.bind('<<ComboboxSelected>>', self.combobox_change)

        self.window.mainloop()