def build_speed_scale(self): """ Construit la barre de reglage de la vitesse d'animation :return: Scale """ speed_label = Label(self, text="Vitesse") speed_label.configure(font=font.Font(family=Config.FONT["main"], size=Config.SIZE["large"]), background=Config.COLOR["main-bg"], foreground=Config.COLOR["main-fg"]) speed_label.grid(sticky='w', padx=10) scale = Scale(self, from_=-1, to=1, resolution=0.1, tickinterval=0.5, command=self.on_move_scale) scale.configure(length=Config.LEFT_MENU_WIDTH - 10, orient='horizontal', font=font.Font(family=Config.FONT["main"], size=Config.SIZE["small"]), background=Config.COLOR["main-bg"], foreground=Config.COLOR["main-fg"], activebackground=Config.COLOR["main-bg"], troughcolor=Config.COLOR["main-fg"], highlightthickness=0) scale.set(1) scale.grid(padx=10) return scale
class ipGUI: def __init__(self, master): self.master = master self.master.minsize(width=800, height=600) menu = Menu(self.master) master.config(menu=menu) # ***** Main Menu ***** # *** file menu *** fileMenu = Menu(menu) menu.add_cascade(label='File', menu=fileMenu) fileMenu.add_command(label="Open", command=self.openImage) fileMenu.add_command(label="Load Blur Kernel", command=self.loadKernel) fileMenu.add_command(label="Save", command=self.saveImage) fileMenu.add_command(label="Exit", command=master.destroy) # *** edit menu *** editMenu = Menu(menu) menu.add_cascade(label='Space', menu=editMenu) editMenu.add_command(label="Histogram Equalization", command=self.histWrap) editMenu.add_command(label="Gamma Correction", command=self.gammaCorWrap) editMenu.add_command(label="Log Transform", command=self.logTranWrap) editMenu.add_command(label="Sharpen", command=self.sharpWrap) editMenu.add_command(label="Cartoonify", command=self.cartoonifyWrap) # *** blur menu *** blurMenu = Menu(editMenu) editMenu.add_cascade(label='Blur', menu=blurMenu) blurMenu.add_command(label="Box", command=self.boxBlurWrap) blurMenu.add_command(label="Gaussian", command=self.gaussianBlurWrap) blurMenu.add_command(label="Median", command=self.medianBlurWrap) # *** frequency filtering *** freqMenu = Menu(menu) menu.add_cascade(label='Frequency', menu=freqMenu) freqMenu.add_command(label="DFT", command=self.dftWrap) freqMenu.add_command(label="Load Mask", command=self.freqMaskWrap) # *** Mask Menu *** maskMenu = Menu(freqMenu) freqMenu.add_cascade(label='Create Mask', menu=maskMenu) maskMenu.add_command(label='Low Pass', command=self.lpmWrap) maskMenu.add_command(label='High Pass', command=self.hpmWrap) maskMenu.add_command(label='Band Pass', command=self.bppmWrap) maskMenu.add_command(label='Band Stop', command=self.bspmWrap) # *** frequency filtering *** restorationMenu = Menu(menu) menu.add_cascade(label='Restoration', menu=restorationMenu) restorationMenu.add_command(label="Full Inverse", command=self.fullInverseWrap) restorationMenu.add_command(label="Radially Limited Inverse", command=self.truncatedInverseWrap) restorationMenu.add_command(label="Approximate Weiner", command=self.approximateWeinerWrap) restorationMenu.add_command(label="Constrained LS", command=self.contrainedLSWrap) # ***** Toolbar ***** toolbar = Frame(master, bg="grey") undoButton = Button(toolbar, text="Undo", command=self.undoFunc) undoButton.pack(side=LEFT) origButton = Button(toolbar, text="Original", command=self.origFunc) origButton.pack(side=LEFT) toolbar.pack(side=TOP, fill=X) # ***** Image Display Area ***** self.frame = Frame(self.master) self.frame.pack() self.panel = Label(self.frame) self.panel.pack(padx=10, pady=10) self.img = None self.origImg = None self.prevImg = None # ***** Gamma Controls ***** self.gammaFrame = Frame(self.master) self.gammaSlider = Scale(self.gammaFrame, from_=0.1, to=2, orient=HORIZONTAL, resolution=0.1) self.gammaSlider.pack(side=TOP) self.gammaExitButton = Button(self.gammaFrame, text="Exit", command=self.gammaFrame.pack_forget) self.gammaExitButton.pack(side=TOP) # ***** Box Blur Controls ***** self.boxFrame = Frame(self.master) self.boxSlider = Scale(self.boxFrame, from_=1, to=5, orient=HORIZONTAL) self.boxSlider.pack(side=TOP) self.boxExitButton = Button(self.boxFrame, text="Exit", command=self.boxFrame.pack_forget) self.boxExitButton.pack(side=TOP) # ***** Truncated Inverse Controls ***** self.truncatedInverseFrame = Frame(self.master) self.truncatedInverseSlider = Scale(self.truncatedInverseFrame, from_=-3, to=2, orient=HORIZONTAL, resolution=0.1) self.truncatedInverseSlider.pack(side=TOP) self.truncatedInverseExitButton = Button( self.truncatedInverseFrame, text="Exit", command=self.truncatedInverseFrame.pack_forget) self.truncatedInverseExitButton.pack(side=TOP) # ***** Weiner Controls ***** self.weinerFrame = Frame(self.master) self.weinerSlider = Scale(self.weinerFrame, from_=-3, to=2, orient=HORIZONTAL, resolution=0.1) self.weinerSlider.pack(side=TOP) self.weinerExitButton = Button(self.weinerFrame, text="Exit", command=self.weinerFrame.pack_forget) self.weinerExitButton.pack(side=TOP) # ***** CLS Controls ***** self.clsFrame = Frame(self.master) self.clsSlider = Scale(self.clsFrame, from_=-3, to=2, orient=HORIZONTAL, resolution=0.1) self.clsSlider.pack(side=TOP) self.clsExitButton = Button(self.clsFrame, text="Exit", command=self.clsFrame.pack_forget) self.clsExitButton.pack(side=TOP) # ***** DFT Display Area ****** self.dftFrame = Frame(self.master) self.magPanel = Label(self.dftFrame) self.magPanel.pack(padx=10, pady=10, side=TOP) self.freqPanel = Label(self.dftFrame) self.freqPanel.pack(padx=10, pady=10, side=TOP) self.dftExitButton = Button( self.dftFrame, text="Exit", command=lambda: self.displayImg(np.array(self.img))) self.dftExitButton.pack(side=TOP, fill=X) # ***** Low Pass Mask Creation ***** self.lpmFrame = Frame(self.master) self.lpmPanel = Label(self.lpmFrame) self.lpmPanel.pack(padx=10, pady=10, side=TOP) self.lpmSubButton = Button(self.lpmFrame, text="submit") self.lpmSubButton.pack(side=TOP) self.lpmExitButton = Button( self.lpmFrame, text="Exit", command=lambda: self.displayImg(np.array(self.img))) self.lpmExitButton.pack(side=TOP) self.lpmSlider = Scale(self.lpmFrame, from_=1, to=2, orient=HORIZONTAL, resolution=1) # ***** High Pass Mask Creation ***** self.hpmFrame = Frame(self.master) self.hpmPanel = Label(self.hpmFrame) self.hpmPanel.pack(padx=10, pady=10, side=TOP) self.hpmSubButton = Button(self.hpmFrame, text="submit") self.hpmSubButton.pack(side=TOP) self.hpmExitButton = Button( self.hpmFrame, text="Exit", command=lambda: self.displayImg(np.array(self.img))) self.hpmExitButton.pack(side=TOP) self.hpmSlider = Scale(self.hpmFrame, from_=1, to=2, orient=HORIZONTAL, resolution=1) # ***** Band Pass Mask Creation ***** self.bppmFrame = Frame(self.master) self.bppmPanel = Label(self.bppmFrame) self.bppmPanel.pack(padx=10, pady=10, side=TOP) self.bppmSubButton = Button(self.bppmFrame, text="submit") self.bppmSubButton.pack(side=TOP) self.bppmExitButton = Button( self.bppmFrame, text="Exit", command=lambda: self.displayImg(np.array(self.img))) self.bppmExitButton.pack(side=TOP) self.bppmSliderLow = Scale(self.bppmFrame, from_=1, to=2, orient=HORIZONTAL, resolution=1) self.bppmSliderHigh = Scale(self.bppmFrame, from_=1, to=2, orient=HORIZONTAL, resolution=1) # ***** Band Pass Mask Creation ***** self.bspmFrame = Frame(self.master) self.bspmPanel = Label(self.bspmFrame) self.bspmPanel.pack(padx=10, pady=10, side=TOP) self.bspmSubButton = Button(self.bspmFrame, text="submit") self.bspmSubButton.pack(side=TOP) self.bspmExitButton = Button( self.bspmFrame, text="exit", command=lambda: self.displayImg(np.array(self.img))) self.bspmExitButton.pack(side=TOP) self.bspmSliderLow = Scale(self.bspmFrame, from_=1, to=2, orient=HORIZONTAL, resolution=1) self.bspmSliderHigh = Scale(self.bspmFrame, from_=1, to=2, orient=HORIZONTAL, resolution=1) def displayImg(self, img): # input image in RGB self.frame.pack() self.dftFrame.pack_forget() self.lpmFrame.pack_forget() self.hpmFrame.pack_forget() self.bppmFrame.pack_forget() self.bspmFrame.pack_forget() self.img = Image.fromarray(img) imgtk = ImageTk.PhotoImage(self.img) self.panel.configure(image=imgtk) self.panel.image = imgtk def openImage(self): # can change the image path = filedialog.askopenfilename() if len(path) > 0: imgRead = cv2.imread(path) if imgRead is not None: imgRead = cv2.cvtColor(imgRead, cv2.COLOR_BGR2RGB) self.origImg = Image.fromarray(imgRead) self.prevImg = Image.fromarray(imgRead) self.displayImg(imgRead) else: raise ValueError("Not a valid image") else: raise ValueError("Not a valid path") def loadKernel(self): path = filedialog.askopenfilename() if len(path) > 0: self.filter_kernel = np.mean(cv2.imread(path), axis=-1) self.filter_kernel = self.filter_kernel / np.sum( self.filter_kernel) else: raise ValueError("Not a valid path") def saveImage(self): if self.img is not None: toSave = filedialog.asksaveasfilename() self.img.save(toSave) else: messagebox.showerror(title="Save Error", message="No image to be saved!") def histWrap(self): img = np.array(self.img) self.prevImg = self.img imgNew = image_utils.histEqlFunc(img) self.displayImg(imgNew) # Gamma Correction def gammaCallback(self, event, img): gamma = self.gammaSlider.get() self.prevImg = self.img imgNew = image_utils.gammaCorFunc(img, 255.0 / (255.0**gamma), gamma) self.displayImg(imgNew) def truncatedInverseCallback(self, event, img): th = 10**self.truncatedInverseSlider.get() imgNew = self.truncatedInverseFilter(th) self.displayImg(imgNew) def weinerCallback(self, event, img): gamma = 10**self.weinerSlider.get() imgNew = self.weinerFilter(gamma) self.displayImg(imgNew) def clsCallback(self, event, img): K = 10**self.clsSlider.get() imgNew = self.clsFilter(K) self.displayImg(imgNew) def gammaCorWrap(self): img = np.array(self.img) self.gammaFrame.pack() self.gammaSlider.set(1.0) self.gammaSlider.bind( "<ButtonRelease-1>", lambda event, img=img: self.gammaCallback(event, img)) def logTranWrap(self): img = np.array(self.img) self.prevImg = self.img imgNew = image_utils.logTranFunc(img, 255.0 / np.log10(256)) self.displayImg(imgNew) def sharpWrap(self): # Sharpen Wrapper img = np.array(self.img) self.prevImg = self.img imgNew = image_utils.sharpFunc(img) self.displayImg(imgNew) def boxBlurWrap(self): # Box Blur Wrapper img = np.array(self.img) self.prevImg = self.img self.boxFrame.pack() self.boxSlider.set(1) self.boxSlider.bind("<ButtonRelease-1>", lambda event, img=img: self.displayImg( image_utils.boxBlurFunc( event, img, 2 * self.boxSlider.get() + 1))) def gaussianBlurWrap(self): # Gaussian Blur Wrapper img = np.array(self.img) self.prevImg = self.img imgNew = image_utils.gaussianBlurFunc(img) self.displayImg(imgNew) def medianBlurWrap(self): # Median Blur Wrapper img = np.array(self.img) self.prevImg = self.img imgNew = image_utils.medianBlurFunc(img) self.displayImg(imgNew) def cartoonifyWrap(self): img = np.array(self.img) self.prevImg = self.img imgNew = image_utils.cartoonifyFunc(img) self.displayImg(imgNew) def undoFunc(self): self.img = self.prevImg self.displayImg(np.array(self.img)) def origFunc(self): self.prevImg = self.img self.img = self.origImg self.displayImg(np.array(self.img)) def displayDFT(self, x_fft): m, n = x_fft.shape[:] self.frame.pack_forget() self.dftFrame.pack() x_mag = np.log10(np.absolute(x_fft)) * 255 / np.log10(m * n * 255) x_mag = Image.fromarray(x_mag) x_mag = x_mag.resize((min(256, m), min(int(256 * n / m), n)), Image.ANTIALIAS) x_mag = ImageTk.PhotoImage(x_mag) x_freq = (np.angle(x_fft) % 360) * 255 / 360 x_freq = Image.fromarray(x_freq) x_freq = x_freq.resize((min(256, m), min(int(256 * n / m), n)), Image.ANTIALIAS) x_freq = ImageTk.PhotoImage(x_freq) self.magPanel.configure(image=x_mag) self.magPanel.image = x_mag self.freqPanel.configure(image=x_freq) self.freqPanel.image = x_freq def dftWrap(self): img = np.array(self.img) x = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) x_outp_img = fft.fft2d_img(x) self.displayDFT(x_outp_img) def freqMaskWrap(self): m, n = np.array(self.img).shape[:2] lm, ln = np.log2(m), np.log2(m) dm, dn = int(2**np.ceil(lm)) + 1, int(2**np.ceil(ln)) + 1 messagebox.showinfo( "Mask Size", "Mask Size should be (" + str(dm) + "," + str(dn) + ")") path = filedialog.askopenfilename() if len(path) > 0: maskRead = cv2.imread(path, 0) if (maskRead.shape != (dm, dn)): messagebox.showerror( title="Shape Error", message="Shape of mask and image don't match") else: self.prevImg = self.img self.display(image_utils.freqMask(np.array(self.img), maskRead)) else: raise ValueError("Not a valid path") def maskWrap(self): img = np.array(self.img) x = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) x_outp_img = fft.fft2d_img(x) x_mag = image_utils.xMagCreate(x_outp_img) return x_outp_img, x_mag def maskFinal(self, x_outp_img): self.prevImg = self.img img = np.array(self.img) img = cv2.cvtColor(img, cv2.COLOR_RGB2HSV) m = len(img) res = fft.ifft2d_img(x_outp_img) res = np.array(res * 255 / np.max(res), dtype=np.uint8) res = np.array([[[img[i][j][0], img[i][j][1], res[i][j]] for j in range(m)] for i in range(m)]) res = cv2.cvtColor(res, cv2.COLOR_HSV2RGB) self.displayImg(res) def lpmCallBack(self, event, slider, x_outp_img): m = len(x_outp_img) m2 = int((m - 1) / 2) r = slider.get() x_outp_copy = np.copy(x_outp_img) nCircle = np.array([[(i - m2)**2 + (j - m2)**2 for j in range(m)] for i in range(m)]) nCircle = np.where(nCircle > r**2) x_outp_copy[nCircle] = 1 x_mag = image_utils.xMagCreate(x_outp_copy) self.lpmPanel.configure(image=x_mag) self.lpmPanel.image = x_mag def lpmFinal(self, x_outp_img): mx = len(x_outp_img) m2 = int((mx - 1) / 2) r = self.lpmSlider.get() nCircle = np.array([[(i - m2)**2 + (j - m2)**2 for j in range(mx)] for i in range(mx)]) nCircle = np.where(nCircle > r**2) x_outp_img[nCircle] = 0 self.maskFinal(x_outp_img) def lpmWrap(self): x_outp_img, x_mag = self.maskWrap() m = len(x_outp_img) self.lpmPanel.configure(image=x_mag) self.lpmPanel.image = x_mag self.lpmSlider.configure(to=int(np.ceil(m / 2))) self.lpmSlider.set(1) self.lpmSlider.pack(side=TOP) self.lpmSlider.bind( "<ButtonRelease-1>", lambda event, slider=self.lpmSlider, x_outp_img=x_outp_img: self. lpmCallBack(event, slider, x_outp_img)) self.lpmSubButton.configure( command=lambda x_outp_img=x_outp_img: self.lpmFinal(x_outp_img)) self.dftFrame.pack_forget() self.frame.pack_forget() self.hpmFrame.pack_forget() self.bppmFrame.pack_forget() self.bspmFrame.pack_forget() self.lpmFrame.pack() def hpmCallBack(self, event, slider, x_outp_img): mx = len(x_outp_img) m2 = int((mx - 1) / 2) r = slider.get() x_outp_copy = np.copy(x_outp_img) circle = np.array([[(i - m2)**2 + (j - m2)**2 for j in range(mx)] for i in range(mx)]) circle = np.where(circle <= r**2) x_outp_copy[circle] = 1 x_mag = image_utils.xMagCreate(x_outp_copy) self.hpmPanel.configure(image=x_mag) self.hpmPanel.image = x_mag def hpmFinal(self, x_outp_img): mx = len(x_outp_img) m2 = int((mx - 1) / 2) r = self.hpmSlider.get() circle = np.array([[(i - m2)**2 + (j - m2)**2 for j in range(mx)] for i in range(mx)]) circle = np.where(circle <= r**2) x_outp_img[circle] = 0 self.maskFinal(x_outp_img) def hpmWrap(self): x_outp_img, x_mag = self.maskWrap() m = len(x_outp_img) self.hpmPanel.configure(image=x_mag) self.hpmPanel.image = x_mag self.hpmSlider.configure(to=m // 2) self.hpmSlider.set(1) self.hpmSlider.pack(side=TOP) self.hpmSlider.bind( "<ButtonRelease-1>", lambda event, slider=self.hpmSlider, x_outp_img=x_outp_img: self. hpmCallBack(event, slider, x_outp_img)) self.hpmSubButton.configure( command=lambda x_outp_img=x_outp_img: self.hpmFinal(x_outp_img)) self.dftFrame.pack_forget() self.frame.pack_forget() self.lpmFrame.pack_forget() self.bppmFrame.pack_forget() self.bspmFrame.pack_forget() self.hpmFrame.pack() def bppmCallBack(self, event, x_outp_img): mx = len(x_outp_img) m2 = int((mx - 1) / 2) r1 = self.bppmSliderLow.get() r2 = self.bppmSliderHigh.get() assert (r1 <= r2) self.bppmSliderLow.configure(to=r2) self.bppmSliderHigh.configure(from_=r1) x_outp_copy = np.copy(x_outp_img) allVals = np.array([[(i - m2)**2 + (j - m2)**2 for j in range(mx)] for i in range(mx)]) nullVals = np.where(allVals < r1**2) x_outp_copy[nullVals] = 1 nullVals = np.where(allVals > r2**2) x_outp_copy[nullVals] = 1 x_mag = image_utils.xMagCreate(x_outp_copy) self.bppmPanel.configure(image=x_mag) self.bppmPanel.image = x_mag def bppmFinal(self, x_outp_img): mx = len(x_outp_img) m2 = int((mx - 1) / 2) r1 = self.bppmSliderLow.get() r2 = self.bppmSliderHigh.get() allVals = np.array([[(i - m2)**2 + (j - m2)**2 for j in range(mx)] for i in range(mx)]) nullVals = np.where(allVals < r1**2) x_outp_img[nullVals] = 0 nullVals = np.where(allVals > r2**2) x_outp_img[nullVals] = 0 self.maskFinal(x_outp_img) def bppmWrap(self): x_outp_img, x_mag = self.maskWrap() m = len(x_outp_img) self.bppmPanel.configure(image=x_mag) self.bppmPanel.image = x_mag self.bppmSliderHigh.configure(from_=1) self.bppmSliderHigh.configure(to=m // 2) self.bppmSliderHigh.set(m // 2) self.bppmSliderHigh.pack(side=TOP) self.bppmSliderHigh.bind("<ButtonRelease-1>", lambda event, x_outp_img=x_outp_img: self. bppmCallBack(event, x_outp_img)) self.bppmSliderLow.configure(from_=1) self.bppmSliderLow.configure(to=m // 2) self.bppmSliderLow.set(1) self.bppmSliderLow.pack(side=TOP) self.bppmSliderLow.bind("<ButtonRelease-1>", lambda event, x_outp_img=x_outp_img: self. bppmCallBack(event, x_outp_img)) self.bppmSubButton.configure( command=lambda x_outp_img=x_outp_img: self.bppmFinal(x_outp_img)) self.dftFrame.pack_forget() self.frame.pack_forget() self.lpmFrame.pack_forget() self.hpmFrame.pack_forget() self.bspmFrame.pack_forget() self.bppmFrame.pack() def bspmCallBack(self, event, x_outp_img): mx = len(x_outp_img) m2 = int((mx - 1) / 2) r1 = self.bspmSliderLow.get() r2 = self.bspmSliderHigh.get() assert (r1 <= r2) self.bspmSliderLow.configure(to=r2) self.bspmSliderHigh.configure(from_=r1) x_outp_copy = np.copy(x_outp_img) allVals = np.array([[(i - m2)**2 + (j - m2)**2 for j in range(mx)] for i in range(mx)]) nullVals = np.where((allVals - r1**2) * (allVals - r2**2) < 0) x_outp_copy[nullVals] = 1 x_mag = image_utils.xMagCreate(x_outp_copy) self.bspmPanel.configure(image=x_mag) self.bspmPanel.image = x_mag def bspmFinal(self, x_outp_img): mx = len(x_outp_img) m2 = int((mx - 1) / 2) r1 = self.bspmSliderLow.get() r2 = self.bspmSliderHigh.get() allVals = np.array([[(i - m2)**2 + (j - m2)**2 for j in range(mx)] for i in range(mx)]) nullVals = np.where((allVals - r1**2) * (allVals - r2**2) < 0) x_outp_img[nullVals] = 0 self.maskFinal(x_outp_img) def bspmWrap(self): x_outp_img, x_mag = self.maskWrap() m = len(x_outp_img) self.bspmPanel.configure(image=x_mag) self.bspmPanel.image = x_mag self.bspmSliderHigh.configure(from_=1) self.bspmSliderHigh.configure(to=m // 2) self.bspmSliderHigh.set(m // 2) self.bspmSliderHigh.pack(side=TOP) self.bspmSliderHigh.bind("<ButtonRelease-1>", lambda event, x_outp_img=x_outp_img: self. bspmCallBack(event, x_outp_img)) self.bspmSliderLow.configure(from_=1) self.bspmSliderLow.configure(to=m // 2) self.bspmSliderLow.set(1) self.bspmSliderLow.pack(side=TOP) self.bspmSliderLow.bind("<ButtonRelease-1>", lambda event, x_outp_img=x_outp_img: self. bspmCallBack(event, x_outp_img)) self.bspmSubButton.configure( command=lambda x_outp_img=x_outp_img: self.bspmFinal(x_outp_img)) self.dftFrame.pack_forget() self.frame.pack_forget() self.lpmFrame.pack_forget() self.hpmFrame.pack_forget() self.bppmFrame.pack_forget() self.bspmFrame.pack() def fullInverseWrap(self): img = np.array(self.img) self.prevImg = self.img imgNew = filtering.inverseFilter2D(img, self.filter_kernel) self.displayImg(imgNew) def truncatedInverseWrap(self): img = np.array(self.img) self.prevImg = self.img self.truncatedInverseFilter = filtering.getTruncatedInverseFilter2D( img, self.filter_kernel) self.truncatedInverseFrame.pack() self.truncatedInverseSlider.set(1.0) self.truncatedInverseSlider.bind( "<ButtonRelease-1>", lambda event, img=img: self.truncatedInverseCallback(event, img)) def approximateWeinerWrap(self): img = np.array(self.img) self.prevImg = self.img self.weinerFilter = filtering.getApproximateWeinerFilter2D( img, self.filter_kernel) self.weinerFrame.pack() self.weinerSlider.set(1.0) self.weinerSlider.bind( "<ButtonRelease-1>", lambda event, img=img: self.weinerCallback(event, img)) def contrainedLSWrap(self): # TODO: implement img = np.array(self.img) self.prevImg = self.img self.clsFilter = filtering.getConstrainedLSFilter2D( img, self.filter_kernel) self.clsFrame.pack() self.clsSlider.set(1.0) self.clsSlider.bind( "<ButtonRelease-1>", lambda event, img=img: self.clsCallback(event, img))
class Gui: """ This class is built to let the user have a better interaction with game. inputs => root = Tk() => an object which inherits the traits of Tkinter class agent = an object which inherit the traits of mctsagent class. """ agent_type = {1: "UCT", 2: "RAVE", 3: "LAST-GOOD-REPLY", 4: "POOLRAVE", 5: "DECISIVE-MOVE", 6: "UCB1-TUNED"} AGENTS = {"UCT": UctMctsAgent, "RAVE": RaveMctsAgent, "LAST-GOOD-REPLY": LGRMctsAgent, "POOLRAVE": PoolRaveMctsAgent, "DECISIVE-MOVE": DecisiveMoveMctsAgent, "UCB1-TUNED": UCB1TunedMctsAgent} def __init__(self, root, agent_name='UCT'): self.root = root self.root.geometry('1366x690+0+0') self.agent_name = agent_name try: self.agent = self.AGENTS[agent_name]() except KeyError: print("Unknown agent defaulting to basic") self.agent_name = "uct" self.agent = self.AGENTS[agent_name]() self.game = GameState(8) self.agent.set_gamestate(self.game) self.time = 1 self.root.configure(bg='#363636') self.colors = {'white': '#ffffff', 'milk': '#e9e5e5', 'red': '#9c0101', 'orange': '#ee7600', 'yellow': '#f4da03', 'green': '#00ee76', 'cyan': '#02adfd', 'blue': '#0261fd', 'purple': '#9c02fd', 'gray1': '#958989', 'gray2': '#3e3e3e', 'black': '#000000'} global BG BG = self.colors['gray2'] self.last_move = None self.frame_board = Frame(self.root) # main frame for the play board self.canvas = Canvas(self.frame_board, bg=BG) self.scroll_y = ttk.Scrollbar(self.frame_board, orient=VERTICAL) self.scroll_x = ttk.Scrollbar(self.frame_board, orient=HORIZONTAL) # the notebook frame which holds the left panel frames self.notebook = ttk.Notebook(self.frame_board, width=350) self.panel_game = Frame(self.notebook, highlightbackground=self.colors['white']) self.developers = Frame(self.notebook, highlightbackground=self.colors['white']) # Registering variables for: self.game_size_value = IntVar() # size of the board self.game_time_value = IntVar() # time of CPU player self.game_turn_value = IntVar() # defines whose turn is it self.switch_agent_value = IntVar() # defines which agent to play against self.switch_agent_value.set(1) self.game_turn_value.set(1) self.turn = {1: 'white', 2: 'black'} self.game_size = Scale(self.panel_game) self.game_time = Scale(self.panel_game) self.game_turn = Scale(self.panel_game) self.generate = Button(self.panel_game) self.reset_board = Button(self.panel_game) self.switch_agent = Scale(self.panel_game) self.agent_show = Label(self.panel_game, font=('Calibri', 14, 'bold'), fg='white', justify=LEFT, bg=BG, text='Agent Policy: ' + self.agent_name + '\n') self.hex_board = [] # Holds the IDs of hexagons in the main board for implementing the click and play functions self.game_size_value.set(8) self.game_time_value.set(1) self.size = self.game_size_value.get() self.time = self.game_time_value.get() self.board = self.game.board self.board = int_(self.board).tolist() self.gameboard2hexagons(self.board) # building the game board self.logo = PhotoImage(file='image/hex.png') self.uut_logo = PhotoImage(file='image/uut_2.png') self.generate_black_edge() self.generate_white_edge() # Frame_content self.frame_board.configure(bg=BG, width=1366, height=760) self.frame_board.pack(fill=BOTH) self.notebook.add(self.panel_game, text=' Game ') self.notebook.add(self.developers, text=' Developers ') self.notebook.pack(side=LEFT, fill=Y) self.canvas.configure(width=980, bg=BG, cursor='hand2') self.canvas.pack(side=LEFT, fill=Y) self.canvas.configure(yscrollcommand=self.scroll_y.set) self.scroll_y.configure(command=self.canvas.yview) self.scroll_x.configure(command=self.canvas.xview) self.scroll_y.place(x=387, y=482) self.scroll_x.place(x=370, y=500) # Frame_left_panel """ the left panel notebook ----> Game """ self.panel_game.configure(bg=BG) Label(self.panel_game, text='Board size', font=('Calibri', 14, 'bold'), foreground='white', bg=BG, pady=10).pack(fill=X, side=TOP) # label ---> Board size self.game_size.configure(from_=3, to=20, tickinterval=1, bg=BG, fg='white', orient=HORIZONTAL, variable=self.game_size_value) self.game_size.pack(side=TOP, fill=X) Label(self.panel_game, text='Time', font=('Calibri', 14, 'bold'), foreground='white', bg=BG, pady=10).pack(side=TOP, fill=X) # label ---> Time self.game_time.configure(from_=1, to=20, tickinterval=1, bg=BG, fg='white', orient=HORIZONTAL, variable=self.game_time_value) self.game_time.pack(side=TOP, fill=X) Label(self.panel_game, text='Player', font=('Calibri', 14, 'bold'), foreground='white', bg=BG, pady=10).pack(side=TOP, fill=X) # label ---> Turn self.game_turn.configure(from_=1, to=2, tickinterval=1, bg=BG, fg='white', orient=HORIZONTAL, variable=self.game_turn_value) self.game_turn.pack(side=TOP) Label(self.panel_game, text=' ', font=('Calibri', 14, 'bold'), foreground='white', bg=BG).pack(side=TOP, fill=X) # ################################## AGENT CONTROLS ############################# self.agent_show.pack(fill=X, side=TOP) self.switch_agent.configure(from_=1, to=len(self.agent_type), tickinterval=1, bg=BG, fg='white', orient=HORIZONTAL, variable=self.switch_agent_value, ) self.switch_agent.pack(side=TOP, fill=X) # ################################## MOVE LABELS ################################ self.move_label = Label(self.panel_game, font=('Calibri', 15, 'bold'), height=5, fg='white', justify=LEFT, bg=BG, text='PLAY : CLICK A CELL ON GAME BOARD \nMCTS BOT: CLICK GENERATE') self.move_label.pack(side=TOP, fill=X) self.reset_board.configure(text='Reset Board', pady=10, cursor='hand2', width=22, font=('Calibri', 12, 'bold')) self.reset_board.pack(side=LEFT) self.generate.configure(text='Generate', pady=10, cursor='hand2', width=22, font=('Calibri', 12, 'bold')) self.generate.pack(side=LEFT) """ the left panel notebook ---> Developers """ self.developers.configure(bg=BG) Label(self.developers, text='HEXPY', font=('Calibri', 18, 'bold'), foreground='white', bg=BG, pady=5).pack(side=TOP, fill=X) Label(self.developers, text='DEVELOPED BY:\n' + 'Masoud Masoumi Moghadam\n\n' + 'SUPERVISED BY:\n' + 'Dr.Pourmahmoud Aghababa\n' + 'Dr.Bagherzadeh\n\n' + 'SPECIAL THANKS TO:\n' + 'Nemat Rahmani\n', font=('Calibri', 16, 'bold'), justify=LEFT, foreground='white', bg=BG, pady=10).pack(side=TOP, fill=X) Label(self.developers, image=self.uut_logo, bg=BG).pack(side=TOP, fill=X) Label(self.developers, text='Summer 2016', font=('Calibri', 17, 'bold'), wraplength=350, justify=LEFT, foreground='white', bg=BG, pady=30).pack(side=TOP, fill=X) # Binding Actions """ Binding triggers for the actions defined in the class. """ self.canvas.bind('<1>', self.click2play) self.game_size.bind('<ButtonRelease>', self.set_size) self.game_time.bind('<ButtonRelease>', self.set_time) self.generate.bind('<ButtonRelease>', self.click_to_bot_play) self.reset_board.bind('<ButtonRelease>', self.reset) self.switch_agent.bind('<ButtonRelease>', self.set_agent) @staticmethod def top_left_hexagon(): """ Returns the points which the first hexagon has to be created based on. """ return [[85, 50], [105, 65], [105, 90], [85, 105], [65, 90], [65, 65]] def hexagon(self, points, color): """ Creates a hexagon by getting a list of points and their assigned colors according to the game board """ if color is 0: hx = self.canvas.create_polygon(points[0], points[1], points[2], points[3], points[4], points[5], fill=self.colors['gray1'], outline='black', width=2, activefill='cyan') elif color is 1: hx = self.canvas.create_polygon(points[0], points[1], points[2], points[3], points[4], points[5], fill=self.colors['yellow'], outline='black', width=2, activefill='cyan') elif color is 2: hx = self.canvas.create_polygon(points[0], points[1], points[2], points[3], points[4], points[5], fill=self.colors['red'], outline='black', width=2, activefill='cyan') elif color is 3: hx = self.canvas.create_polygon(points[0], points[1], points[2], points[3], points[4], points[5], fill=self.colors['black'], outline='black', width=2) else: hx = self.canvas.create_polygon(points[0], points[1], points[2], points[3], points[4], points[5], fill=self.colors['white'], outline='black', width=2) return hx def generate_row(self, points, colors): """ By getting a list of points as the starting point of each row and a list of colors as the dedicated color for each item in row, it generates a row of hexagons by calling hexagon functions multiple times. """ x_offset = 40 row = [] temp_array = [] for i in range(len(colors)): for point in points: temp_points_x = point[0] + x_offset * i temp_points_y = point[1] temp_array.append([temp_points_x, temp_points_y]) if colors[i] is 0: hx = self.hexagon(temp_array, 0) elif colors[i] is 1: hx = self.hexagon(temp_array, 4) else: hx = self.hexagon(temp_array, 3) row.append(hx) temp_array = [] return row def gameboard2hexagons(self, array): """ Simply gets the game_board and generates the hexagons by their dedicated colors. """ initial_offset = 20 y_offset = 40 temp = [] for i in range(len(array)): points = self.top_left_hexagon() for point in points: point[0] += initial_offset * i point[1] += y_offset * i temp.append([point[0], point[1]]) row = self.generate_row(temp, self.board[i]) temp.clear() self.hex_board.append(row) def generate_white_edge(self): """ Generates the white zones in the left and right of the board. """ init_points = self.top_left_hexagon() for pt in init_points: pt[0] -= 40 for pt in init_points: pt[0] -= 20 pt[1] -= 40 label_x, label_y = 0, 0 init_offset = 20 y_offset = 40 temp_list = [] for i in range(len(self.board)): for pt in range(len(init_points)): init_points[pt][0] += init_offset init_points[pt][1] += y_offset label_x += init_points[pt][0] label_y += init_points[pt][1] label_x /= 6 label_y /= 6 self.hexagon(init_points, 4) self.canvas.create_text(label_x, label_y, fill=self.colors['black'], font="Times 20 bold", text=chr(ord('A') + i)) label_x, label_y = 0, 0 for j in init_points: temp_list.append([j[0] + (len(self.board) + 1) * 40, j[1]]) self.hexagon(temp_list, 4) temp_list.clear() def generate_black_edge(self): """ Generates the black zones in the top and bottom of the board. """ init_points = self.top_left_hexagon() label_x, label_y = 0, 0 temp_list = [] for pt in init_points: pt[0] -= 60 pt[1] -= 40 for t in range(len(init_points)): init_points[t][0] += 40 label_x += init_points[t][0] label_y += init_points[t][1] label_x /= 6 label_y /= 6 for i in range(len(self.board)): self.hexagon(init_points, 3) self.canvas.create_text(label_x, label_y, fill=self.colors['white'], font="Times 20 bold", text=i + 1) label_x, label_y = 0, 0 for pt in init_points: temp_list.append([pt[0] + (len(self.board) + 1) * 20, pt[1] + (len(self.board) + 1) * 40]) self.hexagon(temp_list, 3) temp_list.clear() for j in range(len(init_points)): init_points[j][0] += 40 label_x += init_points[j][0] label_y += init_points[j][1] label_x /= 6 label_y /= 6 def click2play(self, event): """ Whenever any of the hexagons in the board is clicked, depending on the player turns, it changes the color of hexagon to the player assigned color. """ if self.winner() == 'none': x = self.canvas.canvasx(event.x) y = self.canvas.canvasy(event.y) idd = self.canvas.find_overlapping(x, y, x, y) idd = list(idd) if len(idd) is not 0: clicked_cell = idd[0] if any([clicked_cell in x for x in self.hex_board]): coordinated_cell = clicked_cell - self.hex_board[0][0] col = (coordinated_cell % self.size) turn = self.turn[self.game_turn_value.get()] if coordinated_cell % self.size == 0: row = int(coordinated_cell / self.size) else: row = int(coordinated_cell / self.size) cell = str(chr(65 + row)) + str(col + 1) self.move_label.configure(text=str(turn) + ' played ' + cell, justify=LEFT, height=5) if self.board[row][col] == 0: self.board[row][col] = self.game_turn_value.get() if self.game_turn_value.get() == 1: self.game_turn_value.set(2) else: self.game_turn_value.set(1) self.refresh() y = row x = col if turn[0].lower() == 'w': self.last_move = (x, y) if self.game.turn() == GameMeta.PLAYERS["white"]: self.game.play((x, y)) self.agent.move((x, y)) if self.winner() != 'none': messagebox.showinfo(" GAME OVER", " Wow, You won! \n Winner is %s" % self.winner()) return else: self.game.place_white((x, y)) self.agent.set_gamestate(self.game) if self.winner() != 'none': messagebox.showinfo(" GAME OVER", " Wow, You won! \n Winner is %s" % self.winner()) return elif turn[0].lower() == 'b': self.last_move = (x, y) if self.game.turn() == GameMeta.PLAYERS["black"]: self.game.play((x, y)) self.agent.move((x, y)) if self.winner() != 'none': messagebox.showinfo(" GAME OVER", " Wow, You won! \n Winner is %s" % self.winner()) return else: self.game.place_black((x, y)) self.agent.set_gamestate(self.game) if self.winner() != 'none': messagebox.showinfo(" GAME OVER", " Wow, You won! \n Winner is %s" % self.winner()) return else: messagebox.showinfo(" GAME OVER ", " The game is already over! Winner is %s" % self.winner()) def set_size(self, event): """ It changes the board size and reset the whole game. """ self.canvas.delete('all') self.size = self.game_size_value.get() self.game = GameState(self.size) self.agent.set_gamestate(self.game) self.board = self.game.board self.board = int_(self.board).tolist() self.last_move = None self.move_label.config(text='PLAY : CLICK A CELL ON GAME BOARD \nMCTS BOT: CLICK GENERATE', justify='left', height=5) self.refresh() def set_time(self, event) -> None: """ It changes the time for CPU player to think and generate a move. """ self.time = self.game_time_value.get() print('The CPU time = ', self.time, ' seconds') def set_agent(self, event) -> None: """ It changes the time for CPU player to think and generate a move. """ agent_num = self.switch_agent_value.get() self.agent_name = self.agent_type[agent_num] self.agent = self.AGENTS[self.agent_name](self.game) self.agent_show.config(font=('Calibri', 14, 'bold'), justify=LEFT, text='Agent Policy: ' + self.agent_name + '\n') def winner(self) -> str: """ Return the winner of the current game (black or white), none if undecided. """ if self.game.winner == GameMeta.PLAYERS["white"]: return "white" elif self.game.winner == GameMeta.PLAYERS["black"]: return "black" else: return "none" def click_to_bot_play(self, event): """ By pushing the generate button, It produces an appropriate move by using monte carlo tree search algorithm for the player which turn is his/hers! . """ if self.winner() == 'none': self.agent.search(self.time) num_rollouts, node_count, run_time = self.agent.statistics() move = self.agent.best_move() # the move is tuple like (3, 1) self.game.play(move) self.agent.move(move) row, col = move # Relating the 'move' tuple with index of self.board self.board[col][row] = self.game_turn_value.get() if self.game_turn_value.get() == 1: # change the turn of players self.game_turn_value.set(2) else: self.game_turn_value.set(1) self.refresh() player = self.turn[self.game_turn_value.get()] cell = chr(ord('A') + move[1]) + str(move[0] + 1) self.move_label.config(font=('Calibri', 15, 'bold'), justify='left', text=str(num_rollouts) + ' Game Simulations ' + '\n' + 'In ' + str(run_time) + ' seconds ' + '\n' + 'Node Count : ' + str(node_count) + '\n' + player + ' played at ' + cell, height=5) print('move = ', cell) if self.winner() != 'none': messagebox.showinfo(" GAME OVER", " Oops!\n You lost! \n Winner is %s" % self.winner()) else: messagebox.showinfo(" GAME OVER", " The game is already over! Winner is %s" % self.winner()) def refresh(self): """ Delete the whole world and recreate it again """ self.canvas.delete('all') self.hex_board.clear() self.gameboard2hexagons(self.board) self.generate_black_edge() self.generate_white_edge() def reset(self, event): """ By clicking on the Reset button game board would be cleared for a new game """ self.game = GameState(self.game.size) self.agent.set_gamestate(self.game) self.set_size(event) self.last_move = None self.game_turn_value.set(1) self.move_label.config(text='PLAY : CLICK A CELL ON GAME BOARD \nMCTS BOT: CLICK GENERATE', justify='left', height=5)
class ImageSlider(Frame): try: NOIMAGE = PILImage.open( open( os.path.join(os.path.dirname(__file__), 'images/noimages.png'), 'rb')) BUTTONLEFT = PILImage.open( open(os.path.join(os.path.dirname(__file__), 'images/left.png'), 'rb')) BUTTONRIGHT = PILImage.open( open(os.path.join(os.path.dirname(__file__), 'images/right.png'), 'rb')) except FileNotFoundError as e: try: NOIMAGE = PILImage.open(open('images/noimages.png', 'rb')) BUTTONLEFT = PILImage.open(open('images/left.png', 'rb')) BUTTONRIGHT = PILImage.open(open('images/right.png', 'rb')) except Exception as f: raise f def __init__(self, parent, directory=os.getcwd(), placeholder=NOIMAGE, leftarrow=BUTTONLEFT, rightarrow=BUTTONRIGHT, *args, **kw): Frame.__init__(self, parent, *args, **kw) self.directory = directory if placeholder != ImageSlider.NOIMAGE: placeholder = PILImage.open(open(placeholder, 'rb')) if leftarrow != ImageSlider.BUTTONLEFT: leftarrow = PILImage.open(open(leftarrow, 'rb')) if rightarrow != ImageSlider.BUTTONRIGHT: rightarrow = PILImage.open(open(rightarrow, 'rb')) self.placeholder = ImageTk.PhotoImage(placeholder) self.leftarrow, self.rightarrow = ImageTk.PhotoImage( leftarrow), ImageTk.PhotoImage(rightarrow) self.pics, self.photoims = None, None self.scalevar = IntVar() tf = Frame(self, bg=self['bg']) tf.pack(fill='both', expand=True) t1 = Frame(tf, bg=self['bg']) t1.pack(side='left', fill='y') Button( t1, image=self.leftarrow, command=lambda: self.scalevar.set(self.scalevar.get() - 1)).pack( side='left') t2 = Frame(tf, bg=self['bg']) t2.pack(side='left', fill='both', expand=True) self.imagelabel = Label(t2, image=self.placeholder, text='', compound='top') self.imagelabel.pack(side='bottom') t3 = Frame(tf, bg=self['bg']) t3.pack(side='right', fill='y') Button( t3, image=self.rightarrow, command=lambda: self.scalevar.set(self.scalevar.get() + 1)).pack( side='right') self.scalevar.trace('w', lambda *event: self.changepic()) self.slider = Scale(self, variable=self.scalevar, orient='horizontal') self.slider.pack(side='bottom') self.loaddirectory(directory) def loaddirectory(self, directory): self.directory = directory self.pics = [ directory + '/' + pic for pic in os.listdir(directory) if pic.split('.')[-1] in ('gif', 'png', 'jpg') ] pics = [PILImage.open(open(pic, 'rb')) for pic in self.pics] for pic in pics: if max(pic.size) > 200: pic.thumbnail((200, 200), PILImage.ANTIALIAS) self.photoims = [ImageTk.PhotoImage(pic) for pic in pics] if not self.photoims: self.scalevar.set(0) self.slider.configure(from_=0, to_=0) self.imagelabel.configure(image=self.placeholder, text='') else: self.slider.configure(from_=1, to=len(self.photoims)) self.scalevar.set(1) def changepic(self): if not self.photoims: return index = self.scalevar.get() if index == 0: self.scalevar.set(len(self.photoims)) elif index > len(self.photoims): self.scalevar.set(1) else: self.imagelabel.configure(image=self.photoims[index - 1], text=self.pics[index - 1].rsplit( '/', maxsplit=1)[-1]) def getpic(self): return self.pics[self.scalevar.get() - 1]
class CameraWindow(Frame): def __init__(self, root=0, video_source=None): Frame.__init__(self) self.root = root self.cam = video_source self.pic = Canvas(root, width=1000, height=800) self.pic.pack(side='top', fill='both', expand=True) self.memory = deque(maxlen=30 * 1) self.refresh_interval = 20 self.config = { 'grayscale': False, 'gc_on': False, 'xmin': 0, 'xmax': 0, 'ymin': 0, 'ymax': 0, 'zmin': 0, 'zmax': 0, 'draw_rect': False, } button_frame = Frame(root) button_frame.pack(fill='both', expand=True) add_button(button_frame, f'GrayScale', 'black', row=0, col=0, sticky="wse").configure( command=lambda: self.toggle_config('grayscale')) add_button(button_frame, f'Draw Rectangle', 'black', row=0, col=1, sticky="wse").configure( command=lambda: self.toggle_config('draw_rect')) add_button(button_frame, f'Foreground', 'black', row=0, col=2, sticky="wse").configure( command=lambda: self.toggle_config('gc_on')) add_button(button_frame, f'{3 + 1}', 'black', row=0, col=3, sticky="wse").configure( command=lambda: print(3 + 1)) add_button(button_frame, f'{4 + 1}', 'black', row=0, col=4, sticky="wse").configure( command=lambda: print(4 + 1)) add_button(button_frame, f'{5 + 1}', 'black', row=0, col=5, sticky="wse").configure( command=lambda: print(5 + 1)) add_button(button_frame, f'{6 + 1}', 'black', row=0, col=6, sticky="wse").configure( command=lambda: print(6 + 1)) add_button(button_frame, f'{7 + 1}', 'black', row=0, col=7, sticky="wse").configure( command=lambda: print(7 + 1)) add_button(button_frame, f'{8 + 1}', 'black', row=0, col=8, sticky="wse").configure( command=lambda: print(8 + 1)) add_button(button_frame, f'{9 + 1}', 'black', row=0, col=9, sticky="wse").configure( command=lambda: print(9 + 1)) quit = add_button(button_frame, f'Quit', 'black', row=0, col=9, sticky="wse") quit.configure( command=lambda: sys.exit(0)) for _col in range(10): button_frame.grid_columnconfigure(_col, weight=1) button_frame.grid_rowconfigure(0, weight=1) self.scale1 = Scale(root, label="Refresh", from_=10, to=500, command=self.set_refresh_interval) self.scale1.pack(side="left") self.scale2 = Scale(root, label="X-Min", to=255) self.scale2.pack(side="left") self.scale2.configure(command=lambda val: self.set_int_value('xmin', val)) self.scale4 = Scale(root, label="X-Max", to=255) self.scale4.pack(side="left") self.scale4.configure(command=lambda val: self.set_int_value('xmax', val)) self.scale3 = Scale(root, label="Y-Min", to=255) self.scale3.pack(side="left") self.scale3.configure(command=lambda val: self.set_int_value('ymin', val)) self.scale5 = Scale(root, label="Y-Max", to=255) self.scale5.pack(side="left") self.scale5.configure(command=lambda val: self.set_int_value('ymax', val)) self.scale3 = Scale(root, label="Z-Min", to=255) self.scale3.pack(side="left") self.scale3.configure(command=lambda val: self.set_int_value('zmin', val)) self.scale5 = Scale(root, label="Z-Max", to=255) self.scale5.pack(side="left") self.scale5.configure(command=lambda val: self.set_int_value('zmax', val)) self.scale8 = Scale(root, label="_8") self.scale8.pack(side="left") self.update() def set_refresh_interval(self, new_value): self.refresh_interval = int(new_value) def toggle_config(self, param): self.config.update({param: self.config[param] ^ True}) print(f"{param} is now: {self.config[param]}") def set_int_value(self, param, new_value): self.config.update({param: int(new_value)}) print(f"{param} is now: {self.config[param]}") def set_pic_size(self, width, height): self.pic.configure(width=width, height=height) def update(self): ret, frame = self.cam.get_frame() image = self.process_image(frame) photo = Image.fromarray(image) photo = ImageTk.PhotoImage(image=photo) self.memory.append(photo) # reference to photo must persist self.pic.create_image(0, 0, image=photo, anchor='nw') self.root.after(self.refresh_interval, self.update) def process_image(self, image): """Returns Tkinter Canvas photo object""" xmin = self.config['xmin'] xmax = self.config['xmax'] ymin = self.config['ymin'] ymax = self.config['ymax'] zmin = self.config['zmin'] zmax = self.config['zmax'] image = self.strip_color(image, xmin, xmax, ymin, ymax, zmin, zmax) image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) return image def strip_color(self, image, hmin, hmax, smin, smax, vmin, vmax): frame_hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) lower_orange = np.array([hmin, smin, vmin]) upper_orange = np.array([hmax, smax, vmax]) mask_alpha = cv2.inRange(frame_hsv, lower_orange, upper_orange) mask = mask_alpha < 1 frame = cv2.cvtColor(frame_hsv, cv2.COLOR_HSV2BGR) return frame def grab_cut(self, image, rect): mask = np.zeros(image.shape[:2], np.uint8) bdgModel = np.zeros((1, 65), np.float64) fgdModel = np.zeros((1, 65), np.float64) cv2.grabCut(image, mask, rect, bdgModel, fgdModel, 5, cv2.GC_INIT_WITH_RECT) mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')[:, :, np.newaxis] image = image * mask2 return image
command=lambda t: update(2, t), variable=int_vars[2]) # scales for 6 servos servos = [] for i in range(6): servo = (lambda i: Scale(root, from_=0, to_=180, orient=HORIZONTAL, length=600, command=lambda t: update(3 + i, t), variable=int_vars[3 + i]))(i) # closure servo.configure(background="white") servos.append(servo) servo.set(arm.position[i]) servo.grid(row=3 + i, column=1) sx.set(100) sy.set(100) sz.set(100) sx.configure(background="white") sy.configure(background="white") sz.configure(background="white") sx.grid(row=0, column=1) sy.grid(row=1, column=1) sz.grid(row=2, column=1) plt.show() root.mainloop()
class PlayerControlPanel(Frame, IPlayerStateListener): def __init__(self, parent): super().__init__(parent) self.trackNameLabel: Label = None self.volumeScale: Scale = None self.muted = False self.__initView() def __initView(self): self.configure(borderwidth=3, relief=RIDGE) self.configure(height=HEIGHT) ################################################################################### image = Image.open(PLAY_ICON) image = image.resize((32, 32), Image.ANTIALIAS) self.play_icon = PhotoImage(image=image) image = Image.open(PAUSE_ICON) image = image.resize((32, 32), Image.ANTIALIAS) self.pause_icon = PhotoImage(image=image) self.playPauseButton = Button(self, image=self.play_icon) self.playPauseButton.grid(row=0, column=0) ################################################################################### image = Image.open(NEXT_TRACK_ICON) image = image.resize((32, 32), Image.ANTIALIAS) self.next_track_icon = PhotoImage(image=image) self.nextTrackButton = Button(self, image=self.next_track_icon) self.nextTrackButton.grid(row=0, column=1) ################################################################################### image = Image.open(LINEAR_ICON) image = image.resize((32, 32), Image.ANTIALIAS) self.linear_icon = PhotoImage(image=image) image = Image.open(REPEAT_ICON) image = image.resize((32, 32), Image.ANTIALIAS) self.repeat_icon = PhotoImage(image=image) self.musicSelectionModeButton = Button(self, image=self.next_track_icon) self.musicSelectionModeButton.grid(row=0, column=2) ################################################################################### image = Image.open(MUTE_ICON) image = image.resize((32, 32), Image.ANTIALIAS) self.mute_icon = PhotoImage(image=image) image = Image.open(UNMUTE_ICON) image = image.resize((32, 32), Image.ANTIALIAS) self.unmute_icon = PhotoImage(image=image) self.muteButton = Button(self, image=self.mute_icon, command=self.__muteButtonPressed) self.muteButton.grid(row=0, column=3) ################################################################################### self.volumeScale = Scale(self, from_=0, to=100, orient=HORIZONTAL) self.volumeScale.set(50) self.volumeScale.grid(row=0, column=4) ################################################################################### self.trackProgressBar = Progressbar(self, orient=HORIZONTAL, length=300, mode='determinate', maximum=MAXIMUM) self.trackProgressBar.grid(row=0, column=5) ################################################################################### self.timeLabel = Label(self, text='--:--/--:--') self.timeLabel.grid(row=0, column=6) self.trackNameLabel = Label(self) self.trackNameLabel.grid(row=0, column=7) def onPlayerStateUpdated(self, state: PlayerState): self.trackNameLabel.configure(text=state.trackName) if state.trackType is TrackType.MUSIC: self.trackProgressBar.configure(value=int(MAXIMUM * state.trackPosition)) self.playPauseButton.configure(state=NORMAL) else: self.trackProgressBar.configure(value=0) self.playPauseButton.configure(state=DISABLED) if state.playbackState is PlaybackState.PLAYING: self.playPauseButton.configure(image=self.pause_icon) else: self.playPauseButton.configure(image=self.play_icon) if state.musicSelectionMode is MusicSelectionMode.LINEAR: self.musicSelectionModeButton.configure(image=self.linear_icon) else: self.musicSelectionModeButton.configure(image=self.repeat_icon) self.__displayTime(state) def __displayTime(self, state: PlayerState): trackMinutes = int(state.trackLength / 60) trackSeconds = state.trackLength % 60 played = int(state.trackPosition * state.trackLength) playedMinutes = int(played / 60) playedSeconds = played % 60 if state.trackType is not TrackType.MUSIC: self.timeLabel.configure(text='--:--/--:--') else: self.timeLabel.configure( text= f'{playedMinutes:02d}:{playedSeconds:02d}/{trackMinutes:02d}:{trackSeconds:02d}' ) def setPlayerController(self, playerController: IPlayerController): self.playerController = playerController self.volumeScale.configure(command=lambda v: self.__sendVolume()) self.__sendVolume() self.trackProgressBar.bind( "<Button-1>", lambda e: self.onProgressBarClicked(e, playerController)) self.playPauseButton.configure( command=playerController.onPlayPauseClicked) self.nextTrackButton.configure( command=playerController.nextTrackClicked) self.musicSelectionModeButton.configure( command=playerController.changeMusicSelectionModeClicked) def __sendVolume(self): if self.playerController is None: return if self.muted: self.playerController.onVolumeSelected(0) else: self.playerController.onVolumeSelected(self.volumeScale.get()) def __muteButtonPressed(self): self.muted = not self.muted if self.muted: self.muteButton.configure(image=self.unmute_icon) else: self.muteButton.configure(image=self.mute_icon) self.__sendVolume() def onProgressBarClicked(self, event, playerController: IPlayerController): percentage = event.x / event.widget.winfo_width() playerController.seekTo(percentage) def onPlayerEndReached(self): pass