你觉得这篇文章怎么样? 帮助我们为您提供更好的内容。
Thank you! Your feedback has been received.
There was a problem submitting your feedback, please try again later.
你觉得这篇文章怎么样?
作者 |
许钰莨/曾俊霖 |
難度 |
普通 |
本文为前篇『使用Google Teachable Machine 来实现Raspberry Pi 4 的影像分类推论』的延伸,所以本文主要是分享如何更换商品之模型文件,读者可以沿用前篇所训练好的模型相关档案作为商品,直接汇入本文所设计好的GUI接口,同时摄像头会将照到的人脸和商品拍照,作为数据库,可进一步优化下次在网页训练时的模型。
本专题将商品结账系统设计成GUI接口,让用户方便操作,商品结账系统分辨人脸及商品两种不同的类别,功能使用如下:
- 「分辨商品窗口」显示到商品后,当使用者按下「增加购买商品」键,「结账台」上会出现该商品名称,反之,若「结账台」没有商品,或「分辨商品窗口」显示非商品(即不是在Teachable Machine所训练的对象),便会播放"结账台上没有商品"的声音。
- 当使用者反悔不想购买商品时,可按下「删除购买商品」键,「结账台」上会出现『-----------』的删除符号,当商品全数删除后,若又按下「商品结账」键时,会播放"没有可结账商品,请先选购商品后再结账"的声音。
- 「结账台」上有商品,使用者按下「商品结账」键时,会播放"结账完成谢谢光临"的声音。
本文将分成几个部分来介绍:
一、介绍 Tkinter 模块。
二、将商品结账系统之相关档案上传至RPi4。
三、汇入训练商品之模型文件。
四、安装商品结账系统播放音频文件和图像PIL之套件。
五、接上设备之须知
六、开启商品结账系统程序。
七、程序说明。
一、介绍Tkinter模块
使用Tkinter ,是因Python 里已经内建的标准模块,且具有以下两项优点:
- 可以跨平台,如: Linux/MAC OS/Windows 可以执行Python的操作系统,而Windows则是安装Python时会一并安装Tkinter。即可先在Windows 操作系统中设计图形介面再到其他操作系统执行,如本文使用的RPi4 。
- 程序代码简洁易懂,对于刚接触人机互动接口的初学者很容易学习,且也很快可以设计出人机介面。
因为RPi4的Python中已内建Tkinter ,我们可进一步查询Tkinter版本,和呼叫内建的测试窗口。
(1)Tkinter版本查询,查询指令步骤如下:
先开启RPi4 终端机,并输入
Python 3
输入
import tkinter
再输入
tkinter.Tcl().eval('info patchlevel')
即可知道本文的Tkinter版本为8.6.9版。
(2)呼叫出内建的测试窗口,执行测试函数_test()即可显示测试窗口
输入
import tkinter
再输入
tkinter._test()
若按下「Click me!」,会显示中括号,按下「QUIT」则退出
二、将商品结账系统之相关档案上传至RPi4
本文准备了Store文件夹,相关的档案读者可以从本文提供的连结下载后上传至RPi4
三、汇入训练商品之模型文件。
如果读者想重新训练商品的模型,请参考前篇文章『使用Google Teachable Machine 来实现Raspberry Pi 4 的影像分类推论』所训练的模型档案,将商品的模型文件及卷标文件改名成labels_goods.txt和model_goods.tflite 。
将商品的模型文件及卷标文件透过远程联机软件传送至RPi4中本文已经创建好的Store文件夹中
四、安装商品结账系统播放音频文件和图像PIL之套件
本文的人机互动接口除可以分辨人脸及商品功能外,也可以播放音讯文件来得知结果,播放音讯文件的套件是使用pygame,故须先安装此套件:
$pip3 install pygame
本文pygame套件的版本,可利用以下指令查询:
$pip3 list
可以得知pygame套件的版本为1.9.6版
还需安装图像PIL套件
$ sudo apt-get install python3-pil.imagetk
如果读者想更换音讯文件,本文是使用文字转语音的人工语音合成网站,输入文字后可以依照喜好如:男生、女生、语速、音高,进行调整后下载。当然,读者有找到不错的人工语音合成网站也可尝试使用。
网址连结: 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文件夹中
$ cd Store/
汇入需要执行影像的档案
$ ln -s /usr/local/python/cv2/python-3.7/cv2.cpython-37m-arm-linux-gnueabihf.so cv2.so
六、执行商品结账系统程序
$python3 tk_cv_goods.py
执行画面如下:
执行程序影片
七、程序说明
汇入相关函式库,本文所使用的框架为Tensorflow Lite ,优点在于若部属在像RPi4的边缘装置,可以使模型优化,执行的效率非常快速,而且也可部属于Android手机。
import tkinter
import cv2
import PIL.Image, PIL.ImageTk
import pygame
from tflite_runtime.interpreter import Interpreter
开启视讯镜头
self.vid_0 = MyVideoCapture(self.video_source_0)
Tkinter的GUI窗口的像素大小设为500*400
self.window.geometry('500x400')
self.window.resizable(False, False)
设置画布尺寸,为240*180。
self.canvas_goods = tkinter.Canvas(window, width = 240, height = 180)
设置画布尺寸窗口中的于第0行第1列,在网格中使用"sticky"参数来指定对齐方式,可指定n、s、e、w,分别为上、下、左、右对齐,这刚好可用指北针的方位图来表示位置。
self.canvas_goods.grid(row=0, column=1, sticky="w")
设置按钮尺寸,分别为"增加购买商品"于第1行第1列、"删除购买商品"于第2行第1列、"商品结账"于第3行第1列
tkinter.Button(window, text="增加购买商品", command=self.add_goods).grid(row=1, column=1)
tkinter.Button(window, text="删除购买商品", command=self.delete_goods).grid(row=2, column=1)
tkinter.Button(window, text="商品结账", command=self.check_out).grid(row=3, column=1)
摄影机还有另一项功能,就是做完影像推论后,会将商品的图像撷取到goods_collect文件夹中作为数据库,往后再重新训练时能提高商品的精确度。
def add_goods(self):
ret_0, frame_0 = self.vid_0.get_frame()
if (ret_0):
cv2.imwrite("goods_collect/" + "goods-" + time.strftime("%d-%m-%Y-%H-%M-%S") + ".jpg", cv2.cvtColor(frame_0, cv2.COLOR_RGB2BGR))
self.is_goods = Goods_class(frame_0,self.item)
self.item=self.item+1
当按下"删除购买商品"时,会将商品删除,卷标组件显示于第self.item+1行,第二列。
def delete_goods(self):
self.item = self.item -1
if (self.item <= 0):
self.item=0
labelExample = tkinter.Label(text="____________________")
labelExample.grid(row=self.item+1, column=2)
接下来说明如何将影像显示在GUI窗口上,摄像头原本的影像大小为320*240
self.vid = cv2.VideoCapture(video_source)
self.vid.set(cv2.CAP_PROP_FRAME_WIDTH,320)
self.vid.set(cv2.CAP_PROP_FRAME_HEIGHT,240)
但前面已设置画布尺寸为240*180,必须符合画布尺寸,所以将影像尺寸缩放成240*180
frame_0_small=cv2.resize(frame_0,(240,180))
最后在Goods_class的函式里,开始进行图像分类,最后推论出来的结果,可以显示商品卷标及信心指数(即预测值)
#做图像分类
class Goods_class:
def load_labels(self,path):
with open(path, 'r') as f:
return {i: line.strip() for i, line in enumerate(f.readlines())}
def set_input_tensor(self, interpreter, image):
tensor_index = interpreter.get_input_details()[0]['index']
input_tensor = interpreter.tensor(tensor_index)()[0]
input_tensor[:, :] = image
def classify_image(self, interpreter, image, top_k=1):
self.set_input_tensor(interpreter, image)
interpreter.invoke()
output_details = interpreter.get_output_details()[0]
output = np.squeeze(interpreter.get_tensor(output_details['index']))
if output_details['dtype'] == np.uint8:
scale, zero_point = output_details['quantization']
output = scale * (output - zero_point)
ordered = np.argpartition(-output, top_k)
return [(i, output[i]) for i in ordered[:top_k]]
def __init__(self,image_src,item):
labels = self.load_labels('/home/pi/Store/labels_goods.txt')
interpreter = Interpreter('/home/pi/Store/model_goods.tflite')
interpreter.allocate_tensors()
_, height, width, _ = interpreter.get_input_details()[0]['shape']
#验证画面尺寸为224X224,改变尺寸会验证错误
image=cv2.resize(image_src,(224,224))
results = self.classify_image(interpreter, image)
label_id, prob = results[0]
#显示商品卷标id及信心指数
print(label_id, prob)
笔者在最后加上"print(label_id, prob)",可以使读者了解图片是如何被分类出来,其中红框表示商品标签id,黄框为预测值
评论