
本文旨在解决基于 OpenCV 和 face_recognition 库构建的人脸识别考勤系统中,重复记录考勤信息的问题。通过分析代码逻辑和文件读写操作,提供两种优化方案,确保考勤记录的准确性和效率。针对初学者,本文提供详细的代码示例和解释,帮助读者理解并解决实际问题。
在人脸识别考勤系统中,一个常见的问题是当摄像头持续检测到同一张脸时,系统会重复将该人员的考勤信息写入 CSV 文件。这不仅导致数据冗余,也影响了考勤记录的准确性。本文将探讨如何解决这个问题,并提供两种优化方案,提升考勤系统的稳定性和效率。
问题分析
原始代码的问题在于 markAttendance 函数中的逻辑。该函数每次被调用时,都会打开 Attendance.csv 文件,读取所有已记录的姓名,然后检查当前检测到的姓名是否已存在。如果不存在,则将该姓名和当前时间写入文件。关键问题在于,这个检查和写入操作是在主循环中进行的,这意味着只要摄像头检测到人脸,markAttendance 函数就会被调用,从而导致重复写入。
解决方案一:循环外判断
第一个解决方案是将判断姓名是否已存在的逻辑移到循环外部。具体来说,首先在函数内部读取所有已存在的姓名,存储到一个列表中。然后在循环结束后,再判断当前姓名是否在列表中。如果不在,则写入文件。
def markAttendance(name): with open('Attendance.csv', 'r+') as f: nameList = [] for line in f: entry = line.split(',') nameList.append(entry[0]) if name not in nameList: dt = datetime.now().strftime('%H:%M:%S') f.writelines(f'n{name},{dt}')
代码解释:
with open(‘Attendance.csv’, ‘r+’) as f::以读写模式打开 Attendance.csv 文件。with 语句确保文件在使用完毕后自动关闭。nameList = []:创建一个空列表,用于存储已记录的姓名。for line in f::遍历文件中的每一行。entry = line.split(‘,’):将每一行以逗号分隔,得到一个包含姓名和时间的列表。nameList.append(entry[0]):将姓名添加到 nameList 中。if name not in nameList::判断当前检测到的姓名是否已存在于 nameList 中。dt = datetime.now().strftime(‘%H:%M:%S’):获取当前时间,并格式化为 HH:MM:SS 字符串。f.writelines(f’n{name},{dt}’):将姓名和时间写入文件。
注意事项:
这种方法每次都会读取整个 CSV 文件,当数据量很大时,效率会降低。
解决方案二:内存缓存
第二个解决方案是在内存中缓存已记录的姓名列表。这意味着在程序启动时,读取 CSV 文件中的所有姓名,存储到一个列表中。然后,在每次检测到人脸时,直接在内存中查找该姓名是否已存在。如果不存在,则将该姓名添加到内存列表,并写入文件。
def readNames(): with open('Attendance.csv', 'r') as f: nameList = [] for line in f: entry = line.split(',') nameList.append(entry[0]) return nameListdef markAttendance(name, nameList): if name not in nameList: nameList.append(name) with open('Attendance.csv', 'a') as f: dt = datetime.now().strftime('%H:%M:%S') f.writelines(f'n{name},{dt}')# 初始化姓名列表nameList = readNames()while True: # ... (人脸识别代码) ... if matches[matchIndex]: # ... markAttendance(name, nameList)
代码解释:
readNames() 函数:以只读模式打开 Attendance.csv 文件。读取所有姓名,存储到 nameList 中。返回 nameList。markAttendance(name, nameList) 函数:接收姓名和姓名列表作为参数。判断姓名是否已存在于 nameList 中。如果不存在,则将姓名添加到 nameList 中,并以追加模式打开 Attendance.csv 文件,将姓名和时间写入文件。nameList = readNames():在主循环开始之前,调用 readNames() 函数,初始化 nameList。markAttendance(name, nameList):在主循环中,调用 markAttendance() 函数,传入姓名和 nameList。
代码修改示例(将上述代码整合到原代码中):
import osimport cv2import numpy as npimport face_recognitionfrom datetime import datetimepath = 'MainImages'images = []classNames = []myList = os.listdir(path)for cl in myList: curImg = cv2.imread(f'{path}/{cl}') images.append(curImg) classNames.append(os.path.splitext(cl)[0])def findEncodings(images): encodeList = [] for img in images: img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) encode = face_recognition.face_encodings(img)[0] encodeList.append(encode) return encodeListdef readNames(): with open('Attendance.csv', 'r') as f: nameList = [] for line in f: entry = line.split(',') nameList.append(entry[0]) return nameListdef markAttendance(name, nameList): if name not in nameList: nameList.append(name) with open('Attendance.csv', 'a') as f: dt = datetime.now().strftime('%H:%M:%S') f.writelines(f'n{name},{dt}')encodeListKnown = findEncodings(images)print('Encoding Complete')cap = cv2.VideoCapture(0)nameList = readNames() # 初始化姓名列表while True: success, img = cap.read() imgS = cv2.resize(img, (0, 0), None, 0.25, 0.25) imgS = cv2.cvtColor(imgS, cv2.COLOR_BGR2RGB) facesCurFrame = face_recognition.face_locations(imgS) encodesCurFrame = face_recognition.face_encodings(imgS, facesCurFrame) for encodeFace, faceLoc in zip(encodesCurFrame, facesCurFrame): matches = face_recognition.compare_faces(encodeListKnown, encodeFace) faceDis = face_recognition.face_distance(encodeListKnown, encodeFace) matchIndex = np.argmin(faceDis) if matches[matchIndex]: name = classNames[matchIndex].upper() y1, x2, y2, x1 = faceLoc y1, x2, y2, x1 = y1*4, x2*4, y2*4, x1*4 cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.rectangle(img, (x1, y2-35), (x2, y2), (0, 255, 0), cv2.FILLED) cv2.putText(img, name, (x1+6, y2-6), cv2.FONT_HERSHEY_COMPLEX, 1, (255, 255, 255), 2) markAttendance(name, nameList) # 传入姓名列表 cv2.imshow('Webcam', img) cv2.waitKey(1)
注意事项:
这种方法将姓名列表存储在内存中,可以提高效率。如果 CSV 文件很大,读取所有姓名可能会占用大量内存。程序退出时,内存中的姓名列表不会保存到 CSV 文件中。如果需要持久化存储,需要在程序退出时将 nameList 重新写入 Attendance.csv。
总结
本文提供了两种解决人脸识别考勤系统重复记录问题的方案。第一种方案通过将判断逻辑移到循环外部,避免了重复写入。第二种方案通过在内存中缓存姓名列表,提高了效率。选择哪种方案取决于实际应用场景和数据量大小。对于数据量较小的应用,第一种方案可能更简单易懂。对于数据量较大的应用,第二种方案可能更高效。在实际应用中,可以根据具体情况选择合适的方案,并进行适当的优化。
以上就是解决人脸识别考勤系统重复记录问题:一份详细教程的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1377969.html
微信扫一扫
支付宝扫一扫