系统结构实践期末大作业
选题简介
我们本次的系统结构实践期末大作业是一个身份认证系统。该系统在人脸识别开源的python库face_recognition的基础上,进行修改示例代码,搭建lnmp框架,构建web项目,拉取MySQL容器等等工作来完成的。身份认证系统在识别人脸的过程中,会从数据库中得到所识别对象的信息,若无法识别,则会不进行显示;在对象信息的调整上,是通过web项目完成的,进行信息的增删改查。
设计
文件结构
lnmp框架
代码
首先进行对图片库加载和学习识别的半自动化
# 保存的图片文件名
image_name_list = []
# 得到文件名
def file_name(image_name_list):
# root是指当前目录路径(文件夹的绝对路径)
# dirs是指路径下所有的子目录(文件夹里的文件夹)
# files是指路径下所有的文件(文件夹里所有的文件)
for root,dirs,files in os.walk(file_dir):
for file in files:
# if os.path.splitext(file)[1] == '.jpg':
image_name_list.append(os.path.join(file))
print(image_name_list)
file_name(image_name_list)
# 创建已知面孔及其名称数组
known_face_encodings = []
known_face_names = []
# 加载图片并学习如何识别它
def konwn_face(known_face_encodings,known_face_names):
for image_name in image_name_list :
character_image = face_recognition.load_image_file(file_dir+image_name)
character_face_encoding = face_recognition.face_encodings(character_image)[0]
known_face_encodings.append(character_face_encoding)
for root,dirs,files in os.walk(file_dir):
for file in files:
known_face_names.append(os.path.splitext(file)[0])
konwn_face(known_face_encodings,known_face_names)
设定阈值
若阈值太低,容易造成无法成功识别人脸,结果如下:
反之,若阈值太高,就会人脸识别混淆,结果如下:
所以阈值太低容易造成无法成功识别人脸,太高容易造成人脸识别混淆,并且识别亚洲人所需要阈值tolerance一般要用低一点。
for face_encoding in face_encodings:
# See if the face is a match for the known face(s)
# 查看该面孔是否与已知面孔匹配
matches = face_recognition.compare_faces(known_face_encodings, face_encoding,tolerance=0.5)
# 默认为unknown
name = "Unknown"
# 使用与新面孔距离最小的已知面孔,即看测试图像与已知面孔之间有多远
face_distances = face_recognition.face_distance(known_face_encodings, face_encoding)
#best_match_index为face_distances中最小值的下标
best_match_index = np.argmin(face_distances)
#如果face_distances[best_match_index]小于0.5(截止值,原本想加上的,但仔细一想又好像不对),matches[best_match_index]比较结果为真
if matches[best_match_index]:
name = known_face_names[best_match_index]
face_names.append(name)
未识别到人脸的信息
呈现在常态和未识别到时的信息面板内容。
#text
rectangular_image = cv2.imread(rectangular_dir)
font = cv2.FONT_HERSHEY_DUPLEX
cv2.putText(rectangular_image, "FACE PLEA!", (0 + 150, 0 + 330), font, 4, (255, 255, 255), 2)
已识别到人脸的信息
呈现已识别到时的信息面板内容。
#mysql
rectangular_image = cv2.imread(rectangular_dir)
id=name
sql = "SELECT * FROM User \
WHERE id = %s" % (id)
results=mysql.mysql_find(cursor,sql)
if(results!=None):
for row in results:
lname = row[1]
age = row[2]
sex =row[3]
iden = row[4]
nation = row[5]
# 画一个有名字的标签
#cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED)
font = cv2.FONT_HERSHEY_DUPLEX
cv2.putText(rectangular_image, "NAME: "+lname, (0 + 50, 0 + 100), font, 2.0, (255, 255, 255), 2)
cv2.putText(rectangular_image, "AGE: "+age, (0 + 50, 0 + 200), font, 2.0, (255, 255, 255), 2)
cv2.putText(rectangular_image, "SEX: "+sex, (0 + 50, 0 + 300), font, 2.0, (255, 255, 255), 2)
cv2.putText(rectangular_image, "IDENTITY: "+iden, (0 + 50, 0 + 400), font, 2.0, (255, 255, 255), 2)
cv2.putText(rectangular_image, "NATION: "+nation, (0 + 50, 0 + 500), font, 2.0, (255, 255, 255), 2)
摄像头界面、信息面板、边框图片整合
首先来了解一下掩膜(mask)的概念:掩膜是用一副二值化图片对另外一幅图片进行局部的遮挡。
将边框图片用来作为掩膜,即灰度化处理
# 边框图片
bor_image = cv2.imread(border_dir)
# 变更为画布的大小
bor_image = cv2.resize(bor_image, (frame.shape[1], frame.shape[0]) )
#roi
rows,cols,channels = bor_image.shape
roi = frame[0:rows, 0:cols ]
# 利用mask合成
# 将图片灰度化(灰度0-255 白255 黑0)
bor_image_gray = cv2.cvtColor(bor_image,cv2.COLOR_BGR2GRAY)
将灰度图取反,其结果与原图分别作用于所需的两张素材,即相当于在原图中按位与运算边框图片的灰度图,使得在原图所对应的边框位置值为0;在边框图片按位与取反的灰度图,使得除边框外部分的值为0。
# 灰度图 把 大于175(即不感兴趣)的值改为 255 ,也就是变为白色
# 现在是mask中 兴趣区域-->黑色 无兴趣区域-->白色
ret, mask = cv2.threshold(bor_image_gray, 180, 255, cv2.THRESH_BINARY)
# 把mask取反,现在是mask_not中 兴趣区域-->白色 无兴趣区域-->黑色
mask_not = cv2.bitwise_not(mask)
# 对图片和mask进行取与操作,作用相当于把mask中为黑色()的部分,
# 在图片中也附黑,白色部分不变。
img1_bg = cv2.bitwise_and(roi,roi,mask = mask)
# 对边框图片和mask_not进行取与操作,作用相当于把mask中为黑色的部分,
# 在边框图片中也附黑,白色部分不变。
img2_bg = cv2.bitwise_and(bor_image,bor_image,mask = mask_not)
进行图片的加和
# 进行图片的加和
dst = cv2.add(img1_bg,img2_bg)
frame[0:rows, 0:cols ] = dst
#add the rectangular
rectangular_image = cv2.resize(rectangular_image, (frame.shape[1], frame.shape[0]), )
vtich = np.vstack((frame, rectangular_image))
mysql.py
import pymysql
def mysql_connect():
connect = pymysql.connect(
host='localhost',
port=3306,
user='root',
passwd='123',
db='myDB',
charset='utf8'
)
if(connect!=None):
print("connect mysql success!")
return connect.cursor()
def mysql_find(cursor,sql):
try:
cursor.execute(sql)
results = cursor.fetchall()
for row in results:
name = row[1]
age = row[2]
sex =row[3]
iden = row[4]
nation = row[5]
print ("name=%s,age=%s,sex=%s,iden=%s,nation=%s" % \
(name, age, sex, iden, nation ))
return results
except:
print ("Error: unable to fecth data")
web项目
MySQL容器
树莓派运行结果
组内分工 + 贡献比
学号 | 姓名 | 分工 | 贡献比 |
---|---|---|---|
031702220 | 黄恒杰 | 框架搭建+实际操作+web前端 | 50% |
031702223 | 郑志强 | 资料查询+php连接 | 20% |
031702239 | 林国钦 | 身份识别代码+PPT、博客编写 | 30% |
总结
⭐ 黄恒杰:本身在机缘巧合下拿到了树莓派,就产生了比较浓厚的兴趣,所以这次大作业我就直接基于树莓派的人脸识别来开展。我们组这次的大作业,可以说真的是三个菜鸟,基于所有已经学过的docker知识,还有平时一步步踏踏实实做好实验的经验,堆积起来了这个还算不小的项目。从python环境下跑人脸识别拓展到拉取mysql镜像容器来存取身份信息的身份识别,再到利用已经学过的lnmp集群框架来实现web服务,这一切似乎不简单但却可行性非常高。其中还拓展了图像功能来呈现身份识别的良好效果,可以说是比较创新的一点。在这里我也很感谢两个组员的配合,虽然实验中遇到了非常多的坎,虽然每个人的能力并没特别突出,但配合起来还是能产生很大的创作性的。即使因为时间有限,最后没有做的尽善尽美,但我们都还是很欣慰最后的那个项目的成果
⭐ 郑志强:从刚刚接触到系统综合实践这门课起,我就感受到这是一门实践性很强、理论性也很强的课程,所以每次作业时,我们组都进行了屏幕分享,视频等方式进行交流、沟通、探讨。
⭐ 林国钦:经过三周的实践操作,我们的作业已经完成。虽然过程中也遇到了很多问题,但通过查询资料,我们基本上都能够解决。本次实验我感受到了cv2在图像处理方面的强大功能,这使得在进行图像处理的代码编写上简单了许多,放掉了想对图像像素点值处理的想法。还有在这里为黄恒杰组长辛苦劳作说一声谢谢,组长不仅分工安排合理,还十分的强大。