這兩天看opencv-python的HSV色彩空間,在寫程式時發現用HSV來提取圖像區域是件令人噁心的麻煩事。拿閾值分割做個對比,閾值最多也就一兩個參數需要調整;但是HSV需要對三個通道調整上下限,也就是起碼有6個參數。於是乎,就一時興起決定做個小程式,把參數都做成滑動塊,這樣自然方便許多。一開始, ...
這兩天看opencv-python的HSV色彩空間,在寫程式時發現用HSV來提取圖像區域是件令人噁心的麻煩事。拿閾值分割做個對比,閾值最多也就一兩個參數需要調整;但是HSV需要對三個通道調整上下限,也就是起碼有6個參數。於是乎,就一時興起決定做個小程式,把參數都做成滑動塊,這樣自然方便許多。一開始,想直接用opencv來做,但是百度了一下它沒有很好的GUI支持。所以決定還是用python自帶的tkinter來設計UI。
UI設計最重要的還是佈局,之前學CSS就差點搞得我稀里糊塗。tkinter有三種佈局方式,網上說grid是常用的,然而我用了一會,感覺這種excel類型的方法有點死板,唯一的好處是不用計算坐標,所以我佈局滑塊時就使用了grid,其他一律使用place。
我要的程式界面得划出兩塊地方顯示圖片,tkinter沒有專用的控制項,不過可以利用Lable的image屬性來設置背景圖片。並且,image屬性對圖片數據流的格式有所要求,得用PIL模塊里的Image和ImageTk兩個工具先對圖片進行處理。在處理時,我還得對它大小限制一下,要不然不同圖片導進來,佈局就亂了。接下來就導入滑塊和按鈕,調一下佈局罷了,沒啥難度,就是審美得糾結一下。所有控制項都導入以後,為了看起來不那麼單調,本來想是給整個視窗加一個高雅的背景圖的,但是當我把背景改成暗灰色以後,奇跡就發生了——這東西居然還有border。暗灰色背景,配上亮白色邊框,別有一番味道啊!!
最後,在給按鈕和字調下顏色,然後把視窗的預設ico圖標換一下,這還是跟之前的圖片導入類似,所以很快就解決了。剩下的事情就是事件控制了,因為按鈕挺多的,功能也越想越複雜,因此,這部分代碼就留給以後寫,文末貼個程式界面截圖和實現代碼。
1 import os 2 from tkinter import * 3 from PIL import Image, ImageTk 4 5 os.chdir('D:/programe/matlab/img') 6 7 8 9 10 class GUI(): 11 def __init__(self,window): 12 self.window = window 13 #title 14 self.window.title("HsvMaster") 15 #siz=800*600,position=(500,200) 16 self.window.geometry('1000x600+500+200') 17 self.window["bg"] = "DimGray" 18 # icon 19 self.icon = ImageTk.PhotoImage(file='hsv_icon.ico') 20 self.window.call('wm','iconphoto',self.window._w,self.icon) 21 22 23 def create_widgets(self): 24 25 #scale 26 self.hmin_label = Label(self.window,text='色調下限',fg='WhiteSmoke',bg="DimGray") 27 self.hmin_scale = Scale(self.window,orient=HORIZONTAL,from_=0,to=255,resolution=1,tickinterval=50,length=200,width=7,fg='WhiteSmoke',bg="DimGray") 28 self.hmax_label = Label(self.window,text='色調上限',fg='WhiteSmoke',bg="DimGray") 29 self.hmax_scale = Scale(self.window,orient=HORIZONTAL,from_=0,to=255,resolution=1,tickinterval=50,length=200,width=7,fg='WhiteSmoke',bg="DimGray") 30 self.smin_label = Label(self.window,text='飽和度下限',fg='WhiteSmoke',bg="DimGray") 31 self.smin_scale = Scale(self.window,orient=HORIZONTAL,from_=0,to=255,resolution=1,tickinterval=50,length=200,width=7,fg='WhiteSmoke',bg="DimGray") 32 self.smax_label = Label(self.window,text='飽和度上限',fg='WhiteSmoke',bg="DimGray") 33 self.smax_scale = Scale(self.window,orient=HORIZONTAL,from_=0,to=255,resolution=1,tickinterval=50,length=200,width=7,fg='WhiteSmoke',bg="DimGray") 34 self.vmin_label = Label(self.window,text='明度下限',fg='WhiteSmoke',bg="DimGray") 35 self.vmin_scale = Scale(self.window,orient=HORIZONTAL,from_=0,to=255,resolution=1,tickinterval=50,length=200,width=7,fg='WhiteSmoke',bg="DimGray") 36 self.vmax_label = Label(self.window,text='明度上限',fg='WhiteSmoke',bg="DimGray") 37 self.vmax_scale = Scale(self.window,orient=HORIZONTAL,from_=0,to=255,resolution=1,tickinterval=50,length=200,width=7,fg='WhiteSmoke',bg="DimGray") 38 39 # scale position 40 self.hmin_label.grid(row=0, column=0,padx=15) 41 self.hmin_scale.grid(row=0,column=1,pady=2) 42 self.hmax_label.grid(row=1, column=0) 43 self.hmax_scale.grid(row=1,column=1,pady=2) 44 self.smin_label.grid(row=2, column=0) 45 self.smin_scale.grid(row=2,column=1,pady=2) 46 self.smax_label.grid(row=3, column=0) 47 self.smax_scale.grid(row=3,column=1,pady=2) 48 self.vmin_label.grid(row=4, column=0) 49 self.vmin_scale.grid(row=4,column=1,pady=2) 50 self.vmax_label.grid(row=5, column=0) 51 self.vmax_scale.grid(row=5,column=1,pady=2) 52 53 #img 54 self.img = Image.open('man.jpg') 55 self.img = self.img.resize((300, 300)) 56 self.img = ImageTk.PhotoImage(self.img) 57 58 self.orign = Label(self.window,image=self.img,width=300,height=300) 59 self.work = Label(self.window,image=self.img,width=300,height=300) 60 #img position 61 self.orign.place(x=320, y=30) 62 self.work.place(x=650,y=30) 63 64 #Button 65 self.import_button = Button(self.window, text='導入原圖',font=('隸書',45), height=2, width=9,fg='WhiteSmoke',bg="BurlyWood") 66 self.clear_button = Button(self.window, text='刪除所有',font=('隸書',12), height=2, width=15,fg='WhiteSmoke',bg="BurlyWood") 67 self.delete_button = Button(self.window, text='刪除當前',font=('隸書',12), height=2, width=15,fg='WhiteSmoke',bg="BurlyWood") 68 self.switch_button = Button(self.window,text='區域切換',font=('隸書',12), height=2, width=15,fg='WhiteSmoke',bg="BurlyWood") 69 self.save_button = Button(self.window, text='區域暫存',font=('隸書',12), height=2, width=15,fg='WhiteSmoke',bg="BurlyWood") 70 self.merge_button = Button(self.window, text='合併區域',font=('隸書',12), height=2, width=15,fg='WhiteSmoke',bg="BurlyWood") 71 self.picture_button = Button(self.window, text='生成圖片',font=('隸書',12), height=2, width=15,fg='WhiteSmoke',bg="BurlyWood") 72 73 #button position 74 self.import_button.place(x=18,y=400) 75 self.clear_button.place(x=370,y=420) 76 self.delete_button.place(x=570,y=420) 77 self.switch_button.place(x=770,y=420) 78 self.save_button.place(x=370,y=500) 79 self.merge_button.place(x=570,y=500) 80 self.picture_button.place(x=770,y=500) 81 82 83 84 85 def gui_start(): 86 87 my_window = Tk() 88 my_gui = GUI(my_window) 89 my_gui.create_widgets() 90 my_window.mainloop() 91 92 93 gui_start()