GUI布局Tkinter完善Python小項(xiàng)目
本次 Python 小項(xiàng)目主要功能:調(diào)用電腦攝像頭實(shí)現(xiàn)拍照,并使用百度 API 接口實(shí)現(xiàn)圖像識(shí)別。
上次完成了API的封裝,這次完成GUI的布局。具體成品如下所示。
拍照保存圖片采用的是opencv中的imwrite方法,具體的示例查看上上篇文章。
Tkinter 布局邏輯中最推薦使用的Grid布局。實(shí)現(xiàn)機(jī)制是將Widget邏輯上分割成表格,在指定的位置放置想要的Widget就可以了。
Grid布局參數(shù)說(shuō)明
具體main.py代碼如下。
- """
 - @Author:Runsen
 - @WeChat:RunsenLiu
 - @微信公眾號(hào):Python之王
 - @CSDN:https://blog.csdn.net/weixin_44510615
 - @Github:https://github.com/MaoliRUNsen
 - @Date:2020/11/29
 - """
 - import time
 - import cv2 as cv # pip install opencv-python
 - import tkinter as tk
 - from tkinter import ttk # 下拉框依賴庫(kù)
 - from tkinter import scrolledtext # 滾動(dòng)文本框依賴庫(kù)
 - from tkinter import N,E,S,W
 - # 引入Baidu_API類 (上次文章)
 - from baidu_api import Baidu_API
 - # 拍照
 - def take_a_photo():
 - # 調(diào)用筆記本內(nèi)置攝像頭,所以參數(shù)為0,如果有其他的攝像頭可以調(diào)整參數(shù)為1,2
 - cap = cv.VideoCapture(0)
 - img_path = str(int(time.time())) + '.jpg'
 - while True:
 - # 從攝像頭讀取圖片
 - sucess, img = cap.read()
 - # 轉(zhuǎn)為灰度圖片
 - # gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)#
 - # 顯示攝像頭
 - cv.imshow('----------please enter "s" to take a picture----------', img)
 - # 保持畫(huà)面的持續(xù),無(wú)限期等待輸入
 - k = cv.waitKey(1)
 - if k == 27:
 - # 通過(guò)esc鍵退出攝像
 - cv.destroyAllWindows()
 - break
 - elif k == ord("s"):
 - # 通過(guò)s鍵保存圖片,并退出。
 - cv.imwrite(img_path, img)
 - cv.destroyAllWindows()
 - break
 - # 關(guān)閉攝像頭
 - cap.release()
 - # 打印日志
 - scr.insert(tk.END, '[{}]拍攝成功...\n'.format(time.strftime('%Y-%m-%d %H:%M:%S')))
 - # 返回圖像
 - return img_path
 - # ----------圖形界面各個(gè)組件功能的設(shè)計(jì)----------
 - # 清除窗口日志
 - def clear_the_window():
 - scr.delete(1.0, tk.END)
 - # 退出軟件
 - def exit():
 - win.quit()
 - # 下拉框選項(xiàng)選擇
 - def select_ttk(event):
 - global numberChosen
 - # 顏值評(píng)分
 - if numberChosen.current() == 1:
 - # 獲取圖像
 - img_path = take_a_photo()
 - try:
 - # 向API發(fā)送圖像并獲取信息
 - score, age, gender, race = Baidu_API().face_detect(img_path=img_path)
 - # 打印日志
 - scr.insert(tk.END, '[{}]年齡「{}」性別「{}」人種「{}」\n'.format(time.strftime('%Y-%m-%d %H:%M:%S'), age, gender, race))
 - scr.insert(tk.END, '[{}]顏值評(píng)分為:{}/100 分\n'.format(time.strftime('%Y-%m-%d %H:%M:%S'), score))
 - except:
 - scr.insert(tk.END, '[{}]{}'.format(time.strftime(time.strftime('%Y-%m-%d %H:%M:%S')),
 - Baidu_API().face_detect(img_path=img_path)))
 - # 手勢(shì)識(shí)別
 - if numberChosen.current() == 2:
 - scr.insert(tk.END, '[{}]請(qǐng)將您的手勢(shì)放置攝像頭前...\n'.format(time.strftime('%Y-%m-%d %H:%M:%S')))
 - time.sleep(0.1)
 - img_path = take_a_photo()
 - try:
 - classname_en, classname_zh = Baidu_API().gesture(img_path=img_path)
 - scr.insert(tk.END,
 - '[{}]手勢(shì)大意:{}({})\n'.format(time.strftime('%Y-%m-%d %H:%M:%S'), classname_zh, classname_en))
 - except:
 - scr.insert(tk.END,
 - '[{}]{}\n'.format(time.strftime('%Y-%m-%d %H:%M:%S'), Baidu_API().gesture(img_path=img_path)))
 - # 智能人臉摳圖
 - if numberChosen.current() == 3:
 - scr.insert(tk.END, '智能人臉摳圖\n'.format(time.strftime('%Y-%m-%d %H:%M:%S')))
 - img_path = take_a_photo()
 - out_path = str(int(time.time())) + '.jpg'
 - try:
 - Baidu_API().body_seg(img_path=img_path, out_path=out_path)
 - scr.insert(tk.END, '完成智能人臉摳圖')
 - except:
 - scr.insert(tk.END, '[{}]{}\n'.format(time.strftime('%Y-%m-%d %H:%M:%S'),
 - Baidu_API().body_seg(img_path=img_path, out_path=None)))
 - # -------------創(chuàng)建窗口--------------
 - win = tk.Tk()
 - win.title('客官先關(guān)注微信公眾號(hào):Python之王!')
 - win.geometry('600x300')
 - # ------------窗口組件設(shè)計(jì)-----------
 - # grid中的參數(shù):column, columnspan, in, ipadx, ipady, padx, pady, row, rowspan,sticky
 - # 下拉框組件
 - number = tk.StringVar
 - numberChosen = ttk.Combobox(win, textvariable=number)
 - numberChosen['value'] = ('please select', '給我的顏值打個(gè)分吧!', '識(shí)別一下我的手勢(shì)', '智能人臉摳圖')
 - numberChosen.current(0) # 設(shè)置默認(rèn)值為第一個(gè),即默認(rèn)下拉框中的內(nèi)容
 - numberChosen.grid(row=1, column=1, rowspan=1, sticky=N + E + S + W)
 - # 下拉框觸發(fā)動(dòng)作 (綁定點(diǎn)擊事件)
 - numberChosen.bind('<<ComboboxSelected>>', select_ttk)
 - # 清除按鈕組件
 - tk.Button(win, cnf={'text': 'clear', 'command': clear_the_window}).grid(row=1, column=2, ipadx=1, sticky=N + E + S + W)
 - # 退出按鈕組件
 - tk.Button(win, cnf={'text': 'exit', 'command': exit}).grid(row=1, column=3, ipadx=1, sticky=N + E + S + W)
 - # 滾動(dòng)文本框組件
 - scr = scrolledtext.ScrolledText(win)
 - scr.grid(row=2, column=1, columnspan=3, rowspan=1)
 - # 使窗口一直顯示
 - win.mainloop()
 
最后使用Pyinstaller打包即可。
Java 一次編譯到處運(yùn)行,Python沒(méi)有這么好本事,Python有一個(gè)pyinstaller可以打包exe,在window平臺(tái)下運(yùn)行,這也是Python非常不好的方面,而且打包出來(lái)的占用內(nèi)存非常的大
安裝:pip install pyinstaller。Pyinstaller具體參數(shù)如下所示。
注意點(diǎn):有的時(shí)候在代碼最后面加上input(),這樣打開(kāi)exe不會(huì)一散而過(guò)。由于上面代碼本身就是窗口一直顯示,無(wú)需加上input()。
在打包時(shí)候,并沒(méi)有提示錯(cuò)誤,可以順利打包成 exe 文件。但是在運(yùn)行打包好的軟件時(shí),會(huì)提示找不到模塊,本人遇到的是找不到第三方模塊,例如 cv2 。這時(shí)候需要在打包時(shí)指定 -p 參數(shù),后面跟上 python 目錄下的第三方庫(kù)模板目錄路徑 site-packages ,再打包就成功了。
cd 到代碼的目錄執(zhí)行 pyinstaller main.py -F -p F:\anaconda\Lib\site-packages如果Pyinstaller打包報(bào)錯(cuò)numpy.core.multiarray failed to import,這是numpy和opencv的不兼容,可以降低numpy的版本。




















 
 
 











 
 
 
 