案例概述
本案例基於ASP.NET和百度雲人臉庫,主要實現靜態人臉添加和靜態人臉檢測的功能,是筆者一個練習的小Demojavascript
使用的工具
主要使用了VS 201七、MS SQL Server數據庫和百度雲人臉庫css
實現的功能
功能及代碼展現
1.打開瀏覽器登陸百度智能雲,(百度帳號便可登陸)
2.應用列表|建立應用
3.人臉庫管理|選擇剛剛建立好的應用
4.在這個應用中建立新分組(這個分組將在以後上傳圖片信息中用到)
html
1.AccessToken.cs前端
主要功能:將建立人臉庫時獲取的API Key和Sercet Key,放入json字符串中傳給百度雲人臉識別接口,與本身建立的人臉庫創建鏈接,並獲取鏈接憑證。
返回回來的json字符串中含有的Access_Token就是這個憑證。java
這個類不是筆者寫的,是百度雲提供的api調用方式文檔(點此訪問),在這個文檔的基礎上,筆者進行了一些修改,造成了下面的類。jquery
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.csweb
主要功能:在人臉庫中新建人臉,並設置這我的臉的編號和分組,這個類也是基於百度雲的開發文檔chrome
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, 0, 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格式的人臉圖片信息和人臉庫中已有的人臉進行對比,匹配的編號和匹配程度(百分制),參考百度雲人臉搜索。json
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, String> dic = new Dictionary<string, string>(); dic.Add("image", 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, 0, 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; } } }
主類其實就是上面三個類,可是爲了方便從上面三個類返回的json字符串中取值和判斷,筆者又添加了兩個類
4.SearchReturn.cs
主要功能:實現json的反序列化,這個類文件中的幾個類定義了一個數據類型,用於存放FaceSearch返回的json字符串轉換成的變量。
其關係是 SearchReturn>Result>User_List
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的Video標籤
和Canvas標籤
,原理是將前置攝像頭的視頻內容放到video
中顯示,而後經過點擊按鈕獲取點擊時刻的video
截圖,將圖片信息放入canvas
中保存,而且將圖片內容編碼爲Base64再經過Hiddenfield
控件傳給後端,實現後端對圖片信息的獲取。
前端代碼
/*<%@ 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, success, error); } else if (navigator.mozGetUserMedia) { // Firefox瀏覽器 navigator.mozGetUserMedia(constraints, success, error); } else if (navigator.getUserMedia) { // 舊版API navigator.getUserMedia(constraints, success, 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 } }, success, error); } else { alert('您的瀏覽器不支持訪問用戶媒體設備!'); } // 綁定拍照按鈕的點擊事件 document.getElementById("capture").addEventListener("click", function () { context.drawImage(video, 0, 0, 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", SqlDbType.VarChar, 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", SqlDbType.NVarChar, 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, 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=""></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, success, error); } else if (navigator.mozGetUserMedia) { // Firefox瀏覽器 navigator.mozGetUserMedia(constraints, success, error); } else if (navigator.getUserMedia) { // 舊版API navigator.getUserMedia(constraints, success, 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 } }, success, error); } else { alert('您的瀏覽器不支持訪問用戶媒體設備!'); } // 綁定拍照按鈕的點擊事件 document.getElementById("capture").addEventListener("click", function () { context.drawImage(video, 0, 0, 480, 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,")) { 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,", ""); } //獲取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,若有錯誤或者不當之處還請各位大佬斧正。
轉載請註明原文連接。