在Raspberry Pi 4設計GUI介面,匯入機器學習模型實現商品結帳應用

raspberry*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結

作者/攝影 許钰莨/曾俊霖
難度

★★★☆☆

使用材料 RaspberryPi4 套件-連結
製作時間 2~3小時

本文為前篇『使用Google Teachable Machine 來實現Raspberry Pi 4 的影像分類推論』的延伸,所以本文主要是分享如何更換商品之模型檔,讀者可以沿用前篇所訓練好的模型相關檔案作為商品,直接匯入本文所設計好的GUI介面,同時攝像頭會將照到的人臉和商品拍照,作為資料庫,可進一步優化下次在網頁訓練時的模型。

 

本專題將商品結帳系統設計成GUI介面,讓使用者方便操作,商品結帳系統分辨人臉及商品兩種不同的類別,功能使用如下:

  • 「分辨商品視窗」顯示到商品後,當使用者按下「增加購買商品」鍵,「結帳台」上會出現該商品名稱,反之,若「結帳台」沒有商品,或「分辨商品視窗」顯示非商品(即不是在Teachable Machine所訓練的物件),便會播放”結帳台上沒有商品”的聲音。
  • 當使用者反悔不想購買商品時,可按下「刪除購買商品」鍵,「結帳台」上會出現『———–』的刪除符號,當商品全數刪除後,若又按下「商品結帳」鍵時,會播放”沒有可結帳商品,請先選購商品後再結帳”的聲音。
  • 「結帳台」上有商品,使用者按下「商品結帳」鍵時,會播放”結帳完成謝謝光臨”的聲音。

 

本文將分成幾個部分來介紹:

  1. 介紹 Tkinter 模組。
  2. 將商品結帳系統之相關檔案上傳至RPi4。
  3. 匯入訓練商品之模型檔。
  4. 安裝商品結帳系統播放音訊檔和圖像PIL之套件。
  5. 接上硬體設備之須知
  6. 開啟商品結帳系統程式。
  7. 程式說明。

 

一、介紹Tkinter模組

使用Tkinter ,是因Python 裡已經內建的標準模組,且具有以下兩項優點:

  • 可以跨平台,如: Linux/MAC OS/Windows 可以執行Python的作業系統,而Windows則是安裝Python時會一併安裝Tkinter。即可先在Windows 作業系統中設計介面再到其他作業系統執行,如本文使用的RPi4 。
  • 程式碼簡潔易懂,對於剛接觸人機互動介面的初學者很容易學習,且也很快可以設計出人機介面。

 

因為RPi4的Python中已內建Tkinter ,我們可進一步查詢Tkinter版本,和呼叫內建的測試視窗。

 

(1)Tkinter版本查詢,查詢指令步驟如下:

先開啟RPi4 終端機,並輸入

[pastacode lang=”python” manual=”Python%203%20″ message=”” highlight=”” provider=”manual”/]

輸入 import tkinter ,再輸入

[pastacode lang=”python” manual=”tkinter.Tcl().eval(‘info%20patchlevel’)” message=”” highlight=”” provider=”manual”/]

即可知道本文的Tkinter版本為8.6.9版。

 

(2)呼叫出內建的測試視窗,執行測試函數_test()即可顯示測試視窗

輸入

[pastacode lang=”python” manual=”import%20tkinter” message=”” highlight=”” provider=”manual”/]

再輸入

[pastacode lang=”python” manual=”tkinter._test()” message=”” highlight=”” provider=”manual”/]

若按下「Click me!」,會顯示中括號,按下「QUIT」則退出

二、將商品結帳系統之相關檔案上傳至RPi4

本文準備了Store資料夾,相關的檔案讀者可以從本文提供的連結下載後上傳至RPi4

三、匯入訓練商品之模型檔

如果讀者想重新訓練商品的模型,請參考前篇文章使用Google Teachable Machine  來實現Raspberry Pi 4 的影像分類推論所訓練的模型檔案,將商品的模型檔及標籤檔改名成labels_goods.txt和model_goods.tflite 。

將商品的模型檔及標籤檔透過遠端連線軟體傳送至RPi4中本文已經創建好的Store資料夾中

四、安裝商品結帳系統播放音訊檔和圖像之套件

本文的人機互動介面除可以分辨人臉及商品功能外,也可以播放音訊檔來得知結果,播放音訊檔的套件是使用pygame,故須先安裝此套件:

[pastacode lang=”python” manual=”%24pip3%20install%20pygame” message=”” highlight=”” provider=”manual”/]

本文pygame套件的版本,可利用以下指令查詢:

[pastacode lang=”python” manual=”%24pip3%20list” message=”” highlight=”” provider=”manual”/]

可以得知pygame套件的版本為1.9.6版

還需安裝圖像PIL套件

[pastacode lang=”python” manual=”%24%20%20sudo%20apt-get%20install%20python3-pil.imagetk” message=”” highlight=”” provider=”manual”/]

如果讀者想更換音訊檔,本文是使用文字轉語音的人工語音合成網站,輸入文字後可以依照喜好如:男生、女生、語速、音高,進行調整後下載。當然,讀者有找到不錯的人工語音合成網站也可嘗試使用。

網址連結: https://www.toolfk.com/tool-online-text2video?type=base

 

要注意的一點,本文所下載的音訊語速和音高皆是調到最低值,主要的原因是pygame套件會加速原本音訊檔的語速,這裡請讀者需耐心測試。

本文整理了商品結帳系統所需的音訊檔名稱,及音訊內容

音訊檔名稱 音訊內容(不可隨意更改檔名)
thanks.mp3 結帳完成謝謝光臨
no_goods.mp3 沒有可結帳商品
請先選購商品後再結帳
no_goods_class.mp3 結帳台上沒有商品

 

以上為商品結帳系統所有音訊檔案的說明,音訊內容的語句可以自行設計,但是音訊檔檔名請照原本的名稱,因為tk_cv_goods.py檔案需要和以上音訊檔檔名一致,故不可隨意更改,否則執行時會顯示找不到檔案的錯誤。

 

五、接上硬體設備之須知

開啟程式前,請先確認攝像頭是否插入RPi4的USB3.0孔(藍色USB插孔)

並將喇叭插入3.5mm 音源孔來播出聲音

開啟商品結帳系統。

首先,移動到Store資料夾中

[pastacode lang=”python” manual=”%24%20cd%20Store%2F%20″ message=”” highlight=”” provider=”manual”/]

匯入需要執行影像的檔案

[pastacode lang=”python” manual=”%24%20ln%20-s%20%2Fusr%2Flocal%2Fpython%2Fcv2%2Fpython-3.7%2Fcv2.cpython-37m-arm-linux-gnueabihf.so%20cv2.so” message=”” highlight=”” provider=”manual”/]

六、執行商品結帳系統程式

[pastacode lang=”python” manual=”%24python3%20tk_cv_goods.py” message=”” highlight=”” provider=”manual”/]

執行畫面如下:

七、程式說明

匯入相關函式庫,本文所使用的框架為Tensorflow Lite ,優點在於若部屬在像RPi4的邊緣裝置,可以使模型優化,執行的效率非常快速,而且也可部屬於Android手機。

[pastacode lang=”python” manual=”import%20tkinter%0Aimport%20cv2%0Aimport%20PIL.Image%2C%20PIL.ImageTk%20%0A%0Aimport%20pygame%0A%0Afrom%20tflite_runtime.interpreter%20import%20Interpreter” message=”” highlight=”” provider=”manual”/]

開啟視訊鏡頭

[pastacode lang=”python” manual=”self.vid_0%20%3D%20MyVideoCapture(self.video_source_0)” message=”” highlight=”” provider=”manual”/]

Tkinter的GUI視窗的像素大小設為500*400

[pastacode lang=”python” manual=”%20self.window.geometry(‘500×400’)%0A%20self.window.resizable(False%2C%20False)” message=”” highlight=”” provider=”manual”/]

設置畫布尺寸,為240*180。

[pastacode lang=”python” manual=”self.canvas_goods%20%3D%20tkinter.Canvas(window%2C%20width%20%3D%20240%2C%20height%20%3D%20180)” message=”” highlight=”” provider=”manual”/]

設置畫布尺寸視窗中的於第0行第1列,在網格中使用”sticky”參數來指定對齊方式,可指定n、s、e、w,分別為上、下、左、右對齊,這剛好可用指北針的方位圖來表示位置。

[pastacode lang=”python” manual=”self.canvas_goods.grid(row%3D0%2C%20column%3D1%2C%20sticky%3D%22w%22)” message=”” highlight=”” provider=”manual”/]

設置按鈕尺寸,分別為”增加購買商品”於第1行第1列、”刪除購買商品”於第2行第1列、”商品結帳”於第3行第1列

[pastacode lang=”python” manual=”%20tkinter.Button(window%2C%20text%3D%22%E5%A2%9E%E5%8A%A0%E8%B3%BC%E8%B2%B7%E5%95%86%E5%93%81%22%2C%20command%3Dself.add_goods).grid(row%3D1%2C%20column%3D1)%0A%20tkinter.Button(window%2C%20text%3D%22%E5%88%AA%E9%99%A4%E8%B3%BC%E8%B2%B7%E5%95%86%E5%93%81%22%2C%20command%3Dself.delete_goods).grid(row%3D2%2C%20column%3D1)%0A%20tkinter.Button(window%2C%20text%3D%22%E5%95%86%E5%93%81%E7%B5%90%E5%B8%B3%22%2C%20command%3Dself.check_out).grid(row%3D3%2C%20column%3D1)” message=”” highlight=”” provider=”manual”/]

攝影機還有另一項功能,就是做完影像推論後,會將商品的圖像擷取到goods_collect資料夾中作為資料庫,往後再重新訓練時能提高商品的精確度。

[pastacode lang=”python” manual=”%20%20%20%20def%20add_goods(self)%3A%0A%20%20%20%20%20%20%20%20ret_0%2C%20frame_0%20%3D%20self.vid_0.get_frame()%0A%20%20%20%20%20%20%20%20if%20(ret_0)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20cv2.imwrite(%22goods_collect%2F%22%20%2B%20%22goods-%22%20%2B%20time.strftime(%22%25d-%25m-%25Y-%25H-%25M-%25S%22)%20%2B%20%22.jpg%22%2C%20cv2.cvtColor(frame_0%2C%20cv2.COLOR_RGB2BGR))%0A%20%20%20%20%20%20%20%20%20%20%20%20self.is_goods%20%3D%20Goods_class(frame_0%2Cself.item)%20%20%20%20%0A%20%20%20%20%20%20%20%20self.item%3Dself.item%2B1″ message=”” highlight=”” provider=”manual”/]

當按下”刪除購買商品”時,會將商品刪除,標籤元件顯示於第self.item+1行,第二列。

[pastacode lang=”python” manual=”def%20delete_goods(self)%3A%0A%20%20%20%20%20%20%20%20self.item%20%3D%20self.item%20-1%0A%20%20%20%20%20%20%20%20if%20(self.item%20%3C%3D%200)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.item%3D0%0A%20%20%20%20%20%20%20%20labelExample%20%3D%20tkinter.Label(text%3D%22____________________%22)%0A%20%20%20%20%20%20%20%20labelExample.grid(row%3Dself.item%2B1%2C%20column%3D2)” message=”” highlight=”” provider=”manual”/]

接下來說明如何將影像顯示在GUI視窗上,攝像頭原本的影像大小為320*240

[pastacode lang=”python” manual=”%20%20self.vid%20%3D%20cv2.VideoCapture(video_source)%0A%20%20self.vid.set(cv2.CAP_PROP_FRAME_WIDTH%2C320)%0A%20%20self.vid.set(cv2.CAP_PROP_FRAME_HEIGHT%2C240)” message=”” highlight=”” provider=”manual”/]

但前面已設置畫布尺寸為240*180,必須符合畫布尺寸,所以將影像尺寸縮放成240*180

[pastacode lang=”python” manual=”frame_0_small%3Dcv2.resize(frame_0%2C(240%2C180))” message=”” highlight=”” provider=”manual”/]

最後在Goods_class的函式裡,開始進行圖像分類,最後推論出來的結果,可以顯示商品標籤及信心指數(即預測值)

[pastacode lang=”python” manual=”%23%E5%81%9A%E5%9C%96%E5%83%8F%E5%88%86%E9%A1%9E%0Aclass%20Goods_class%3A%0A%20%20%20%20def%20load_labels(self%2Cpath)%3A%0A%20%20%20%20%20%20%20%20with%20open(path%2C%20’r’)%20as%20f%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%7Bi%3A%20line.strip()%20for%20i%2C%20line%20in%20enumerate(f.readlines())%7D%0A%0A%20%20%20%20def%20set_input_tensor(self%2C%20interpreter%2C%20image)%3A%0A%20%20%20%20%20%20%20%20tensor_index%20%3D%20interpreter.get_input_details()%5B0%5D%5B’index’%5D%0A%20%20%20%20%20%20%20%20input_tensor%20%3D%20interpreter.tensor(tensor_index)()%5B0%5D%0A%20%20%20%20%20%20%20%20input_tensor%5B%3A%2C%20%3A%5D%20%3D%20image%0A%20%20%20%20%0A%20%20%20%20%0A%20%20%20%20def%20classify_image(self%2C%20interpreter%2C%20image%2C%20top_k%3D1)%3A%0A%20%20%20%20%20%20%20%20self.set_input_tensor(interpreter%2C%20image)%0A%20%20%20%20%20%20%20%20interpreter.invoke()%0A%20%20%20%20%20%20%20%20output_details%20%3D%20interpreter.get_output_details()%5B0%5D%0A%20%20%20%20%20%20%20%20output%20%3D%20np.squeeze(interpreter.get_tensor(output_details%5B’index’%5D))%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20if%20output_details%5B’dtype’%5D%20%3D%3D%20np.uint8%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20scale%2C%20zero_point%20%3D%20output_details%5B’quantization’%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20output%20%3D%20scale%20*%20(output%20-%20zero_point)%0A%0A%20%20%20%20%20%20%20%20ordered%20%3D%20np.argpartition(-output%2C%20top_k)%0A%20%20%20%20%20%20%20%20return%20%5B(i%2C%20output%5Bi%5D)%20for%20i%20in%20ordered%5B%3Atop_k%5D%5D%0A%0A%0A%20%20%20%20def%20__init__(self%2Cimage_src%2Citem)%3A%0A%20%20%20%20%20%20%20%20labels%20%3D%20self.load_labels(‘%2Fhome%2Fpi%2FStore%2Flabels_goods.txt’)%0A%20%20%20%20%20%20%20%20interpreter%20%3D%20Interpreter(‘%2Fhome%2Fpi%2FStore%2Fmodel_goods.tflite’)%0A%20%20%20%20%20%20%20%20interpreter.allocate_tensors()%20%0A%20%20%20%20%20%20%20%20_%2C%20height%2C%20width%2C%20_%20%3D%20interpreter.get_input_details()%5B0%5D%5B’shape’%5D%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%23%E9%A9%97%E8%AD%89%E7%95%AB%E9%9D%A2%E5%B0%BA%E5%AF%B8%E7%82%BA224X224%EF%BC%8C%E6%94%B9%E8%AE%8A%E5%B0%BA%E5%AF%B8%E6%9C%83%E9%A9%97%E8%AD%89%E9%8C%AF%E8%AA%A4%0A%20%20%20%20%20%20%20%20image%3Dcv2.resize(image_src%2C(224%2C224))%0A%0A%20%20%20%20%20%20%20%20results%20%3D%20self.classify_image(interpreter%2C%20image)%0A%20%20%20%20%20%20%20%20label_id%2C%20prob%20%3D%20results%5B0%5D%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%23%E9%A1%AF%E7%A4%BA%E5%95%86%E5%93%81%E6%A8%99%E7%B1%A4id%E5%8F%8A%E4%BF%A1%E5%BF%83%E6%8C%87%E6%95%B8%0A%20%20%20%20%20%20%20%20print(label_id%2C%20prob)” message=”” highlight=”” provider=”manual”/]

筆者在最後加上”print(label_id, prob)”,可以使讀者了解圖片是如何被分類出來,其中紅框表示商品標籤id,黃框為預測值

 

*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結 (本篇文章完整範例程式請至原文下載)

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *