基于ASP.NET使用C#实现简单人脸识别功能
(博客园对Markdown的排版也太不友好了吧(小声逼逼))
本案例基于ASP.NET和百度云人脸库,主要实现静态人脸添加和静态人脸检测的功能,是笔者一个练习的小Demo
主要使用了VS 2017、MS SQL Server数据库和百度云人脸库
知识背景百度人脸库的创建1.打开浏览器登录百度智能云,(百度账号即可登录) 2.应用列表|创建应用 3.人脸库管理|选择刚刚创建好的应用 4.在这个应用中创建新分组(这个分组将在之后上传图片信息中用到) 本项目中用到的类1.AccessToken.cs 主要功能:将创建人脸库时获取的API Key和Sercet Key,放入json字符串中传给百度云人脸识别接口,与自己创建的人脸库建立连接,并获取连接凭证。 这个类不是笔者写的,是百度云提供的api调用方式文档(点此访问),在这个文档的基础上,笔者进行了一些修改,形成了下面的类。 using System; using System.Collections.Generic; using System.Net.Http; using System.Web.Script.Serialization; namespace com.baidu.ai { public static class AccessToken { // 调用getAccessToken()获取的 access_token建议根据expires_in 时间 设置缓存 // 返回token示例 public static String TOKEN = "24.adda70c11b9786206253ddb70affdc46.2592000.1493524354.282335-1234567"; // 百度云中开通对应服务应用的 API Key 建议开通应用的时候多选服务 private static String clientId = "*********"; // 百度云中开通对应服务应用的 Secret Key private static String clientSecret = "**********"; public static String getAccessToken() { String authHost = "https://aip.baidubce.com/oauth/2.0/token"; HttpClient client = new HttpClient(); List<KeyValuePair<String,String>> paraList = new List<KeyValuePair<string,string>>(); paraList.Add(new KeyValuePair<string,string>("grant_type","client_credentials")); paraList.Add(new KeyValuePair<string,string>("client_id",clientId)); paraList.Add(new KeyValuePair<string,string>("client_secret",clientSecret)); HttpResponseMessage response = client.PostAsync(authHost,new FormUrlEncodedContent(paraList)).Result; String result = response.Content.ReadAsStringAsync().Result; Console.WriteLine(result); //获取返回的字符串 //string test = AccessToken.getAccessToken(); //Response.Write(test + "<br/>"); //获取返回的Access_Token string Access_Token = ""; JavaScriptSerializer Jss = new JavaScriptSerializer(); Dictionary<string,object> DicText = (Dictionary<string,object>)Jss.DeserializeObject(result); //如果返回值中含有access_token,则将其值赋予Access_Token,不存在则说明获取失败。 if (!DicText.ContainsKey("access_token")) { Access_Token = "获取Access_Token失败"; } else { Access_Token = DicText["access_token"].ToString(); } //Session["Token"] = Access_Token; //Response.Write(Access_Token); return Access_Token; } } } 2.FaceAdd.cs 主要功能:在人脸库中新建人脸,并设置这个人脸的编号和分组,这个类也是基于百度云的开发文档 using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Text; using System.Web; using System.Web.Script.Serialization; namespace com.baidu.ai { public class FaceAdd { // 人脸注册 ///参数说明:token->之前获取的Access_Token,base64->图片数据,tel->人脸编号 public static string add(string token,string base64,string tel) { //string token = "[调用鉴权接口获取的token]"; string host = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add?access_token=" + token; Encoding encoding = Encoding.Default; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(host); request.Method = "post"; request.KeepAlive = true; //将数据写入json字符串中 Dictionary<String,String> dic = new Dictionary<string,string>(); dic.Add("image",base64); dic.Add("image_type","BASE64"); //人脸库里的分组名 dic.Add("group_id","Users"); //这个人脸的编号 dic.Add("user_id",tel); //图片质量检测,Low表示可以接受较低画质的人脸数据 dic.Add("quality_control","LOW"); //活体检测,这里只是一个小Demo,所以没有添加活体检测的功能 dic.Add("liveness_control","NONE"); JavaScriptSerializer js = new JavaScriptSerializer(); String str = js.Serialize(dic); byte[] buffer = encoding.GetBytes(str); request.ContentLength = buffer.Length; request.GetRequestStream().Write(buffer,buffer.Length); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); StreamReader reader = new StreamReader(response.GetResponseStream(),Encoding.Default); string result = reader.ReadToEnd(); Console.WriteLine("人脸注册:"); Console.WriteLine(result); return result; } } } 3.FaceSearch.cs 主要功能:将从前端获取的Base64格式的人脸图片信息和人脸库中已有的人脸进行对比,匹配的编号和匹配程度(百分制),参考百度云人脸搜索。 using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Text; using System.Web; using System.Web.Script.Serialization; namespace com.baidu.ai { public class FaceSearch { // 人脸搜索 public static string Search(string token,string strbase64) { //服务器地址,Access_Token作为凭证 string host = "https://aip.baidubce.com/rest/2.0/face/v3/search?access_token=" + token; Encoding encoding = Encoding.Default; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(host); request.Method = "post"; request.KeepAlive = true; //序列化,生成json字符串 Dictionary<String,strbase64); dic.Add("image_type","BASE64"); dic.Add("group_id_list","Users"); dic.Add("quality_control","LOW"); dic.Add("liveness_control","NONE"); JavaScriptSerializer js = new JavaScriptSerializer(); String str = js.Serialize(dic); byte[] buffer = encoding.GetBytes(str); request.ContentLength = buffer.Length; request.GetRequestStream().Write(buffer,Encoding.Default); string result = reader.ReadToEnd(); Console.WriteLine("人脸搜索:"); Console.WriteLine(result); return result; } } } 主类其实就是上面三个类,但是为了方便从上面三个类返回的json字符串中取值和判断,笔者又添加了两个类 4.SearchReturn.cs 主要功能:实现json的反序列化,这个类文件中的几个类定义了一个数据类型,用于存放FaceSearch返回的json字符串转换成的变量。 using System; using System.Collections.Generic; using System.Linq; using System.Web; /// <summary> /// SearchReturn 的摘要说明 /// </summary> namespace com.baidu.ai { public class SearchReturn { public int error_code { get; set; } public string error_msg { get; set; } public long log_id { get; set; } public int timestamp { get; set; } public int cached { get; set; } public Result result { get; set; } } public class Result { public string face_token { get; set; } public User_List[] user_list { get; set; } } public class User_List { public string group_id { get; set; } public string user_id { get; set; } public string user_info { get; set; } public float score { get; set; } } } 5.ReturnResultDetect.cs 主要功能:基于FaceAdd和FaceSearch返回的json字符串,获取相应的值并返回相应的标记以帮助业务代码的实现。 (*需要在Nuget中添加Newtonsoft包) using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Script.Serialization; using Newtonsoft.Json.Linq; using com.baidu.ai; using Newtonsoft.Json; /// <summary> /// ReturnResultDetect 的摘要说明 /// </summary> namespace com.baidu.ai { public static class ReturnResultDetect { public static int GetFaceAddReturnResult(string strjson) { int BackResult = 0; SearchReturn feedback = JsonConvert.DeserializeObject<SearchReturn>(strjson); if (feedback.result==null) { BackResult = 0; } else { BackResult = 1; } return BackResult; } public static string GetFaceSearchReturnResult(string strjson) { string BackResult =""; int score = 0; //将收到的json字符串转化成SearchReturn类型的变量,即反序列化 SearchReturn feedback = JsonConvert.DeserializeObject<SearchReturn>(strjson); if (feedback.result==null) { BackResult = "_0"; //未检测到人脸 } else { score = Convert.ToInt32(feedback.result.user_list[0].score); if (score<80) { BackResult = "_1"; //人脸不匹配 } else { BackResult = feedback.result.user_list[0].user_id; } } return BackResult; } } } 人脸注册人脸注册的图像获取主要是通过HTML5的 前端代码 /*<%@ Page Language="C#" AutoEventWireup="true" CodeFile="User_Face_Signup.aspx.cs" Inherits="User_Face_Signup" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta charset='UTF-8' /> <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <title>人脸注册</title> <meta name="renderer" content="webkit"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width,user-scalable=yes,minimum-scale=0.4,initial-scale=0.8,target-densitydpi=low-dpi" /> <link rel="stylesheet" href="./css/font.css"> <link rel="stylesheet" href="./css/xadmin.css"> <script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script> <script type="text/javascript" src="./lib/layui/layui.js" charset="utf-8"></script> <script type="text/javascript" src="./js/xadmin.js"></script> <script type="text/javascript" src="./js/cookie.js"></script> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <form id="form1" runat="server"> <div> <div> <%--<div></div>--%> <div style="margin-top: 80px; margin-left: 20%; width: 30%; padding: 10px" class="layui-bg-green">人脸注册</div> <div style="margin-left: 20%; margin-top: 20px"> <video id="video" autoplay="" style="width: 70%;"></video> </div> <div style="margin-top: 10px; margin-left: 20%; width: 70%"> <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label> </div> <div style="margin-top: 10px; margin-left: 20%; width: 30%"> <asp:Button ID="capture" runat="server" Text="提交并注册" OnClick="capture_Click" class="layui-btn" /> </div> <%--<div style="margin-left: 20%; width: 70%"> <span style="color: #f00; font-size: smaller"> <asp:Label ID="Label1" runat="server" Text=""></asp:Label> </span> </div>--%> </div> </div>*/ <!-- 显示MediaStream视频流 --> <div> <asp:HiddenField ID="HiddenField1" runat="server" /> </div> <div style="display: none"> <canvas id="canvas" width="480" height="320"></canvas> </div> <script type="text/javascript"> // 访问用户媒体设备的兼容方法 function getUserMedia(constraints,success,error) { if (navigator.mediaDevices.getUserMedia) { // 最新的标准API navigator.mediaDevices.getUserMedia(constraints) .then(success).catch(error); } else if (navigator.webkitGetUserMedia) { // Webkit核心浏览器 navigator.webkitGetUserMedia(constraints,error); } else if (navigator.mozGetUserMedia) { // Firefox浏览器 navigator.mozGetUserMedia(constraints,error); } else if (navigator.getUserMedia) { // 旧版API navigator.getUserMedia(constraints,error); } } var video = document.getElementById("video");// video元素 var canvas = document.getElementById("canvas");// canvas元素 var context = canvas.getContext("2d"); // 成功的回调函数 function success(stream) { var CompatibleURL = window.URL || window.webkitURL video.src = CompatibleURL.createObjectURL(stream);//将视频流设置为video元素的源 video.play();// 播放视频 } // 异常的回调函数 function error(error) { console.log('访问用户媒体设备失败:',error.name,error.message); } if (navigator.mediaDevices.getUserMedia || navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia) { // 调用用户媒体设备,访问摄像头 getUserMedia({ video: { width: 480,height: 320 } },error); } else { alert('您的浏览器不支持访问用户媒体设备!'); } // 绑定拍照按钮的点击事件 document.getElementById("capture").addEventListener("click",function () { context.drawImage(video,480,320); // 将video画面在canvas上绘制出来 var data = canvas.toDataURL('image/png',1); //将当前显示的图像传到Base64编码的字符串里 document.getElementById('HiddenField1').value = data; //将上面转换好的Base64编码传到C#的HiddenField里,方便后端取值 }); </script> </form> </body> </html> 后端代码 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using com.baidu.ai; using System.Data; using System.Data.Sql; using System.Data.SqlClient; public partial class User_Face_Signup : System.Web.UI.Page { protected void Page_Load(object sender,EventArgs e) { Label1.Text= "<span style='color: #c2c2c2; font-size: x-small'>**请在光线充足的地方录入人脸以提高刷脸登录准确度!**<br />**准备好后点击下方按钮即可录入人脸!**</ span > "; } protected void capture_Click(object sender,EventArgs e) { //下面几个从session传过来的值是笔者这个项目里前一个页面的值,可以不看,但是为了保证程序完整性笔者还是将其放了上来 string name = Session["UserName"].ToString(); string tel = Session["UserTel"].ToString(); string password = Session["UserPass"].ToString(); string email = Session["UserMail"].ToString(); string PreBase64 = HiddenField1.Value; string Base64 = ""; //兼容各种不同的图片格式 if (PreBase64.Contains("data:image/png;base64,")) { Base64 = PreBase64.Replace("data:image/png;base64,",""); } if(PreBase64.Contains("data:image/jpg; base64,")) { Base64 = PreBase64.Replace("data:image/jpg;base64,""); } if (PreBase64.Contains("data:image/jpeg; base64,")) { Base64 = PreBase64.Replace("data:image/jpeg;base64,""); } //调用类AccessToken中的getAccessToken方法,获取返回值Access_Token //注:Access_Token其实每次取值都可以保留一段时间,但是为了减少不必要的麻烦,笔者这里还是每次都获取新的Access_Token,代价是每次都要多连接一次人脸库,浪费时间 string Access_Token = AccessToken.getAccessToken(); //将图片信息和对应人脸编号传入,上传到服务器 string Face_Add_Return = FaceAdd.add(Access_Token,Base64,tel); //获取人脸添加的返回值,1表示添加成功,否则为失败 int Face_Add_Result = ReturnResultDetect.GetFaceAddReturnResult(Face_Add_Return); if (Face_Add_Result==1) { SqlConnection conn = new SqlConnection(); conn.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionStringProManage"].ConnectionString; try { conn.Open(); string SQL = "insert into Users (uername,password,usertype,name,tel,email) values (@tel,@password,2,@name,@tel,@email)"; SqlCommand cmd = new SqlCommand(); cmd.Connection = conn; cmd.CommandType = CommandType.Text; cmd.CommandText = SQL; //依次添加每个字段的值 SqlParameter ptel = new SqlParameter("@tel",SqlDbType.VarChar,11); ptel.Value = tel; cmd.Parameters.Add(ptel); SqlParameter ppassword = new SqlParameter("@password",20); ppassword.Value = password; cmd.Parameters.Add(ppassword); SqlParameter pname = new SqlParameter("@name",SqlDbType.NVarChar,10); pname.Value = name; cmd.Parameters.Add(pname); SqlParameter pemail = new SqlParameter("@email",30); pemail.Value = email; cmd.Parameters.Add(pemail); int R = cmd.ExecuteNonQuery(); //R 的值就是返回影响表的行数 if (R > 0) { Session["ReturnPath"] = "Move_login.aspx"; Session["Message"] = "恭喜,注册成功!"; Response.Redirect("Success.aspx"); } else { Session["Message"] = "插入失败,请检查您的操作!"; Response.Redirect("Error.aspx"); } //Session["ReturnPath"] = "Admin_Add.aspx"; //Response.Redirect("Mid.aspx"); } finally { conn.Close(); } } else { Label1.Text = "<span style='color: #f00; font-size: smaller'>**未检测到人脸,请重试!**</span> "; } } } 人脸搜索人脸搜索和人脸注册的实现方式是类似的,只不过一个是写(注册),一个是读(搜索)。注册是把人脸信息录入人脸库,并给其分配一个唯一标识号——人脸编号,而搜索就是一个相反的过程,通过上传的人脸与数据库中的人脸对比,返回这个人脸编号和相似度。 前端代码 <%--和人脸注册的代码基本一致--> <%@ Page Language="C#" AutoEventWireup="true" CodeFile="User_Face_Login.aspx.cs" Inherits="User_Face_Login" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta charset='UTF-8' /> <meta name="viewport" content="width=device-width,user-scalable=no"/> <title>刷脸登录</title> <meta name="renderer" content="webkit"/> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/> <meta name="viewport" content="width=device-width,target-densitydpi=low-dpi" /> <link rel="stylesheet" href="./css/font.css"/> <link rel="stylesheet" href="./css/xadmin.css"/> <script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script> <script type="text/javascript" src="./lib/layui/layui.js" charset="utf-8"></script> <script type="text/javascript" src="./js/xadmin.js"></script> <script type="text/javascript" src="./js/cookie.js"></script> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <form id="form1" runat="server"> <div> <div> <%--<div></div>--%> <div style="margin-top: 80px; margin-left: 20%; width: 30%; padding: 10px" class="layui-bg-green">刷脸登录</div> <div style="margin-left: 20%; margin-top: 20px"> <video id="video" autoplay="" style="width: 70%;"></video> </div> <div style="margin-top: 10px; margin-left: 20%; width: 70%"> <asp:Label ID="Label1" runat="server" Text=""></asp:Label> </div> <div style="margin-top: 10px; margin-left: 20%; width: 30%"> <asp:Button ID="capture" runat="server" Text="登录" OnClick="capture_Click" class="layui-btn" /> </div> <%--<div style="margin-left: 20%; width: 70%"> <span style="color: #f00; font-size: smaller"> <asp:Label ID="Label1" runat="server" Text=""></asp:Label> </span> </div>--%> </div> </div> <!-- 显示MediaStream视频流 --> <div> <asp:HiddenField ID="HiddenField1" runat="server" /> </div> <div style="display: none"> <canvas id="canvas" width="480" height="320"></canvas> </div> <script type="text/javascript"> // 访问用户媒体设备的兼容方法 function getUserMedia(constraints,320);// 将video画面在canvas上绘制出来 var data = canvas.toDataURL('image/png',1); document.getElementById('HiddenField1').value = data; }); </script> </form> </body> </html> 后端代码 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using com.baidu.ai; public partial class User_Face_Login : System.Web.UI.Page { protected void Page_Load(object sender,EventArgs e) { Label1.Text = "<span style='color: #c2c2c2; font-size: x-small'>**请保持环境光线充足以提高刷脸登录准确度!**<br />**准备好后点击下方按钮即可登录!**</ span > "; } protected void capture_Click(object sender,EventArgs e) { //与上面类似的,获取前端传过来的Base64格式的图片编码 string PreBase64 = HiddenField1.Value; string Base64 = ""; if (PreBase64.Contains("data:image/png;base64,""); } if (PreBase64.Contains("data:image/jpg; base64,""); } //获取Access_Token,同上 string Access_Token = AccessToken.getAccessToken(); //获取返回的json字符串 string feedback = FaceSearch.Search(Access_Token,Base64); //从返回的字符串中取值,并根据值给出相应的判断 string backid = ReturnResultDetect.GetFaceSearchReturnResult(feedback); if (backid=="_0") { Label1.Text = "<span style='color: #f00; font-size: smaller'>**未检测到人脸,请重试!**</span> "; } else if (backid == "_1") { Label1.Text = "<span style='color: #f00; font-size: smaller'>**您尚未注册,请注册后登录**</span> "; Response.Redirect("Faca_Login_error.aspx"); } else { Session["Move_Name"] = backid; Session["Move_Islogin"] = 2; Response.Redirect("Move_User.aspx"); } } } 本文是小弟在学习过程中做的一个小Demo,如有错误或者不当之处还请各位大佬斧正。 转载请注明原文链接。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- .net – Textboxfor mvc3日期格式和日期验证
- ASP.NET MVC学习之NuGet在VS中的运用浅谈
- asp.net-mvc – 使用401发送消息:Asp.net Web-api
- asp.net-mvc – 由于对输入文本框进行过滤而导致绑定列表更
- asp.net – 如何维护具有大量分支的SQL Server DB
- asp.net – Web Farm上的Forms Authentication 4.0
- Asp.NET Core+ABP框架+IdentityServer4+MySQL+Ext JS之验证
- 如何在ASP.NET MVC中使用JQuery调用控制器操作
- asp.net – 模型绑定与禁用文本框
- 谈谈分布式事务之三: System.Transactions事务详解[上篇]