树莓派python离线语音识别_基于树莓派3b的离线人脸识别相机-i See U

一、主要功能需求

做成手持设备

可离线进行人脸比对,并检索出最相似的人

可录入人脸信息及脸纹(最终在输入信息时还是少不了要用键盘)

识别模式

信息录入模式

二、运行环境

(一)硬件环境

(二)软件环境

操作系统--RASPBIAN

python 3.6

dlib 19

OpenCV 3.4

(三)GUI

python3.6自带的tkinter

三、实现思路

1、使用tkinter作为UI库。

2、UI主程序启动后,主线程负责图形界面刷新和操作响应,所有业务逻辑均以线程的方式实现。这样在进行耗时的功能运算时也不会在界面上停顿。

3、设置一个“模式切换”按钮用于在“识别模式”和“信息录入模式”间进行切换

4、拍照按钮根据当前所处的模式进行“识别”或“信息录入”操作

5、“代表队”和“姓名”在识别模式下用于显示识别出的信息。信息录入模式下用于输入所对应的信息

四、程序开发中的主要技术点说明和体会

(一)用tkinter制作UI

关于tkinter网上一抓一大把,这里说一下使用的体会:

1、python 3 import的时候用:import tkinter,而python 2 import的时候应该用:import Tkinter

2、frame控件用width和height设置大小没卵用,实际大小还得看frame上放置的其他可见控件(如:label、entry、text等)的实际大小。

3、除了主窗口外,其他可见或不可见的空间在定义后要用pack方法,这样才能在界面上出现。假如一个frame没有用pack方法,那么放在这个frame上的所有控件都不可见。

4、mainloop()必不可少。这个方法可以在调用的时候显示调用,也可以在类的init()方法里调用。这个循环的作用就是不断的检测UI上的中断,以及刷新界面。

(二)人脸识别

其实人脸识别是一个笼统的说法,它包括这几个过程:图像采集-->人脸检测-->图像预处理-->特征提取(获取脸纹)-->比对识别。

1、图像采集

本项目用OpenCV,通过摄像头拍摄进行采集。OpenCV用read方法取出的帧是BGR通道的,而dlib只能处理rgb和gray图片,所以OpenCV取出帧之后,一定要用cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)或者cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)进行转换。

2、人脸检测

用dlib的detector(rgbImage, 1)方法就可以检测出图片中的人脸了,这个方法返回矩形特征框的坐标,faces数据结构见下图:

image.png

3、图像预处理

shape_predictor = dlib.shape_predictor(predictor_path)定义了一个预处理器,使用这个预处理器把图片中的人脸进行预处理。每调用一次预处理一个人脸:

face_shape = shape_predictor(rgbImage, faces[Index])

4、特征提取(获取脸纹)

model = dlib.face_recognition_model_v1(MODEL_PATH)定义了一个模型提取器,使用这个提取器就能提取“脸纹”特征,每调用一次获取一张图片中的一个脸纹,参数中的face_shape就是上一步预处理所返回的结果

face_fingerprint = model.compute_face_descriptor(rgbImage, face_shape)

5、将特征保存到npy文件

上一步获取到的特征是一个多维向量(可能叫这个名字吧),可以保存到文件中,供后续使用的。保存方法直接看源码:

def saveFaceFingerprintToFile(faceFingerprint, npyFilePath):

vectors = np.array([])

for i, num in enumerate(faceFingerprint):

vectors = np.append(vectors, num)

np.save(npyFilePath, vectors)

if os.path.exists(npyFilePath):

return True

else:

return False

6、特征比对

用欧式向量法比对两个人脸的128维特征,差越小就越“像”。一般小于0.4可以认为是同一个人,当然也可以限定得更严格。这里要说明一下,本项目进行人脸特征比对的时候,用的是遍历法。也就是要与特征库中所有的人脸进行比对,把最“像”的人脸出来。

def featureCompare(self, faceFingerprint_1, faceFingerprint_2):

feature_1 = np.array(faceFingerprint_1)

feature_2 = np.array(faceFingerprint_2)

dist = np.sqrt(np.sum(np.square(feature_1 - feature_2)))

return dist

(三)主要方法/函数的思路

1、APP类的初始化过程

1、初始化窗体,并设置其参数

2、初始化一些全局变量

3、初始化人脸识别器

4、初始化摄像头

5、初始化界面布局

6、调用 start_core_thread 方法启动“视频显示”(执行video_loop方法)和“图片显示”(执行display_pic方法)线程。

7、mainloop()循环

2、界面布局的设计

1、左右各放1个frame,左边的frame用于放置显示视频的控件,右边的frame放置信息显示和操作控件。

2、程序逻辑上,先把一层层的frame布放好,然后再按“从左到右,从上到下”的顺序逐个定义frame上摆放的各个控件。

3、识别模式下“拍摄”按钮的实现逻辑

1、使2个按钮失效

2、生成执行“start_recognizer”方法的线程,由线程去执行识别操作,执行完后恢复按钮。

4、信息录入模式下“拍摄”按钮的实现逻辑:

1、获取输入框内容并去除首位空格

2、判断代表队和姓名两项是否有其中一项为空

3、如果均不为空,则判断根据代表队和姓名所构成的npy文件是否已存在。文件名格式为:“代表队-姓名.npy”,

4、同时生成将要保存的图片文件的文件名,格式为:"代表队-姓名.jpg"。

5、使2个按钮失效后发送信号。

6、生成执行“handle_picture”方法的线程,由线程去执行图片处理操作。

5、人脸识别线程“start_recognizer”的实现逻辑:

1、线程启动后若信号被激活,把当前帧缩小一半后另存为需处理图片

2、BGR转换为RGB格式

3、计算需处理帧中有多少个人脸

4、如果人脸数大于1,调用recognizer类的getMaxFaceFingerprint方法,获得帧里最大人脸的“脸纹”

5、根据获得的“脸纹”,调用searchSimilarPlayer方法遍历比对已载入的人脸脸纹信息。

6、若相似度大于阀值在log控件中显示代表队和姓名,并根据代表队和姓名,把存在目录中的照片换为ImageTk格式的图片,放入图片显示队列。由“图片显示”线程显示出来

7、5秒后,把默认图片放入图片显示队列。由“图片显示”线程显示出来

8、若相似度小于阀值,则在log控件中显示识别失败字样

9、恢复2个按钮为可用。

6、图片处理线程“handle_picture”的实现逻辑:

1、线程启动后若信号被激活,先获取摄像头当前的原始帧,另存为需处理帧,以这个需处理帧作为后续识别处理的基准

2、需处理帧缩小到原始大小的一半

3、因为用CV2捕获的图片是BGR格式的,所以把BGR转换为RGB

4、计算需处理帧中有多少个人脸

5、如果人脸数大于1,调用recognizer类的getMaxFaceFingerprint方法,获得帧里最大人脸的“脸纹”

6、把“脸纹”保持到npy文件,把需处理帧保存为jpg文件

7、把需处理帧转换为ImageTk格式的图片,放入图片显示队列。由“图片显示”线程显示出来

8、5秒后,把默认图片放入图片显示队列。由“图片显示”线程(类初始化的时候已经运行了)显示出来。

7、用label控件显示实时视频“video_loop”的实现逻辑

1、用cv2.cvtColor方法将BGR格式图片转换为RGB格式

2、用Image.fromarray方法转换为PIL适用的格式

3、用ImageTk.PhotoImage方法转换为tkinter适用的格式

4、把tkinter适用的格式让label显示

5、用self.root.after(1, self.video_loop)方法做循环,处理并显示下一帧。

8、用label控件按需显示图片的实现逻辑(display_pic方法)

1、这是一个死循环方法,被调用后会一直运行,知道父线程退出。

2、一开始就判断队列是否为空。这个队列是专门传递imgtk类型图片的。

3、如果不为空,则取出。如果为空(就是没有其他程序往队列里放图片),就进入下一次循环。

4、label的image属性设置为刚取出的imgtk类型的图片

5、然后就显示了

6、再然后就进入下一次循环了

其他函数或方法在需要显示图片的时候,先用put_nowait()方法往队列里面塞你想显示的图片,sleep几秒后,再用put_nowait()方法往队列里塞默认图片。这样的效果就是,没有操作的时候都显示默认图片,只有操作成功了才显示需要显示的图片。

六、源码及说明

main.py 不用说,主程序了。

configuration.py 一些全局变量存在这。因为之前写的版本是把信息录入和识别分开成2个程序的,所以把两个程序都用到的参数放在这个文件里。后来合并后,就懒得改这个文件了。一直沿用。

recognizer.py 定义了名为recognizer的人脸识别器类。把dlib库中人脸识别的一些函数和方法进行了封装,作出了自己的方法。比如获取图片中占地面积最大的脸,计算图片中最大人脸边框的左上角和右下角的位置(一般画框的时候需要用到)、获取rgb图片中最大人脸的“脸纹”等。

audio_player.py 用于播放wav文件的,调用后可以生成另一个线程播放指定WAV文件。

source目录 存放了一些外部依赖文件,包括dlib人脸识别模型文件,面部特征点文件,音频文件,默认图片文件

registered_players目录 存放已登记了信息的人的脸纹和照片的目录,脸纹文件存放在face_description下,照片存放在images下。因为一开始是要做一个给裁判员使用的人脸识别相机,在运动员上场前检录的时候使用的。所以就用了“registered_players”。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值