用 Python 实现视频流中逐帧识别匹配的人脸
本文通过实际代码案例,详细解析如何利用face_recognition库根据人脸特征点匹配实现视频中寻人的效果,帮助读者快速掌握相关技术要点。
环境搭建
在开始之前,请确保你的开发环境中已安装face-recognition和opencv库。可以通过以下命令安装:
pip install face-recognition opencv-python
代码实现与解析
完整代码
import face_recognition
import cv2
input_movie = cv2.VideoCapture('presentation.mp4')
if not input_movie.isOpened():
print("error")
exit()
length = int(input_movie.get(cv2.CAP_PROP_FRAME_COUNT))
fourcc = cv2.VideoWriter.fourcc(*'XVID')
output_movie = cv2.VideoWriter('output.avi', fourcc, 60, (1920,1080))
trump_image = face_recognition.load_image_file('trump.jpg')
trump_face_encoding = face_recognition.face_encodings(trump_image)[0]
obama_image = face_recognition.load_image_file('obama.jpg')
obama_face_encoding = face_recognition.face_encodings(obama_image)[0]
known_faces = [
trump_face_encoding,
obama_face_encoding
]
face_locations = []
face_encodings = []
face_names = []
frame_number = 0
while True:
ret,frame = input_movie.read()
frame_number +=1
if not ret:
break
rgb_frame = frame[:, :, ::-1]
face_locations = face_recognition.face_locations(rgb_frame)
face_encodings = face_recognition.face_encodings(rgb_frame, face_locations)
face_names = []
for face_encoding in face_encodings:
match = face_recognition.compare_faces(known_faces, face_encoding, tolerance=0.5)
name = None
if match[0]:
name = "Trump"
elif match[1]:
name = 'Obama'
face_names.append(name)
for (top, right, bottom, left), name in zip(face_locations, face_names):
if not name:
continue
cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)
cv2.rectangle(frame, (left, bottom - 25), (right, bottom), (0, 0, 255), cv2.FILLED)
font = cv2.FONT_HERSHEY_DUPLEX
cv2.putText(frame, name, (left + 6, bottom - 6), font, 0.5, (255, 255, 255), 1)
print('writing frame {}/{}'.format(frame_number, length))
output_movie.write(frame)
input_movie.release()
output_movie.release()
cv2.destroyAllWindows()
代码解读
1 视频读取与输出设置
input_movie = cv2.VideoCapture('presentation.mp4')
if not input_movie.isOpened():
print("error")
exit()
length = int(input_movie.get(cv2.CAP_PROP_FRAME_COUNT))
fourcc = cv2.VideoWriter.fourcc(*'XVID')
output_movie = cv2.VideoWriter('1.avi', fourcc, 60, (1920,1080))
使用 OpenCV 的cv2.VideoCapture方法打开输入视频文件 "presentation.mp4"。通过input_movie.isOpened()方法检查视频是否成功打开,若未打开则输出错误信息并退出程序。接着,通过length = int(input_movie.get(cv2.CAP_PROP_FRAME_COUNT))获取视频的总帧数,以便后续在处理过程中能够实时显示进度。
2 加载已知人脸图像并提取特征
trump_image = face_recognition.load_image_file('trump.jpg')
trump_face_encoding = face_recognition.face_encodings(trump_image)[0]
obama_image = face_recognition.load_image_file('obama.jpg')
obama_face_encoding = face_recognition.face_encodings(obama_image)[0]
known_faces = [
trump_face_encoding,
obama_face_encoding
]
在进行视频中人脸的识别之前,需要先加载已知的人脸图像,并提取其特征。这里分别加载了 "trump.jpg" 和 "obama.jpg" 两张图片,分别代表特朗普和奥巴马。使用方法face_recognition.load_image_file加载图片,然后通过方法提取图片中人脸的特征编码。这些特征编码是后续进行人脸比对的关键依据,将它们存储到known_faces列表中,以便在视频帧中检测到人脸时进行比对识别。
3 视频帧处理与人脸检测识别
while True:
ret,frame = input_movie.read()
frame_number +=1
if not ret:
break
rgb_frame = frame[:, :, ::-1]
face_locations = face_recognition.face_locations(rgb_frame)
face_encodings = face_recognition.face_encodings(rgb_frame, face_locations)
进入循环,逐帧读取视频。通过input_movie.read()方法读取每一帧,ret表示读取是否成功,frame是读取到的帧图像。若读取失败(即视频结束),则退出循环。
为了提高人脸检测的速度,先将每一帧图像从 BGR 格式转换为 RGB 格式库要求输入为 RGB 格式),接着,使用face_recognition.face_locations方法在图像中检测人脸的位置,得到人脸的坐标框。最后,使用face_recognition.face_encodings方法提取当前帧中检测到的人脸的特征编码,以便后续与已知人脸特征进行比对。
for face_encoding in face_encodings:
match = face_recognition.compare_faces(known_faces, face_encoding, tolerance=0.5)
name = None
if match[0]:
name = "Trump"
elif match[1]:
name = 'Obama'
face_names.append(name)
对于当前帧中检测到的每一个人脸特征编码,使用face_recognition.compare_faces方法与已知的人脸特征列表known_faces进行比对。tolerance参数指定了比对的容差阈值,值越小,比对越严格。根据比对结果,确定当前人脸对应的名称,若与第一个已知人脸特征匹配,则名称为 "Trump";若与第二个已知人脸特征匹配,则名称为 "Obama";若都不匹配,则名称为None。将识别到的名称存储到face_names列表中,与人脸坐标框一一对应。
for (top, right, bottom, left), name in zip(face_locations, face_names):
if not name:
continue
cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)
cv2.rectangle(frame, (left, bottom - 25), (right, bottom), (0, 0, 255), cv2.FILLED)
font = cv2.FONT_HERSHEY_DUPLEX
cv2.putText(frame, name, (left + 6, bottom - 6), font, 0.5, (255, 255, 255), 1)
遍历人脸坐标框和对应的名称,若名称不为空(即识别到了已知人物),则在原始帧图像上绘制矩形框来标记人脸位置,矩形框的颜色为红色(BGR 格式下的 (0, 0, 255))。同时,在矩形框下方绘制一个填充的矩形区域,用于显示人物名称,字体颜色为白色((255, 255, 255)),字体大小为 0.5,字体类型为cv2.FONT_HERSHEY_DUPLEX 这样,识别到的人物名称就会清晰地显示在人脸下方。
print('writing frame {}/{}'.format(frame_number, length))
output_movie.write(frame)
在处理完每一帧后,输出当前帧的处理进度(当前帧数与总帧数的比例)。然后,通过output_movie.write(frame)方法将绘制了识别结果的帧写入到输出视频文件中。
4 资源释放
input_movie.release()
output_movie.release()
cv2.destroyAllWindows()
当所有帧都处理完成并写入输出视频后,释放输入视频和输出视频的资源,关闭所有 OpenCV 创建的窗口,以确保程序正常结束,避免资源泄漏等问题。
结果
通过运行上述代码,我们可以得到一个新的视频文件 "output.avi",其中在原始视频的基础上,对检测到的特朗普和奥巴马人脸进行了标注。
作者每周更新栏目文章,和读者一起从原理剖析到代码实践,完整实现实时人脸识别项目。
若您对文章内容有疑问,或发现文章中存在错误,请您指出,谢谢!