内容简介:忙了一段时间,少有时间写文,前连天公司的一个web项目需要用户上传自拍照然后检查自拍照里面的人脸状态(人脸数量,是否正脸,是否戴眼镜,是否戴帽子等等),如果状态合适就将人脸提取出来,最后与设置的前景图片进行融合。这其中涉及到的关键点在于人脸的检测,人脸的提取,至于人脸与前景的融合则可以使用前端js实现,对人脸的处理一般使用滤镜处理,前端可以使用腾讯AlloyTeam团队开源的项目AlloyImage(关于滤镜处理图片这部分不多说了,仔细研读腾讯的开源项目文档就能搞定,今天说说人脸检测和提取部分,注意是“检
前言
忙了一段时间,少有时间写文,前连天公司的一个web项目需要用户上传自拍照然后检查自拍照里面的人脸状态(人脸数量,是否正脸,是否戴眼镜,是否戴帽子等等),如果状态合适就将人脸提取出来,最后与设置的前景图片进行融合。
这其中涉及到的关键点在于人脸的检测,人脸的提取,至于人脸与前景的融合则可以使用前端js实现,对人脸的处理一般使用滤镜处理,前端可以使用腾讯AlloyTeam团队开源的项目AlloyImage( http://alloyteam.github.io/AlloyImage/ )处理图片,拥有丰富的滤镜。当然也可以在后端处理好传给前端,后端处理可以选择使用OpenCV,后端处理的缺点在于多用户同时上传的时候服务器压力较大,交给前端处理比较妥当。
关于滤镜处理图片这部分不多说了,仔细研读腾讯的开源项目文档就能搞定,今天说说人脸检测和提取部分,注意是“检测”,不是“识别”。
检测的意思是只需要检查是人脸和人脸的状态以及人脸的位置,识别则是根据人脸特征匹配到人的姓名,这是两种不同的概念,千万不要混淆。
分析
既然是入门级的人脸检测,当然是从易到难,首先考虑的是有没有第三方人脸检测API,直接调用第三方接口,也是一种快速实现的方法。说到第三方接口,自然要货比三家,谁好用用谁。
经过搜索引擎的筛选,博主选择了四家服务商的接口,分别是百度、腾讯、阿里云、Face++。当然了,如果这篇文章只是单纯的描述如何调用第三方接口的话,估计各位看官也不会买账,不就是一个requests请求的事,还需要写个文?
为了体现从易到难循序渐进的思想,博主增加了本地检测的方式进行对比,本地 Python 配合OpenCV也可以实现人脸的检测,把这几种进行对比,自然就能看出各自的优劣。
当然了,本地OpenCV检测的速度和效率是第三方服务商接口调用无法比的,这也是为下一篇进阶(监控流媒体画面实时检测)打基础。
好了,废话不多说,开始几种方案的对比。
接口
首先对四家的接口文档进行分析,对接难度从易到难分别是 Face++、百度、腾讯、阿里云,参考标准是实现相同功能需要的代码行数(手动滑稽!)。
给出四家服务商的接口文档地址供大家自行参考:
- Face++ 文档地址:https://console.faceplusplus.com.cn/documents/4888373
- 腾讯人脸检测 文档地址:https://cloud.tencent.com/document/product/867/17588
- 百度 人脸检测 文档地址:http://ai.baidu.com/docs#/Face-Detect-V3/top
- 阿里云 人脸检测 文档地址:https://help.aliyun.com/knowledge_detail/53399.html
Face++和百度云不需要生成签名,只需要传入key和id即可,腾讯和阿里云需要生成对应的签名做认证才能调用成功,其中阿里云的签名生成是对所有的请求内容进行签名,稍有错误就导致签名失败,所以调试起来稍微有点复杂,博主也是在这里被坑的很惨。
Face++ 支持三种图片的传递方式,url、二进制、base64,文件大小为最大2M。
腾讯 支持两种图片的传递方式,url和二进制。
百度 支持两种图片的传递方式,url和Base64。
阿里云 支持两种图片的传递方式,url和Base64。
阿里云返回的结果中数据量最小,很多检测结果是没有的,比如是否戴眼镜,戴帽子等,当然了,这里的重点是人脸检测,只需要检测到人脸的位置信息就OK了,其他的都是次要信息。
针对项目需求,url传图的方式因为有图片下载的时间不确定性,而且用户上传图片后台转换url也是一道程序,还不如直接传图,四家服务商除了腾讯不支持base64以外,其他三家都支持base64,而且前端调用微信的图片上传方法可以直接将图片在前端就转换成base64,通过接口上传给服务端处理,调用腾讯云的时候可以将base64编码的图片直接decode成二进制文件,这样腾讯云就可以支持了。
实战
博主首选选取一张带有明显人脸标志的图片进行测试,上测试图(在此感谢迪丽热巴)
然后根据需求编写代码,先给出测试结果的对比图,再来根据各自的结果进行分析
从对比图可以看出,Face++和百度的识别结果基本一致,腾讯和本地OpenCV识别出来的结果非常接近,而阿里云识别出来的结果则是相对比较完整的人脸。
当然了,仅仅依靠这一张图很难判断出来谁更厉害,那咱们多来几个测试,首先来一张胡歌的侧脸特写(在此感谢胡歌)
这组检测结果里面依然是阿里云表现最佳,而百度则有点离谱,OpenCV虽然检测到的位置是准确的,但是检测人脸的范围出现了失误,显示为正方形。
下面再来一张,这张测试图是一张面部被头发遮挡并且不是正面,看下各自的识别结果(在此感谢袁姗姗)
从这组测试结果来看还是阿里云最佳,其次是face++,而OpenCV直接识别失败了!!
这里得说明一下,OpenCV识别失败并不是因为它就一定很垃圾,OpenCV的识别率是根据给定的人脸模型而来的,OpenCV自带了很多识别的模型,这些模型都是经过多次卷积网络算法训练得来的,而博主这里使用的是人脸最为严格的模型,也就是说识别的条件更为苛刻,所以在这次测试中OpenCV没有检测到人脸,比较尴尬。
所以,综上一些简单的测试后发现如果要做人脸的提取,还是选择阿里云的人脸检测接口比较合适,下面来看看各家API的收费情况,这里仅仅比对免费额度。
Face++提供免费的使用API key,不限制调用次数,但是一些高级的功能无法使用。
百度 对于个人用户提供QOS 为2 企业用户QOS 为10,调用次数不限的免费服务。
腾讯 提供不限次数的调用请求,但是高级功能需要付费。
阿里云 提供免费5000次的免费调用额度,5000次用完自动切换到付费模式。
这里放上一张前两天项目中的效果图吧
代码
根据各家提供的API文档和测试demo,编写各自的测试代码,下面提供代码供大家参考。
注意:这里代码仅仅作为快速调试的参考,没有做异常处理,正式开发请根据自身开发环境和生产环境自行考虑各种异常处理,请不要直接使用我的代码。
如果有不懂的地方可以发邮件询问。
Face++(图片以二进制上传)
# -*- coding: utf-8 -*- import requests, sys from PIL import Image, ImageDraw source_path = sys.path[0] + '/shanshan.jpg' with open(source_path, "rb") as f: file_data = f.read() params = { "api_key": "xxxxxx", "api_secret": "xxxxxxx" } f = {"image_file": file_data} request_url = "https://api-cn.faceplusplus.com/facepp/v3/detect" decode_result = requests.post(url=request_url, data=params, files=f, timeout=30).json() current_face = decode_result.get('faces')[0] face_location = current_face.get('face_rectangle') face_x = int(face_location.get("left")) face_y = int(face_location.get("top")) face_width = face_x + int(face_location.get("width")) face_height = face_y + int(face_location.get("height")) old_img = Image.open(source_path) draw_instance = ImageDraw.Draw(old_img) draw_instance.rectangle((face_x, face_y, face_width, face_height), outline=(255, 0, 0)) old_img.save(sys.path[0] + '/i-face++.jpg')
百度
# -*- coding: utf-8 -*- import requests, sys, base64 from PIL import Image, ImageDraw source_path = sys.path[0] + '/shanshan.jpg' # client_id 为官网获取的AK, client_secret 为官网获取的SK host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=*********&client_secret=**********' session = requests.get(url=host, timeout=30).json() access_token = session.get('access_token') with open(source_path, "rb") as f: base64_data = base64.b64encode(f.read()) params = { "image": base64_data, "image_type": "BASE64", "face_field": "beauty,age,glasses,face_type,quality" } request_url = "https://aip.baidubce.com/rest/2.0/face/v3/detect" request_url = request_url + "?access_token=" + access_token decode_result = requests.post(url=request_url, data=params, timeout=30).json() face_num = decode_result.get('result').get('face_num') current_face = decode_result.get('result').get('face_list')[0] face_location = current_face.get('location') face_glasses = current_face.get('glasses') face_real = current_face.get('face_type') face_quality = current_face.get('quality') face_probability = current_face.get('face_probability') face_angel = current_face.get('angel') face_x = int(face_location.get("left")) face_y = int(face_location.get("top")) face_width = face_x + int(face_location.get("width")) face_height = face_y + int(face_location.get("height")) old_img = Image.open(source_path) draw_instance = ImageDraw.Draw(old_img) draw_instance.rectangle((face_x, face_y, face_width, face_height), outline=(255, 0, 0)) old_img.save(sys.path[0] + '/i-baidu.jpg')
腾讯
# -*- coding: utf-8 -*- import requests, sys, base64, time, random, hashlib, hmac from PIL import Image, ImageDraw source_path = sys.path[0] + '/shanshan.jpg' orignal = "a=******&b=&k=*******&e=******&t=%d&r=%d&f=" % (int(time.time()), random.randint(1, 1000)) SignTmp = hmac.new("**********".encode('utf8'), orignal.encode('utf8'), hashlib.sha1).digest() before_string = SignTmp + orignal.encode('utf8') Sign = base64.b64encode(before_string).decode('utf8') request_url = "https://recognition.image.myqcloud.com/face/detect" headers = {"authorization": Sign, "host": "recognition.image.myqcloud.com"} s = requests.session() with open(source_path, "rb") as f: img_file = f.read() params = {"appid": "*********", "mode": 1} f = {"image": open(source_path, "rb").read()} decode_result = s.post(url=request_url, headers=headers, data=params, files=f, timeout=30).json() if decode_result.get('code') == 0: face_data = decode_result.get('data') current_face = face_data.get('face')[0] face_x = int(current_face.get("x")) face_y = int(current_face.get("y")) face_width = face_x + int(current_face.get("width")) face_height = face_y + int(current_face.get("height")) old_img = Image.open(source_path) draw_instance = ImageDraw.Draw(old_img) draw_instance.rectangle((face_x, face_y, face_width, face_height), outline=(255, 0, 0)) old_img.save(sys.path[0] + '/i-tencent.jpg')
阿里云
# -*- coding: utf-8 -*- import requests, sys, base64, hashlib, hmac, json, datetime from PIL import Image, ImageDraw source_path = sys.path[0] + '/shanshan.jpg' id = "*******" key = "***********" request_url = "https://dtplus-cn-shanghai.data.aliyuncs.com/face/detect" with open(source_path, "rb") as f: base64_data = base64.b64encode(f.read()).decode('utf8') params = {"type": 1, "content": base64_data} def get_current_date(): date = datetime.datetime.strftime(datetime.datetime.utcnow(), "%a, %d %b %Y %H:%M:%S GMT") return date def to_md5_base64(string_body): hash_obj = hashlib.md5() hash_obj.update(string_body.encode('utf8')) return base64.b64encode(hash_obj.digest()).decode('utf8') def to_sha1_base64(string_to_sign, secret): hmac_sha1 = hmac.new(secret.encode('utf8'), string_to_sign.encode('utf8'), hashlib.sha1) return base64.b64encode(hmac_sha1.digest()).decode('utf8') options = { 'method': 'POST', 'body': json.dumps(params), 'headers': { 'accept': 'application/json', 'content-type': 'application/json', 'date': get_current_date() } } body_md5 = to_md5_base64(options.get('body')) string_sign = '%s\n%s\n%s\n%s\n%s\n%s' % ( options.get('method'), options.get('headers').get('accept'), body_md5, options.get('headers').get('content-type'), options.get('headers').get('date'), "/face/detect" ) signature = to_sha1_base64(string_sign, key) headers = { 'Accept': 'application/json', 'Content-type': 'application/json', "Date": options.get('headers').get('date'), "Authorization": "Dataplus %s:%s" % (id, signature) } s = requests.session() decode_result = s.post(url=request_url, headers=headers, data=json.dumps(params), timeout=30).json() if decode_result.get('errno') == 0: face_data = decode_result.get('face_rect') face_x = int(face_data[0]) face_y = int(face_data[1]) face_width = face_x + int(face_data[2]) face_height = face_y + int(face_data[3]) old_img = Image.open(source_path) draw_instance = ImageDraw.Draw(old_img) draw_instance.rectangle((face_x, face_y, face_width, face_height), outline=(255, 0, 0)) old_img.save(sys.path[0] + '/i-aliyun.jpg')
OpenCV
# -*- coding: utf-8 -*- import cv2, sys from PIL import Image, ImageDraw def test_face(): source_path = sys.path[0] + '/shanshan.jpg' img = cv2.imread(source_path) face_cascade = cv2.CascadeClassifier("/usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.3, 4) if len(faces) > 1: print("不止一个人脸") else: print("一个人脸") face_x = faces[0][0] face_y = faces[0][1] face_width = face_x + faces[0][2] face_height = face_y + faces[0][3] old_img = Image.open(source_path) draw_instance = ImageDraw.Draw(old_img) draw_instance.rectangle((face_x, face_y, face_width, face_height), outline=(255, 0, 0)) old_img.save(sys.path[0] + '/i-opencv.jpg') if __name__ == '__main__': test_face()
请根据自己的环境自行替换代码中的参数进行测试。
如果需要对图片中的人脸进行提取也非常简单,增加下面的代码即可
image_name = sys.path[0] + '/cut-opencv.jpg' Image.open(source_path).crop((face_x, face_y, face_width, face_height)).save(image_name)
用途
写了这么多,到底都有啥用途呢,很常见的那种颜值测试就可以用这种api直接实现,api里面都可以直接返回颜值分数,非常简单。
本文链接:https://www.92ez.com/?action=show&id=23472
!!! 转载请先联系non3gov@gmail.com授权并在显著位置注明作者和原文链接 !!!小黑屋
提示:技术文章有一定的时效性,请先确认是否适用你当前的系统环境。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 人脸专集(三):人脸关键点检测(下)
- iOS 相机流人脸识别(一)-人脸框检测(基于iOS原生)
- 自然场景人脸检测技术实践
- 算法升级!开源极快速CNN人脸检测新增人脸关键点功能
- 50行Python代码实现人脸检测
- 最新人脸检测 & 识别的趋势和分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。