- 🎬 博客主页:https://xiaoy.blog.csdn.net
- 🎥 本文由 呆呆敲代码的小Y 原创,首发于 CSDN🙉
- 🎄 学习专栏推荐:Unity系统学习专栏
- 🌲 游戏制作专栏推荐:游戏制作
- 🌲Unity实战100例专栏推荐:Unity 实战100例 教程
- 🏅 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
- 📆 未来很长,值得我们全力奔赴更美好的生活✨
- ------------------❤️分割线❤️-------------------------
📢 前言
- 本篇文章来学习一下怎样使用
Unity实现简单地人脸识别
功能。 - 关于人脸识别,我们可以选择很多平台的SDK接入Unity来实现人脸识别的功能。
- 比如
百度AI开放平台
、科大讯飞人脸识别
、支付宝蚂蚁人脸认证
、虹软人脸识别算法
等等。 - 本文中的方法是基于百度AI开放平台实现的,后续有时间也会使用其他平台尝试一下效果如何。
🎬 实战篇 |基于百度AI开放平台实现简易版人脸识别功能
一、获取SDK准备工作
文章部分文档链接如下:
- 百度AI开放平台:https://ai.baidu.com/
- C#文档:https://ai.baidu.com/ai-doc/FACE/Ck37c1ri0
- SDK下载地址:https://ai.baidu.com/sdk#bfr
- C# SDK 开源:https://github.com/Baidu-AIP/dotnet-sdk
- 控制台地址:https://console.bce.baidu.com/ai/?fromai=1#/ai/face/offline/index
1.1 前往 百度AI开放平台 登录
既然选择了使用 百度AI开放平台的SDK,那我们就需要去官网下载SDK啦!
首先我们需要前往 百度AI开放平台,要登录百度账号。
如果之前有账号则直接登录,没有的话点击去注册一个就好了,这里不多赘述。
1.2 前往 人脸与人体
然后点击
开放能力
->
人脸与人体
->
人脸搜索
点击立即使用会跳转到控制台界面,然后点击 公有云服务 -> 应用列表。
1.3 创建一个应用
在 公有云服务 中点击 应用列表。
若此时没有应用,则进行创建。
找不到的小伙伴可以直接点击该链接,看看能不能直达创建应用的网址:https://console.bce.baidu.com/ai/#/ai/face/app/create
点击完之后该应用就创建完毕了,
APPID
和
API KEY
以及
Secret Key
要保存好,后面在Unity中也会用到!
1.3 下载人脸识别SDK资源
接下来在 百度AI开放平台 的首页点击
开发与教学 -> SDK下载
选择
人脸识别 -> C# HTTP SDK
点击下载
可能随着时间推移,官方的进入SDK下载的页面会发生改变。
如果改变了不跟我文中位置一致,大家可以在首页自己找找看,只要找到SDK下载的地方就行,一般不会太隐蔽。
也可以点击SDK下载地址直接转入:https://ai.baidu.com/sdk#bfr
1.4 从SDK中取出我们会使用的文件
下载SDK后,解压到本地文件夹中。
之后打开
net35
文件夹,其中
AipSdk.dll
和
Newtonsoft.Json.dll
这两个dll文件,后边会放到Unity3d工程中使用。
1.5 人脸离线识别SDK申请
如果想使用 人脸离线识别 功能则需要单独去申请。本文教程暂时没有用到,不感兴趣的话可以跳过此内容。
点击
开放能力 -> 人脸与人体 -> 人脸识别离线SDK
我这里选择了
Android版
,最后打算使用一个Android设备进行测试。
大家可以根据自己的需求选择,操作步骤整体差异不大。
可以看到有一个 立即使用 和 技术文档 。
点击立即使用后会进入下一个页面,让我们填写一些信息 申请SDK。
那我们就简单填写一下就好了,填写完之后需要等一段时间审核,我这里第一次的时候等了大概十几分钟就申请好了。
二、Unity端操作
2.1 新建一个Unity工程
新建一个Unity打开后 打开
File>BuildSettings -> PlayerSettings -> OtherSettings
改变
Api Compatibility Level
为
.NET2.0
,若本来就是则不需要修改。
2.2 导入 人脸识别 .dll文件
在
Assets
下新建一个
Plugins
文件夹,注意不要拼错单词哦~
将上面讲到的两个文件
AipSdk.dll
和
Newtonsoft.Json.dll
放入该文件夹。
然后新建一个测试场景和脚本,命名随意。
打开人脸识别的C#官方文档:https://ai.baidu.com/ai-doc/FACE/Ck37c1ri0
文档中的步骤挺详细,可以结合文章与文档共同参考 ~
2.3 新建交互类
定义一个客户端,此时要用到之前创建的应用的
APPID
、
APIKey
和
SecretKey
代码如下:
usingBaidu.Aip.Face;usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;publicclassFaceRecognitionDemo:MonoBehaviour{// 设置APPID/AK/SKpublicstring APP_ID ="你的 App ID";publicstring API_KEY ="你的 Api Key";publicstring SECRET_KEY ="你的 Secret Key";Face client;voidStart(){
client =newFace(API_KEY, SECRET_KEY);
client.Timeout =60000;// 修改超时时间}}
2.4 人脸注册
接下来要进行人脸注册,简单意思就是我们要将几张某个人的照片传到人脸库中,用于下面的人脸识别时使用。
我们先注册几个人脸,官网教程中各个参数说明很清楚,想要了解更多内容也可以在官网仔细查看,我们一步一步来。
人脸注册 返回数据参数详情
人脸注册 返回示例
{"face_token":"2fa64a88a9d5118916f9a303782a97d3","location":{"left":117,"top":131,"width":172,"height":170,"rotation":4}}
注册人脸代码如下:
// 人脸注册publicvoidSignUpFace(string image,string imageType,string groupId,string userId){var options =newDictionary<string,object>{{"user_info","user's info"},{"quality_control","NORMAL"},{"liveness_control","LOW"}};// 带参数调用人脸注册var result = client.UserAdd(image, imageType, groupId, userId, options);
Debug.Log(result);}
2.5 注册人脸 上传到 百度大脑人脸识别库
上面说的人脸注册 有两种方法可以实现,一是可以选择在云端手动创建组然后添加图片,二是可以通过URL方式在Unity中上传,下面都有介绍操作方式。
1.在控制台手动创建组并添加用户
手动创建方法很简单,直接点击新建组然后创建用户,将图片添加上即可!
2.使用脚本代码在Unity中上传人脸库
下面再来简单说一下在Unity中通过url上传的方法。
在Unity项目的Assets下 创建文件夹
StreamingAssets / FaceUpLoad
然后在网上找几张同一个人的图片,用作人脸识别测试时候使用,将下载的图片放到我们创建的文件夹中。
代码如下:
//获取图片base64字符串,由于QPS限制,此处采用协程降低注册频率IEnumeratorIEGetStringBase64(){//获取到每一张图片的路径string[] picsPathArr = Directory.GetFiles(Application.streamingAssetsPath +"/**FaceDetect**/");//循环获取每张图片的base64字符串for(int i =0; i < picsPathArr.Length; i++){//unity会自动生成.meta文件,过滤掉if(picsPathArr[i].Contains("meta"))continue;//读取FileInfo file =newFileInfo(picsPathArr[i]);var stream = file.OpenRead();byte[] buffer =newbyte[file.Length];//读取图片字节流
stream.Read(buffer,0, Convert.ToInt32(file.Length));//base64字符串string imageBase64 = Convert.ToBase64String(buffer);//采用base64字符串方式上传string imageType ="BASE64";//用户组string groupId ="GodY";//用户id,一般同一个人的图片放在同一个id下string userId ="xiaoY";//开始注册SignUpFace(imageBase64, imageType, groupId, userId);yieldreturnnewWaitForSeconds(0.6f);}}
@@需要换图
注册完后我们可以在百度大脑的控制台找到之前创建的应用的人脸识别库里看到上传的图片
2.6 使用图片进行 人脸对比
上面我们已经将人脸注册到人脸库了,下面就来在Unity中使用一张新的图片来与人脸库中的进行人脸对比。
虽然说上去是进行人脸对比,实际上是使用的人脸搜索的API。
值得注意的是 使用该人脸搜索方法是从我们注册的人脸库中 检测与我们当前想要进行比较的人脸最相似的人脸,所以说我们最好是新建组之后,为想进行识别的人脸单独创建在一个userID会比较好管理!
可以在官网查看更多关于人脸搜索与人脸库管理详细参数:https://ai.baidu.com/ai-doc/FACE/Gk37c1uzc
我们这里使用的应该是 1:N 人脸搜索,人脸对比其实和人脸搜索实现的功能效果差不多。
关于这俩的对比差异,官方也给出了解答,我们就不纠结这个了,这个直接拿来做测试使用就行!
后面感兴趣可以把官方给的样例全部使用测试一遍,看看到底哪个更好用一些 ~
接下来我们另外弄一张之前人脸库里没有的图片保存到FaceDetect文件夹下
编写脚本代码如下:代码中的groupid需要改成自己的人脸识别库中创建的的groupid
userid需要改成自己的人脸识别库中的userid
publicvoidFaceSearch(){//1.拿到我们放在文件夹中的照片文件FileInfo file =newFileInfo(Application.streamingAssetsPath +"/FaceDetect/图片文件名.jpg");var stream = file.OpenRead();byte[] buffer =newbyte[file.Length];
stream.Read(buffer,0, Convert.ToInt32(file.Length));//读取图片字节流var image = Convert.ToBase64String(buffer);//2.使用人脸搜索API进行对比查询var imageType ="BASE64";var groupIdList ="@@@";//需修改为自己人脸库的组,人脸库注册的组var options =newDictionary<string,object>{{"match_threshold",70},//限制 匹配阈值(设置阈值后,score低于此阈值的用户信息将不会返回){"user_id","@@@"},//需修改为自己人脸库的id,在指定某个固定user_id时调用,可不加此部分};var result = client.Search(image, imageType, groupIdList,options);
Debug.Log(result);}
对比后会返回一组数据,其中我们只要看score的值,就可以看到人脸的相似度如何
如果score值超过80,就基本认定是同一个人。
检测结果如下:
这样我们基本就实现了一个简单的人脸识别功能,在注册完人脸库之后,就可以自己随便找一些人脸照片进行测试使用啦!
当然这样对使用者来说体验很差,需要一直去看返回的score值来判断人脸识别的结果。
下面就对该功能进行一个整合优化体验给大家做一个参考,更多想法可以自己改进体验哦!
三、将工程优化整合,人性化处理
简单说一下整合优化的思路。
- 增加一个打开文件夹选择文件的功能,可以让我们手动选择照片进行对比
- 增加一个检测结果相似度的UI显示,优化显示效果
- 增加一个对比人脸的选项,可自定义多款人脸对比
搭建一个UI效果如下:
实际识别检测效果如下:
我们可以通过在人脸识别库中添加某个人的人脸照片,就可以实现在Unity中自定义某个人的人脸识别检测!
四、代码一直调用失败问题
4.1 免费领取试用资源
第一次使用的时候代码一直报错,问了客服才知道原来是免费资源没有领取导致的!!所以直接去领取资源吧!
"error_code":18,"error_msg":"Open api qps request limit reached"
免费资源领取地址:https://console.bce.baidu.com/ai/#/ai/face/overview/index
选择需要领取的资源点击领取。
领取后的资源可以在资源列表中查看!
问客服的地址如下:https://ticket.bce.baidu.com/#/ticket/list
有疑问直接创建工单提问即可。
五、工程源码下载
虽然文章内容不少,但是整体流程很简单。
先建一个交互类,然后注册人脸,就进行人脸识别就可以了!
工程下载地址:https://download.csdn.net/download/zhangay1998/86803920
本文优化后最终效果核心脚本代码展示:
Windows简易版源码如下
usingBaidu.Aip.Face;usingSystem;usingSystem.Collections;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Runtime.InteropServices;usingUnityEngine;usingUnityEngine.UI;publicclassFaceRecognitionDemo:MonoBehaviour{[Header("设置APPID/AK/SK")]publicstring APP_ID ="你的 App ID";publicstring API_KEY ="你的 Api Key";publicstring SECRET_KEY ="你的 Secret Key";Face client;[Header("UI部分")]publicButton _selectDocumentBtn;//选择文件按钮publicButton _faceSearchBtn;//开始检测按钮publicImage _faceSearchImage;//当前选择的图片publicText _faceSearchTxt;//检测结果文本privatefloat _faceSearchScore;//最终返回的分数privateTexture2D m_Tex;privateOpenFileName ofn;voidStart(){
ofn =newOpenFileName();
client =newFace(API_KEY, SECRET_KEY);
client.Timeout =60000;// 修改超时时间
_selectDocumentBtn.onClick.AddListener(OpenFileWin);
_faceSearchBtn.onClick.AddListener(FaceSearch);//StartCoroutine(IEGetStringBase64());}//可优化部分:开始检测换为协程,加一个等待两秒的动画,两秒结束后显示检测结果#region 注册人脸部分//获取图片base64字符串,由于QPS限制,此处采用协程降低注册频率IEnumeratorIEGetStringBase64(){//获取到每一张图片的路径string[] picsPathArr = Directory.GetFiles(Application.streamingAssetsPath +"/FaceUpLoad/");//循环获取每张图片的base64字符串for(int i =0; i < picsPathArr.Length; i++){//unity会自动生成.meta文件,过滤掉if(picsPathArr[i].Contains("meta"))continue;//读取FileInfo file =newFileInfo(picsPathArr[i]);var stream = file.OpenRead();byte[] buffer =newbyte[file.Length];//读取图片字节流
stream.Read(buffer,0, Convert.ToInt32(file.Length));//base64字符串string imageBase64 = Convert.ToBase64String(buffer);//采用base64字符串方式上传string imageType ="BASE64";//用户组string groupId ="group1";//用户id,一般同一个人的图片放在同一个id下string userId ="YangMi";//开始注册SignUpFace(imageBase64, imageType, groupId, userId);yieldreturnnewWaitForSeconds(0.6f);}}/// <summary>/// 人脸注册/// </summary>/// <param name="image"></param>/// <param name="imageType"></param>/// <param name="groupId"></param>/// <param name="userId"></param>publicvoidSignUpFace(string image,string imageType,string groupId,string userId){var options =newDictionary<string,object>{{"user_info","WuYanZu"},{"quality_control","NORMAL"},{"liveness_control","LOW"},{"action_type","REPLACE"}};// 带参数调用人脸注册var result = client.UserAdd(image, imageType, groupId, userId, options);
Debug.Log("注册完成:"+ result);}#endregion/// <summary>/// 打开文件夹选择想检测的文件/// </summary>publicvoidOpenFileWin(){
ofn.structSize = Marshal.SizeOf(ofn);
ofn.filter ="All Files\0*.*\0\0";
ofn.file =newstring(newchar[256]);
ofn.maxFile = ofn.file.Length;
ofn.fileTitle =newstring(newchar[64]);
ofn.maxFileTitle = ofn.fileTitle.Length;string path = Application.dataPath;
path = path.Replace('/','\\');//默认路径
ofn.initialDir = path;//ofn.initialDir = "D:\\MyProject\\UnityOpenCV\\Assets";
ofn.title ="Open Project";
ofn.defExt ="xlsx";//显示文件的类型 //注意 一下项目不一定要全选 但是0x00000008项不要缺少
ofn.flags =0x00080000|0x00001000|0x00000800|0x00000200|0x00000008;//OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST| OFN_ALLOWMULTISELECT|OFN_NOCHANGEDIR if(WindowDll.GetOpenFileName(ofn)){
Debug.Log("当前选择的文件路径:"+ ofn.file);SelectImage();}}/// <summary>/// 将选择的图片显示在Image上/// </summary>publicvoidSelectImage(){//加载LoadFromFile(ofn.file);//变换格式Sprite tempSprite = Sprite.Create(m_Tex,newRect(0,0, m_Tex.width, m_Tex.height),newVector2(10,10));
_faceSearchImage.sprite = tempSprite;//赋值}//开始对比publicvoidFaceSearch(){//1.拿到我们放在文件夹中的照片文件//FileInfo file = new FileInfo(Application.dataPath + "/StreamingAssets/FaceDetect/Ym14s.jpeg");FileInfo file =newFileInfo(ofn.file);var stream = file.OpenRead();byte[] buffer =newbyte[file.Length];
stream.Read(buffer,0, Convert.ToInt32(file.Length));//读取图片字节流var image = Convert.ToBase64String(buffer);//2.使用人脸搜索API进行对比查询var imageType ="BASE64";var groupIdList ="Test1";//人脸库注册的组,需替换为自己的人脸库组名var options =newDictionary<string,object>{{"match_threshold",70},{"user_id","ym"},//在指定某个固定user_id时调用,可不加此部分};var result = client.Search(image, imageType, groupIdList);
Debug.Log(result);string str = result.ToString();int scoreIndex = str.IndexOf("score");//返回人脸检测到的分数if(scoreIndex !=0)//避免拿不到返回的检测分数{string scoreResult = str.Substring(scoreIndex +8,5);//拿到返回数值后的操作//float f1 = Convert.ToSingle(scoreResult);float f;if(float.TryParse(scoreResult,out f)){
_faceSearchScore = f;}else{
_faceSearchScore =50f;}}else{ _faceSearchScore =50f;}DisplayingResults();}/// <summary>/// 结果处理/// </summary>privatevoidDisplayingResults(){if(_faceSearchScore >=80){
_faceSearchTxt.text="是本人没错了!";}else{
_faceSearchTxt.text ="不是本人!这是哪个小饼干??";}}/// <summary>/// 根据路径读取本地文件并转换为Texture2D文件/// </summary>/// <param name="path"></param>privatevoidLoadFromFile(string path){
m_Tex =newTexture2D(1,1);
m_Tex.LoadImage(ReadPNG(path));//读取图片字节流}privatebyte[]ReadPNG(string path){FileStream fileStream =newFileStream(path, FileMode.Open, System.IO.FileAccess.Read);
fileStream.Seek(0, SeekOrigin.Begin);byte[] binary =newbyte[fileStream.Length];//创建文件长度的buffer
fileStream.Read(binary,0,(int)fileStream.Length);
fileStream.Close();
fileStream.Dispose();
fileStream =null;return binary;}}
👥 总结
- 本文借助百度AI开放平台实现了一个简单的人脸识别工程。
- 文章内容看起来比较多,实际上需要操作的流程很简单,若有文章介绍不仔细的地方也可以直接在官方文档查看明细。
- 后续有机会还会更新一些AI相关的实战类文章,该专栏后面会慢慢涨价📈的,喜欢的小伙伴记得早点订阅该专栏Unity 实战100例 教程⭐️
- 那本篇文章到此结束啦,记得点赞收藏不迷路哦!
版权归原作者 呆呆敲代码的小Y 所有, 如有侵权,请联系我们删除。