简单又神奇的面部识别指南,让你不再对韩国女星“脸盲”
简单又神奇的面部识别指南,让你不再对韩国女星“脸盲”
全文共8587字,预计学习时长20分钟或更长
韩国女团Twice
对很多程序猿/媛来说,脸盲症绝对是个要命的短板,尤其是那些青春靓丽但偏偏又彼此相似的韩国明星……这时候,就需要图像识别中的面部识别技术来助你一臂之力了。
Amazon Rekognition网站提供了许多有用的功能,例如“物体和场景检测”、“面部识别”、“面部分析”和“名人识别”。不过,在针对韩国明星的“名人识别”功能体验中,Amazon Rekognition偶尔会遇到麻烦:有时系统无法识别,还有时识别结果是错误的。
图为女团Twice中的周子瑜,但Amazon把她识别成了金雪炫(另一个韩国女团AOA成员)
因此,本文将用Amazon Rekognition编写一个简单的Python脚本,从而来准确地识别Twice的成员。
用Amazon Rekognition进行人脸检测
为了能在Jupyter Notebook上运行本文中的代码,你需要满足以下几个条件:
1. 拥有亚马逊AWS账户
2. 使用AWS命令行界面(CLI)配置的AWS凭证
3. 更新Boto3至最新版本
首先,导入一些package,这些package可用于下一步。
import boto3 from PIL import Image %matplotlib inline
现在需要找到一张想要处理的图片。我们以上文出现过的图片为例。把图片发送到Rekognition API,获取图像识别结果。
display(Image.open('Tzuyu.jpeg'))
我们可以把最基本的任务,也就是面部识别交给Rekognition来做。只需几行代码就能完成这个任务。
import io rekognition = boto3.client('rekognition') image = Image.open("Tzuyu.jpeg") stream = io.BytesIO() image.save(stream,format="JPEG") image_binary = stream.getvalue() rekognition.detect_faces( Image={'Bytes':image_binary}, Attributes=['ALL'] )
你可以直接把图片作为内存中的二进制文件对象,从本地计算机发送到Rekogntion,也可以上传图片到S3,并在调用rekognition.detect_faces()时将存储桶和密钥作为参数给出。在这里,把图片作为二进制对象发出。上述调用会花费很长时间。你可以从Rekognition的detect_faces功能中获得所有信息。
{'FaceDetails': [{'AgeRange': {'High': 38, 'Low': 20}, 'Beard': {'Confidence': 99.98848724365234, 'Value': False}, 'BoundingBox': {'Height': 0.1584049016237259, 'Left': 0.4546355605125427, 'Top': 0.0878104418516159, 'Width': 0.09999311715364456}, 'Confidence': 100.0, 'Emotions': [{'Confidence': 37.66959762573242, 'Type': 'SURPRISED'}, {'Confidence': 29.646778106689453, 'Type': 'CALM'}, {'Confidence': 3.8459930419921875, 'Type': 'SAD'}, {'Confidence': 3.134934186935425, 'Type': 'DISGUSTED'}, {'Confidence': 2.061260938644409, 'Type': 'HAPPY'}, {'Confidence': 18.516468048095703, 'Type': 'CONFUSED'}, {'Confidence': 5.1249613761901855, 'Type': 'ANGRY'}], 'Eyeglasses': {'Confidence': 99.98339080810547, 'Value': False}, 'EyesOpen': {'Confidence': 99.9864730834961, 'Value': True}, 'Gender': {'Confidence': 99.84709167480469, 'Value': 'Female'}, 'Landmarks': [{'Type': 'eyeLeft', 'X': 0.47338899970054626, 'Y': 0.15436244010925293}, {'Type': 'eyeRight', 'X': 0.5152773261070251, 'Y': 0.1474122554063797}, {'Type': 'mouthLeft', 'X': 0.48312342166900635, 'Y': 0.211111381649971}, {'Type': 'mouthRight', 'X': 0.5174261927604675, 'Y': 0.20560002326965332}, {'Type': 'nose', 'X': 0.4872787892818451, 'Y': 0.1808750480413437}, {'Type': 'leftEyeBrowLeft', 'X': 0.45876359939575195, 'Y': 0.14424000680446625}, {'Type': 'leftEyeBrowRight', 'X': 0.4760720133781433, 'Y': 0.13612663745880127}, {'Type': 'leftEyeBrowUp', 'X': 0.4654795229434967, 'Y': 0.13559915125370026}, {'Type': 'rightEyeBrowLeft', 'X': 0.5008187890052795, 'Y': 0.1317606270313263}, {'Type': 'rightEyeBrowRight', 'X': 0.5342025756835938, 'Y': 0.1317359358072281}, {'Type': 'rightEyeBrowUp', 'X': 0.5151524543762207, 'Y': 0.12679456174373627}, {'Type': 'leftEyeLeft', 'X': 0.4674917757511139, 'Y': 0.15510375797748566}, {'Type': 'leftEyeRight', 'X': 0.4817998707
从上面detect_faces的响应示例中可以看出,识别结果不仅包含人脸在图片中的边界框位置,还包含更高级的特征,如情感、性别、年龄段等。
人脸比较
Amazon Rekognition可以帮助对比两张图片中的人脸。例如,如果将子瑜的图片设为源图片,然后发送一张Twice成员的照片作为目标图片,Rekognition能够从目标图片中找到同源图片最相像的脸。我们要用到的Twice集体照就是下面这张。
如果你既不是亚洲人也不是Twice粉的话,可能连作为人类的你也无法完成这项任务。你可以猜猜这张图片里谁是子瑜。现在让我们来看看Rekognition是怎么完成任务的。
sourceFile='Tzuyu.jpeg' targetFile='twice_group.jpg' imageSource=open(sourceFile,'rb') imageTarget=open(targetFile,'rb') response = rekognition.compare_faces(SimilarityThreshold=80, SourceImage={'Bytes': imageSource.read()}, TargetImage={'Bytes': imageTarget.read()}) response['FaceMatches']
输入compare_faces作为指令,系统会分析团体照中所有不匹配人脸的信息,这会花费大量时间。因此,我们将指令特殊化成[‘FaceMatches’],要求Rekognition只输入匹配的人脸信息。看上去,Rekognition从这张团体照中找出了一张相似度为97%的人脸。让我们通过边界框信息来检查一下Rekognition有没有在集体照中正确识别出周子瑜。
顺便一提,BoundingBox给出的值是人脸占整个图像大小的比率。所以,为了用BoundingBox的值来绘制边框,你需要将图像的真实长度或宽度乘以比率,计算人脸框的大小。利用下面的代码可以做到这一点。
from PIL import ImageDraw image = Image.open("twice_group.jpg") imgWidth,imgHeight = image.size draw = ImageDraw.Draw(image) box = response['FaceMatches'][0]['Face']['BoundingBox'] left = imgWidth * box['Left'] top = imgHeight * box['Top'] width = imgWidth * box['Width'] height = imgHeight * box['Height'] points = ( (left,top), (left + width, top), (left + width, top + height), (left , top + height), (left, top) ) draw.line(points, fill='#00d400', width=2) display(image)
Rekognition,干得漂亮!这确实就是子瑜!
创建集合
现在我们能够识别图片中的面部,并且可以从目标图像中识别出源图像的人脸。但是以上功能都是一次性的,我们还需要存储女团中每个成员的面部信息和名字。这样的话,每发送一张Twice的新照片,系统都可以检索数据,识别成员面部并且显示成员名。
为达到该目的,需要应用亚马逊的“基于存储的API操作(Storage-Based API Operations)”。该操作包括两种亚马逊特有的专有术语。“集合”指的是Rekognition存储已识别人脸信息的虚拟数据库。通过使用集合,可以进行“索引”。这里指的是检测图像中的人脸,然后将信息存储在指定的集合中。需要提到的是,Rekognition存储的信息不是实际的图像,而是由算法提取的特征向量。接下来让我们学习如何创建集合并且添加索引。
collectionId='test-collection' rekognition.create_collection(CollectionId=collectionId)
是的,就是这么简单。由于这是刚刚创建的新集合,因此里面没有存储任何信息。但是,让我们再看一下。
rekognition.describe_collection(CollectionId=collectionId)
在上面的响应中可以看到“FaceCount”的值是0。如果加入人脸索引并将其存储在集合中,这个值就会改变。
人脸索引
同样的,人脸索引也很简单,只需要在Rekognition中添加一行代码。
sourceFile='Tzuyu.jpeg' imageSource=open(sourceFile,'rb') rekognition.index_faces(Image={'Bytes':imageSource.read()},ExternalImageId='Tzuyu',CollectionId=collectionId)
你可以看到,上面的代码中设置了参数ExternalImageId,并把值命名为“子瑜”。当你尝试从新图片中识别出子瑜的脸时,Rekognition就会搜索索引中的面部信息。每当有新的面部被编入索引时,Rekognition就会给它一个独有的face ID。但是我们想在匹配出来的子瑜的脸旁边显示出她的名字。因此,需要用到参数ExternalImageId。现在,如果查看集合的话,会发现一个人脸信息已经被加到该集合中了。
rekognition.describe_collection(CollectionId=collectionId)
按图像搜索人脸
现在子瑜的面部信息已被加入到集合中,可以将一张新的图片发送到Rekognition进行匹配。但是search_faces_by_image功能有一个问题,那就是它每次只能检测一张人脸(图像中面积最大的脸)。因此,如果想在Twice的集体照中找到子瑜,还需要再添加一步。在执行detect_faces前,应利用每张脸的边界框信息,逐个调用search_faces_by_image。首先,让我们检测每个成员的面部信息。
imageSource=open('twice_group.jpg','rb') resp = rekognition.detect_faces(Image={'Bytes':imageSource.read()}) all_faces = resp['FaceDetails'] len(all_faces)
Rekognition从集体照中识别出了9张脸。不错。接下来裁剪照片,用serach_faces_by_image逐个搜索。
image = Image.open("twice_group.jpg") image_width,image_height = image.size for face in all_faces: box=face['BoundingBox'] x1 = box['Left'] * image_width y1 = box['Top'] * image_height x2 = x1 + box['Width'] * image_width y2 = y1 + box['Height'] * image_height image_crop = image.crop((x1,y1,x2,y2)) stream = io.BytesIO() image_crop.save(stream,format="JPEG") image_crop_binary = stream.getvalue() response = rekognition.search_faces_by_image( CollectionId=collectionId, Image={'Bytes':image_crop_binary} ) print(response) print('-'*100)
在search_faces_by_image的9个结果中,Rekognition发现了一张能够和集合中的面部匹配的人脸。我们只建立了子瑜的索引,所以匹配到的人脸就是子瑜的。在图片上显示边界框和名字吧。有关名字的部分,会用到把人脸编入索引时设置的ExternalImageId。
顺便说一下,在所有search_faces_by_image的响应中,“FaceMatches”是一个数组。也就是说,如果集合中有多个面部被匹配,系统则会显示所有的匹配结果。根据亚马逊的说法,这个数组是按照相似性得分排序的,相似性最高的优先。将数组中的第一项作为匹配度最高的结果。
from PIL import ImageFont import io image = Image.open("twice_group.jpg") image_width,image_height = image.size for face in all_faces: box=face['BoundingBox'] x1 = box['Left'] * image_width y1 = box['Top'] * image_height x2 = x1 + box['Width'] * image_width y2 = y1 + box['Height'] * image_height image_crop = image.crop((x1,y1,x2,y2)) stream = io.BytesIO() image_crop.save(stream,format="JPEG") image_crop_binary = stream.getvalue() response = rekognition.search_faces_by_image( CollectionId=collectionId, Image={'Bytes':image_crop_binary} ) if len(response['FaceMatches']) > 0: draw = ImageDraw.Draw(image) points = ( (x1,y1), (x2, y1), (x2, y2), (x1 , y2), (x1, y1) ) draw.line(points, fill='#00d400', width=2) fnt = ImageFont.truetype('/Library/Fonts/Arial.ttf', 15) draw.text((x1,y2),response['FaceMatches'][0]['Face']['ExternalImageId'], font=fnt, fill=(255, 255, 0)) display(image)
太棒了!答案又是正确的!
识别Twice的所有成员
现在,让我们开发更多的项目功能,使之能够识别团体照中的所有成员。为了实现这个目标,首先需要把所有人的面部信息编入索引(一共有9个成员)。在Christian Petters编写的亚马逊教程中提到:“为每个人添加多个参考图像会大大提高匹配的成功率。”他的建议简单易懂。因此,我们为每个成员都准备了四张照片,并添加了同一个成员的多张照片。
collectionId='twice' rekognition.create_collection(CollectionId=collectionId)
import os path = 'Twice' for r, d, f in os.walk(path): for file in f: if file != '.DS_Store': sourceFile = os.path.join(r,file) imageSource=open(sourceFile,'rb') rekognition.index_faces(Image={'Bytes':imageSource.read()},ExternalImageId=file.split('_')[0],CollectionId=collectionId) rekognition.describe_collection(CollectionId=collectionId)
好的。现在所有36张照片都被编入了“Twice”集合的索引。现在是时候检验成果了。升级后的Rekognition能够识别Twice的全部成员吗?
from PIL import ImageFont image = Image.open("twice_group.jpg") image_width,image_height = image.size for face in all_faces: box=face['BoundingBox'] x1 = box['Left'] * image_width y1 = box['Top'] * image_height x2 = x1 + box['Width'] * image_width y2 = y1 + box['Height'] * image_height image_crop = image.crop((x1,y1,x2,y2)) stream = io.BytesIO() image_crop.save(stream,format="JPEG") image_crop_binary = stream.getvalue() response = rekognition.search_faces_by_image( CollectionId=collectionId, Image={'Bytes':image_crop_binary} ) if len(response['FaceMatches']) > 0: draw = ImageDraw.Draw(image) points = ( (x1,y1), (x2, y1), (x2, y2), (x1 , y2), (x1, y1) ) draw.line(points, fill='#00d400', width=2) fnt = ImageFont.truetype('/Library/Fonts/Arial.ttf', 15) draw.text((x1,y2),response['FaceMatches'][0]['Face']['ExternalImageId'], font=fnt, fill=(255, 255, 0)) display(image)
是的,它做到了!它正确识别了所有成员!
Jupyter Notebook和所有照片传送门:
https://github.com/tthustla/twice_recognition
留言 点赞 关注
我们一起分享AI学习与发展的干货
欢迎关注全平台AI垂类自媒体 “读芯术”
-
- 歌坛巨星贾斯丁比伯25年的跌宕人生
-
2025-01-16 19:23:05
-
- 钢琴五线谱的各种记号大全,亲们速度收藏哈!
-
2025-01-16 19:20:50
-
- 郑爽的三宗罪,才是她翻车的根本原因
-
2025-01-16 19:17:49
-
- 世界杯历届回顾:第6届 1958年瑞典世界杯
-
2025-01-16 19:15:34
-
- 14部奥斯卡最佳动画短片,你可能一部都没陪孩子看过……
-
2025-01-16 19:13:19
-
- 成毅演绎爱国重义军人张不逊
-
2025-01-16 19:11:04
-
- “不要!好疼!求求你不要这样对我……求你饶过我……”
-
2025-01-16 19:08:49
-
- 鬼才导演今敏《红辣椒》- 一场华丽梦境下的自我救赎
-
2025-01-16 19:06:34
-
- “钢铁侠”马克系列战甲进化历程 图文详解(1)
-
2025-01-16 19:04:19
-
- “优越感”是什么?网上的我们为何如此在意“优越感”?
-
2025-01-16 19:02:04
-
- 跳蛛非凡的感官捕捉到了我们无法感知的世界
-
2025-01-16 18:59:50
-
- 郭台铭长子郭守正:这是准备接班了?
-
2025-01-16 18:57:35
-
- 南沙楼市投资是不是坑 看完这组人口数据再说话
-
2025-01-14 21:47:46
-
- 哪款祛痘产品最有效 十款口碑极好的祛痘产品排行榜
-
2025-01-14 21:45:31
-
- 春晚最牛观众你还记得吗?人称“笑脸哥”,比明星大腕上春晚还多
-
2025-01-14 21:43:16
-
- 比《柯南》还要精彩的《查理九世》,为何被家长举报直接下架
-
2025-01-14 21:41:01
-
- “榫卯”怎么读?-从读音开始,了解中国科技馆“榫卯的魅力”主题展览
-
2025-01-14 21:38:46
-
- 又潮又萌的男孩发型!妈妈们收藏吧
-
2025-01-14 21:36:31
-
- 硬核兄弟!《流浪地球》中俄罗斯“老铁”用生命与中国并肩作战
-
2025-01-14 21:34:17
-
- 新手怎么画眼睛?眼睛绘画教程
-
2025-01-14 21:32:02