1.背景概述
由于我们学校有的宿舍在校外,人员流动性大,人员身份复杂,学生安全意识相对薄弱等几大特点,学生的财产安全及学生宿舍管理问题急需有待解诀,其中尤为突出的又表现在现有门锁的不安全及管理上诸多不便。现常用普通机械门锁主要有以下几大不便:顺手不能锁门、钥匙容易复制、容易丢失且不能挂失、无法查询开门记录、防盜性能极差、外观简单。鉴于以上原因学校不得不陷入循环换锁的尴尬之中,浪费巨大的人力、物力与财力并且还是无法从根本上解诀问题。人脸智能门锁从根本上解诀了以上问题,所以学生宿舍改用人脸智能门锁就势在必行了。人脸智能门锁是现在高度文明的表现,人脸智能门锁能够实时监控进入宿舍的人员并做记录,没有得到许可(需要宿舍长录入人脸)的人员是无法进入宿舍的,如果非法闯入还将引发警报。
2.设计方案
2.1框架设计
利用wxPython设计一个人机交互界面的窗口,便于更好的实现人机交互。
2.2宿舍管理
在这个模块中利用wxPython,sqlite3和dlib库结合完成人脸的录入、删除功能
(1)利用opencv打开笔记本摄像头完成人脸检测,并绘制矩形框,获取当前捕获到的图像的所有人脸特征与姓名和学号进行绑定存储到数据库。
(2)检测到人脸的同时需要与数据库中的人脸进行匹配,如果人脸相似就不在进行录入,如果录入就覆盖之前的人脸信息。
(3)删除人脸信息就是弹出一个对话框进行姓名填写,如果名字存在就将本地文件夹与数据库里面的该条数据删除,如果该名字不存在就弹出警告。
2.3监测人员
该模块与上面人脸录入模块设计类似,利用opencv调用摄像头完成人脸检测,并将检测到的人脸信息与存储的信息进行比对,如果有就将其存到日志表中。
2.4流动日志
该模块与监测人员模块相结合,将监测人员模块中得到的数据显示在表格中,反映人员的流动情况。
3.实验详细步骤
3.1.框架设计
(1)初始化
def __init__(self):
wx.Frame.__init__(self,parent=None,title="宿舍管理系统",size=(920,560))
self.initMenu()
self.initInfoText()
self.initGallery()
self.initDatabase()
self.initData()
(2)初始化菜单栏
def initMenu(self):
menuBar = wx.MenuBar() #生成菜单栏
menu_Font = wx.Font()#Font(faceName="consolas",pointsize=20)
menu_Font.SetPointSize(14)
menu_Font.SetWeight(wx.BOLD)
registerMenu = wx.Menu() #生成菜单
self.new_register = wx.MenuItem(registerMenu,ID_NEW_REGISTER,"新建录入")
self.new_register.SetBitmap(wx.Bitmap("F:/WorkAttendanceSystem-master/V2.0/drawable/new_register.png"))
self.new_register.SetTextColour("SLATE BLUE")
self.new_register.SetFont(menu_Font)
registerMenu.Append(self.new_register)
self.delete_member = wx.MenuItem(registerMenu,ID_DELETE_MEMBER,"人员删除")
self.delete_member.SetBitmap(wx.Bitmap("F:/WorkAttendanceSystem-master/V2.0/drawable/finish_register.png"))
self.delete_member.SetTextColour("SLATE BLUE")
self.delete_member.SetFont(menu_Font)
registerMenu.Append(self.delete_member)
puncardMenu = wx.Menu()
self.start_punchcard = wx.MenuItem(puncardMenu,ID_START_PUNCHCARD,"开始监测")
self.start_punchcard.SetBitmap(wx.Bitmap("F:/WorkAttendanceSystem-master/V2.0/drawable/start_punchcard.png"))
self.start_punchcard.SetTextColour("SLATE BLUE")
self.start_punchcard.SetFont(menu_Font)
puncardMenu.Append(self.start_punchcard)
self.end_puncard = wx.MenuItem(puncardMenu,ID_END_PUNCARD,"退出监测")
self.end_puncard.SetBitmap(wx.Bitmap("F:/WorkAttendanceSystem-master/V2.0/drawable/end_puncard.png"))
self.end_puncard.SetTextColour("SLATE BLUE")
self.end_puncard.SetFont(menu_Font)
self.end_puncard.Enable(False)
puncardMenu.Append(self.end_puncard)
logcatMenu = wx.Menu()
self.open_logcat = wx.MenuItem(logcatMenu,ID_OPEN_LOGCAT,"打开日志")
self.open_logcat.SetBitmap(wx.Bitmap("F:/WorkAttendanceSystem-master/V2.0/drawable/open_logcat.png"))
self.open_logcat.SetFont(menu_Font)
self.open_logcat.SetTextColour("SLATE BLUE")
logcatMenu.Append(self.open_logcat)
self.close_logcat = wx.MenuItem(logcatMenu, ID_CLOSE_LOGCAT, "关闭日志")
self.close_logcat.SetBitmap(wx.Bitmap("F:/WorkAttendanceSystem-master/V2.0/drawable/close_logcat.png"))
self.close_logcat.SetFont(menu_Font)
self.close_logcat.SetTextColour("SLATE BLUE")
logcatMenu.Append(self.close_logcat)
menuBar.Append(registerMenu,"&宿舍管理")
menuBar.Append(puncardMenu,"&监测人员")
menuBar.Append(logcatMenu,"&流动日志")
self.SetMenuBar(menuBar)
self.Bind(wx.EVT_MENU,self.OnNewRegisterClicked,id=ID_NEW_REGISTER)
self.Bind(wx.EVT_MENU,self.delmember,id=ID_DELETE_MEMBER)
self.Bind(wx.EVT_MENU,self.OnStartPunchCardClicked,id=ID_START_PUNCHCARD)
self.Bind(wx.EVT_MENU,self.OnEndPunchCardClicked,id=ID_END_PUNCARD)
self.Bind(wx.EVT_MENU,self.OnOpenLogcatClicked,id=ID_OPEN_LOGCAT)
self.Bind(wx.EVT_MENU,self.OnCloseLogcatClicked,id=ID_CLOSE_LOGCAT)
3.2宿舍管理模块的设计
(1)新建录入
def register_cap(self,event):
self.cap = cv2.VideoCapture(0)
flag, im_rd = self.cap.read()
# 每帧数据延时1ms,延时为0读取的是静态帧
kk = cv2.waitKey(1)
# 人脸数 dets
dets = detector(im_rd, 1)
# 检测到人脸
if len(dets) != 0:
biggest_face = dets[0]
#取占比最大的脸
maxArea = 0
for det in dets:
w = det.right() - det.left()
h = det.top()-det.bottom()
if w*h > maxArea:
biggest_face = det
maxArea = w*h
# 绘制矩形框
cv2.rectangle(im_rd, tuple([biggest_face.left(), biggest_face.top()]),
tuple([biggest_face.right(), biggest_face.bottom()]),
(255, 0, 0), 2)
img_height, img_width = im_rd.shape[:2]
image1 = cv2.cvtColor(im_rd, cv2.COLOR_BGR2RGB)
pic = wx.Bitmap.FromBuffer(img_width, img_height, image1)
# 显示图片在panel上
self.bmp.SetBitmap(pic)
# 获取当前捕获到的图像的所有人脸的特征,存储到 features_cap_arr
shape = predictor(im_rd, biggest_face)
features_cap = facerec.compute_face_descriptor(im_rd, shape)
# 对于某张人脸,遍历所有存储的人脸特征
for i,knew_face_feature in enumerate(self.knew_face_feature):
# 将某张人脸与存储的所有人脸数据进行比对
compare = return_euclidean_distance(features_cap, knew_face_feature)
if compare == "same": # 找到了相似脸
self.infoText.AppendText(self.getDateAndTime()+"学号:"+str(self.knew_id[i])
+" 姓名:"+self.knew_name[i]+" 的人脸数据已存在\r\n")
self.flag_registed = True
self.OnFinishRegister()
_thread.exit()
face_height = biggest_face.bottom()-biggest_face.top()
face_width = biggest_face.right()- biggest_face.left()
im_blank = np.zeros((face_height, face_width, 3), np.uint8)
try:
for ii in range(face_height):
for jj in range(face_width):
im_blank[ii][jj] = im_rd[biggest_face.top() + ii][biggest_face.left() + jj]
if len(self.name)>0:
cv2.imencode('.jpg', im_blank)[1].tofile(
PATH_FACE + self.name + "/img_face_" + str(self.pic_num) + ".jpg") # 正确方法
self.pic_num += 1
print("写入本地:", str(PATH_FACE + self.name) + "/img_face_" + str(self.pic_num) + ".jpg")
self.infoText.AppendText(self.getDateAndTime()+"图片:"+str(PATH_FACE + self.name) + "/img_face_" + str(self.pic_num) + ".jpg保存成功\r\n")
except:
print("保存照片异常,请对准摄像头")
if self.new_register.IsEnabled():
_thread.exit()
if self.pic_num == 10:
self.OnFinishRegister()
_thread.exit()
(2)人员删除
def delmember(self,event):
self.loadDataBase(1)
self.name = wx.GetTextFromUser(message="请输入您的的姓名",
caption="温馨提示",
default_value="", parent=self.bmp)
filePath = PATH_FACE + self.name
if self.name!='':
if os.path.exists(filePath):
con = sqlite3.connect('F:/WorkAttendanceSystem-master/V2.0/inspurer.db')
cur = con.cursor()
del_sql = "delete from worker_info where name = "+"'"+self.name+"'"
print(del_sql)
try:
cur.execute(del_sql)
con.commit()#提交事务
except Exception as e:
con.rollback()#删除失败则回滚
finally:
cur.close()
con.close()
for fileList in os.walk(filePath):
for name in fileList[2]:
os.chmod(os.path.join(fileList[0],name), stat.S_IWRITE)
os.remove(os.path.join(fileList[0],name))
shutil.rmtree(filePath)
wx.MessageBox(message="删除成功", caption="提示")
else:
wx.MessageBox(message="此人不存在", caption="警告")
self.initData()
pass
3.3.监测人员
监测
def punchcard_cap(self,event):
self.cap = cv2.VideoCapture(0)
while self.cap.isOpened():
flag, im_rd = self.cap.read()
# 每帧数据延时1ms,延时为0读取的是静态帧
kk = cv2.waitKey(1)
# 人脸数 dets
dets = detector(im_rd, 1)
# 检测到人脸
if len(dets) != 0:
biggest_face = dets[0]
# 取占比最大的脸
maxArea = 0
for det in dets:
w = det.right() - det.left()
h = det.top() - det.bottom()
if w * h > maxArea:
biggest_face = det
maxArea = w * h
# 绘制矩形框
cv2.rectangle(im_rd, tuple([biggest_face.left(), biggest_face.top()]),
tuple([biggest_face.right(), biggest_face.bottom()]),
(255, 0, 255), 2)
img_height, img_width = im_rd.shape[:2]
image1 = cv2.cvtColor(im_rd, cv2.COLOR_BGR2RGB)
pic = wx.Bitmap.FromBuffer(img_width, img_height, image1)
# 显示图片在panel上
self.bmp.SetBitmap(pic)
# 获取当前捕获到的图像的所有人脸的特征,存储到 features_cap_arr
shape = predictor(im_rd, biggest_face)
features_cap = facerec.compute_face_descriptor(im_rd, shape)
# 对于某张人脸,遍历所有存储的人脸特征
for i, knew_face_feature in enumerate(self.knew_face_feature):
# 将某张人脸与存储的所有人脸数据进行比对
compare = return_euclidean_distance(features_cap, knew_face_feature)
if compare == "same": # 找到了相似脸
nowdt = self.getDateAndTime()
for j,logcat_name in enumerate(self.logcat_name):
if logcat_name == self.knew_name[i] and nowdt[0:nowdt.index(" ")] == self.logcat_datetime[j][0:self.logcat_datetime[j].index(" ")]:
break
else:
engine = pyttsx3.init()
engine.say("Welcome !!")
engine.runAndWait()
self.insertARow([self.knew_id[i],self.knew_name[i],nowdt],2)
if self.start_punchcard.IsEnabled():
self.bmp.SetBitmap(wx.Bitmap(self.pic_index))
_thread.exit()
3.4.流动日志
(1)打开日志
def OnOpenLogcatClicked(self,event):
self.loadDataBase(2)
#必须要变宽才能显示 scroll
self.SetSize(980,560)
grid = wx.grid.Grid(self,pos=(320,0),size=(920,560))
grid.CreateGrid(100, 4)
for i in range(100):
for j in range(3):
grid.SetCellAlignment(i,j,wx.ALIGN_CENTER,wx.ALIGN_CENTER)
grid.SetColLabelValue(0, "学号") #第一列标签
grid.SetColLabelValue(1, "姓名")
grid.SetColLabelValue(2, "进入时间")
grid.SetColSize(0,120)
grid.SetColSize(1,120)
grid.SetColSize(2,150)
for i,id in enumerate(self.logcat_id):
grid.SetCellValue(i,0,str(id))
grid.SetCellValue(i,1,self.logcat_name[i])
grid.SetCellValue(i,2,self.logcat_datetime[i])
Pass
(2)关闭日志
def OnCloseLogcatClicked(self,event):
self.SetSize(920,560)
self.initGallery()
Pass
4.系统性能测试和分析
4.1.框架界面
4.2.宿舍管理
(1)人脸录入
(2)删除人脸
4.3.监测人员
4.4.查看日志
监测、查看
上面是主要功能的相关代码,由于代码量有点大所以就没有全部写出来,如有需要请看这里