阅读 108

玩转人脸识别

一、人脸识别发展

细数人脸识别发展史,我们大致可将其分为四个阶段:

  1. 1964~1990年,第一阶段,研究人脸识别面部特征,没有实现自动识别

  2. 1991~1997年,第二阶段,研究人工算法识别

  3. 1998~2014年,第三阶段,主要研究鲁棒性,如光照、姿态

  4. 2015年至今,第四阶段,互联网应用:技术成熟,大面积推广应用

这一技术已经让生活发生翻天覆地变化!

试想,周一早上,你通过人脸打卡机进入办公室,打开美团选好一杯热咖啡,人脸无感支付。然后你想起周末和朋友的快乐时光,习惯性打开facebook,人脸验证通过后,编辑、上传图片一气呵成,facebook也瞬间帮你@到照片中的好友。


(图源:人脸识别原理)

二、基于face_recognition实现人脸识别

如此酷炫的功能,我们也可以借助face_recognition轻松实现!

face_recognition:是世界上最简洁的人脸识别库,你可以使用Python和命令行工具提取、识别、操作人脸。 face_recognition 提供丰富的api(详见)供调用,我们借助python-flask框架,封装接口,搭建一个小型人脸识别服务器。

核心代码如下:

def faceMatch(name):     if name is None:         abort(404)     name = './uploadimg/'+name     unknown_image = face_recognition.load_image_file(name)     res = []     if unknown_image is None:         res.append(" position fail!")     else:         try:             unknown_encoding = face_recognition.face_encodings(unknown_image)[0]             WSI_MASK_PATH = './orisample/'  #原始库             wsi_mask_paths = glob.glob(os.path.join(WSI_MASK_PATH, '*.jpg'))             for pic in wsi_mask_paths:                 known_image = face_recognition.load_image_file(pic)                 #已知人脸编码                 known_encoding = face_recognition.face_encodings(known_image)[0]                 #待识别图像,与源库比对                 results = face_recognition.compare_faces([known_encoding], unknown_encoding, tolerance = 0.4)                 if results[0] == True:                     res.append(pic.split('/')[2]+" It's a picture of me!")                 else:                     res.append(pic.split('/')[2]+" not")         except:             res.append(" position fail!!")     return render_template('facematch.html', url=res, name=res) 复制代码

代码(源码地址)解读:

  • 导入face_recognition后,调用face_encodings接口获得图片编码

  • 再通过compare_faces接口,依靠算法比对两者相似度,进行预判

效果展示:

以上示例,使用python-flask简单封装了face_recognition接口 完整代码

三、人脸识别原理

注:只对人脸识别应用感兴趣同学,可以跳过此章节

人脸识别,一般可分为四个步骤:

  • 定位人脸

  • 提取脸部特征

  • 脸部特征参数化

  • 比对源库作人脸辨识

3.1 定位人脸

人脸定位应用HOG算法,通过渐变替换像素,获取图片人脸主要特征。

我们首先将图片置为黑白,剔除色彩影响,然后根据像素点周围渐变趋势,用箭头标记:

(图源:人脸识别原理)

重复如此操作,最后得到箭头标记后的图像( HOG算法实现代码 ):

HOG算法中转图像的目的,是忽略图像色彩、明亮度等影响,准确定位到图片中人脸位置,为下一步提取脸部特征做好准备。

3.2 提取脸部特征

定位到人脸位置后,我们会面对一个新问题:即不同视角下(正脸、侧脸)呈现不同?在同一纬度,待识别图和源图皆为正面,那么预测会更加精准。

于是,进行简易的中转,得到待识别图的近似正脸图。

接着,我们需要提取识别图中人脸的特征。就像美术生在素描时,通常会做构图前点位设置。

(图源:CMU的Brandon Amos)

3.3 脸部特征参数化

接下来就是本文重点了!!

每一张待人脸识别的图像,会经由机器转为128位参数化标识。

那么,机器按怎样的规则做图像参数化呢?通过训练一个深度卷积神经网络,进行深度学习和训练,确定图像转128位规则。

训练方式:

  • 导入已知人脸图像,得到#1

  • 加载已知人的另外一张图片,得到#2

  • 加载非已知人的图片,得到#3

我们不断调整算法和参数,使得#1与#2越来越接近、#1与#3越来越疏远,经过百万千万次运算,最终神经网络便能学会最优的图像参数化规则,达到人脸识别目的。

3.4 比对源库作人脸辨识

我们把得到的128位数值,与数据源库比对,找到最相似的,即完成人脸识别。通过一个简单SVM分类器,可以让比对过程,缩短到几毫秒。

四、进阶:视频打码

前有霍某,后有迪某,这可忙坏了热门综艺《披荆斩棘的GG》后期同学,这里也帮后期同学们减压,让程式自动打码吧!

我们选取一小段《披荆斩棘的GG》原视频:

打码后的视频如下:

主要借助ffmpeg、opencv实现,(完整代码来源:Jack Cui)就不用重复造轮子了:

def mask_video(input_video, output_video, mask_path='mask.jpg'):     # 打码图片     mask = cv2.imread(mask_path)     # 读取视频     cap = cv2.VideoCapture(input_video)     # 读取视频参数,fps、width、heigth     CV_CAP_PROP_FPS = 5     CV_CAP_PROP_FRAME_WIDTH = 3     CV_CAP_PROP_FRAME_HEIGHT = 4     v_fps = cap.get(CV_CAP_PROP_FPS)     v_width = cap.get(CV_CAP_PROP_FRAME_WIDTH)     v_height = cap.get(CV_CAP_PROP_FRAME_HEIGHT)     # 设置写视频参数,格式为 mp4     size = (int(v_width), int(v_height))     fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')     out = cv2.VideoWriter(output_video, fourcc, v_fps, size)     # 已知人脸     known_image = face_recognition.load_image_file("lyd2.png")     # print(known_image)     biden_encoding = face_recognition.face_encodings(known_image)[0]     print(biden_encoding)     # 读取视频     cap = cv2.VideoCapture(input_video)     while(cap.isOpened()):         ret, frame = cap.read()         if ret:             # 检测人脸             face_locations = face_recognition.face_locations(frame)             # 检测每一个人脸             for (top_right_y, top_right_x, left_bottom_y, left_bottom_x) in face_locations:                 unknown_image = frame[top_right_y-50:left_bottom_y +                                       50, left_bottom_x-50:top_right_x+50]                 if unknown_image is None:                     break                 try:                     unknown_encoding = face_recognition.face_encodings(unknown_image)[0]                 except:                     break                 # 对比结果                 results = face_recognition.compare_faces(                     [biden_encoding], unknown_encoding)                 # 是李云迪,就打码                 if results[0] == True:                     mask = cv2.resize(mask, (top_right_x-left_bottom_x, left_bottom_y-top_right_y))                     frame[top_right_y:left_bottom_y,left_bottom_x:top_right_x] = mask             # 写入视频             out.write(frame)         else:             break 复制代码

代码解读:

  • 借助opencv,读取视频流cap = cv2.VideoCapture(input_video),获取每一帧while(cap.isOpened())

  • 针对每一帧做人脸识别face_recognition.compare_faces(),若识别到目标人脸,则对每帧图像做打码cv2.resize()

  • 图像流保存,逐帧写入视频out.write(frame)

  • 新视频是无声的,可以通过ffmpeg转音频,再整合到一起

五、问题与方案

5.1 face_recognition对小孩和亚洲人脸辨识度较低

官方说明是缺少数据源,解决办法是扩大对应的训练库。另外,在特定人脸定位不佳,也可以针对性进行深度学习,以提升识别准确度。

5.2 视频人脸动态变化,导致打码完整度低

视频过长,对应人脸变动较大,在演示中明显发现远视角和低补光下,识别不佳,对应我们逐帧定位人脸大小,自适应打码。若想达到更好效果,人工辅助和矫正也是必不可少的。

5.3 人脸识别商业化

安防、交通、金融、楼宇是较为常见领域,但是其天然互联网属性,可以孕育出更多创造性产品,比如前一阵很火的换脸视频、宠物情绪探测器等等。随着物联网普及,相信人脸识别也会有很多有趣应用落地。

六、总结

本文通过face_recognition为大家演示了人脸识别搭建,同时介绍了背后人脸定位、特征提取、深度学习原理。最后,借助opencv通过逐帧处理,实现视频打码,让《披荆斩棘的GG》中迪某,”码“上消失。


作者:起个帅的名
链接:https://juejin.cn/post/7024307464828878862

文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐