人臉註冊、人臉搜索使用百度AI接口。不支持H5活體檢測(須要活體檢測請參考百度AI-H5活體檢測)
體驗地址(人臉註冊) http://123.207.12.111:32095/storage
體驗地址(人臉搜索) http://123.207.12.111:32095/javascript只是爲了演示。因此是IP。最好用火狐瀏覽器訪問。谷歌提示異常做者就不專門修改了。你們能夠直接下載源碼運行體驗的css
1.http://ai.ai/ 註冊帳戶 實名認證 建立人臉應用 保存APPID、APIKEY、SECRETKEY 三個值備用html
2.須要必須的Java經驗(最好是會用SpringBoot、Maven)java
3.https://trackingjs.com/ 瞭解一下trackingjs(進行視頻中的人臉檢測。更多功能自行閱讀文檔)jquery
4.項目源碼地址:https://gitee.com/xshuai/faceRecognitiongit
百度AI人臉註冊須要userid groupid 演示功能 直接寫固定的值 userid是UUID生成的一個字符串。你們根據實際狀況更改便可web
確保圖片中包含人臉便可。未作活體檢測。活體檢測請參考百度AI官方文檔的H5活體檢測ajax
trackingjs提供人臉檢測功能。須要完整面部 缺乏下顎也是不行的。搜索是使用百度AI接口。成功搜索返回註冊給的用戶名稱spring
無需用戶主動拍照。只要攝像頭中包含完整面部便可。一樣也不支持活體檢測apache
項目地址 https://gitee.com/xshuai/faceRecognition
百度SDK、fastjson、thymeleaf必不可少
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>cn.xsshome</groupId> <artifactId>faceRecognition</artifactId> <packaging>jar</packaging> <name>faceRecognition</name> <url>http://maven.apache.org</url> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <swagger.version>2.7.0</swagger.version> </properties> <dependencies> <!-- fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.35</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>springloaded</artifactId> <version>1.2.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <!-- SpringBoot 核心包 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- SpringBoot Web容器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- SpringBoot集成thymeleaf模板 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!-- 日誌版本 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- 百度AI SDK --> <dependency> <groupId>com.baidu.aip</groupId> <artifactId>java-sdk</artifactId> <version>4.10.0</version> </dependency> </dependencies> <!-- jar --> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> </configuration> </plugin> </plugins> </build> </project>
server: port: 8888 #只簡單配置了項目啓動端口
package cn.xsshome.controller; import java.util.HashMap; import java.util.UUID; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baidu.aip.face.AipFace; import cn.xsshome.common.FactoryUtil; import cn.xsshome.vo.FacePageBean; import cn.xsshome.vo.FacePageResponse; import cn.xsshome.vo.response.FaceSerachResponse; /** * 人臉照片註冊方法 * @author 小帥丶 * */ @Controller @RequestMapping("/facemanager") public class FaceManagerController { //人臉模塊對象 AipFace aipFace = FactoryUtil.getAipFace(); private static Logger log = LoggerFactory.getLogger(FaceManagerController.class); /** * 人臉註冊 * @param facePageBean 請求的參數對象 * @param request * @param response * @return */ @PostMapping("/add") @ResponseBody public String addFace(FacePageBean facePageBean,HttpServletRequest request, HttpServletResponse response){ log.info("發送過來的參數{}",JSONObject.toJSONString(facePageBean)); FacePageResponse facePageResponse = new FacePageResponse(); if(facePageBean.getUser_info().equals("")||null==facePageBean.getUser_info()){ facePageResponse.setError_code("100"); facePageResponse.setError_msg("用戶名稱爲空 請填寫後重試"); return JSON.toJSONString(facePageResponse); }else{ String groupId = "xsdemo";//記得替換成本身的或經過頁面傳遞用戶組id(由數字、字母、下劃線組成),長度限制128B String userId = UUID.randomUUID().toString().replace("-", "").toUpperCase();//用戶id(由數字、字母、下劃線組成),長度限制128B HashMap<String, String> options = new HashMap<String, String>(); options.put("user_info","小帥丶"); org.json.JSONObject resultObject = aipFace.addUser(facePageBean.getImgdata(), "BASE64", groupId, userId, options); log.info("註冊返回的數據{}",resultObject.toString(2)); return resultObject.toString(); } } /** * 人臉搜索 * @param facePageBean 請求的參數對象 * @param request * @param response * @return */ @PostMapping("/search") @ResponseBody public FacePageResponse searchFace(FacePageBean facePageBean,HttpServletRequest request, HttpServletResponse response){ FacePageResponse facePageResponse = new FacePageResponse(); log.info("發送過來的參數{}",JSONObject.toJSONString(facePageBean)); String groupIdList = "xsdemo";//用戶組id(由數字、字母、下劃線組成),長度限制128B org.json.JSONObject resultObject = aipFace.search(facePageBean.getImgdata(), "BASE64", groupIdList, null); //使用fastjson處理返回的內容 直接用javabean接收 方便取值 FaceSerachResponse faceSerachResponse = JSON.parseObject(resultObject.toString(), FaceSerachResponse.class); if("0".equals(faceSerachResponse.getError_code())&&"SUCCESS".equals(faceSerachResponse.getError_msg())){ if(faceSerachResponse.getResult().getUser_list().get(0).getScore()>80f){ facePageResponse.setError_code(faceSerachResponse.getError_code()); facePageResponse.setError_msg(faceSerachResponse.getError_msg()); facePageResponse.setUser_info(faceSerachResponse.getResult().getUser_list().get(0).getUser_info()); }else{ facePageResponse.setError_code("555"); facePageResponse.setError_msg("人臉搜索失敗,請重試或請先註冊"); } }else{ facePageResponse.setError_code("500"); facePageResponse.setError_msg(faceSerachResponse.getError_msg()); } log.info("搜索返回的數據{}",resultObject.toString(2)); return facePageResponse; } }
<!DOCTYPE html> <html lang="zh" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="../css/layer.css"> <link rel="stylesheet" href="../css/storage.css" /> <title>人臉註冊</title> <script type="text/javascript" src="../js/jquery-1.9.1.js"></script> <script type="text/javascript" src="../js/layer.js"></script> <style type="text/css"> body { background: url('../img/AI3.jpg') no-repeat; height: 100%; width: 100%; overflow: hidden; background-size: cover; } </style> </head> <body> <div class="storage"> <div class="text1"> <p>人臉註冊</p> </div> <div class="vid"> <video id="video" autoplay></video> </div> <div class="canv"> <canvas id="canvas"></canvas> </div> <div> <button id="snap" onclick="Shoot()">拍照</button> <span class='user_info'>用戶名稱:</span> <input type="text" name="user_info" id="user_info" placeholder="請輸入名稱"> <button id="download" onclick="download()">上傳</button> </div> </div> </body> <script type="text/javascript" th:inline="javascript"> /*<![CDATA[*/ var ctx = /*[[${#httpServletRequest.getScheme() + "://" + #httpServletRequest.getServerName() + ":" + #httpServletRequest.getServerPort() + #httpServletRequest.getContextPath()}]]*/; var aVideo = document.getElementById('video'); var aCanvas = document.getElementById('canvas'); navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; //獲取媒體對象(這裏指攝像頭) navigator.getUserMedia({ video: true }, gotStream, noStream); //參數1獲取用戶打開權限;參數二是一個回調函數,自動傳入視屏流,成功後調用,並傳一個視頻流對象,參數三打開失敗後調用,傳錯誤信息 function gotStream(stream) { // video.src = URL.createObjectURL(stream); // 老寫法 aVideo.srcObject = stream; aVideo.onerror = function() { stream.stop(); }; stream.onended = noStream; aVideo.onloadedmetadata = function() { console.info('攝像頭成功打開!'); }; } function noStream(err) { alert(err); } function Shoot() { var context = canvas.getContext('2d'); //把當前視頻幀內容渲染到畫布上 context.drawImage(aVideo, 0, 5, 320,160); } //將圖片下載到本地 function download() { var userInfo = $('#user_info').val(); var dom = document.createElement("a"); dom.href = this.canvas.toDataURL("image/png"); dom.download = new Date().getTime() + ".png"; dom.click(); //刪除字符串前的提示信息 "data:image/png;base64," var data = aCanvas.toDataURL(); var b64 = data.substring(22); var path = ctx+"/facemanager/add"; var name = new Date().getTime() + ".png"; var context = canvas.getContext('2d'); $.ajax({ type : 'post', dataType : 'json', url : path, data : { imgdata:b64, imgname:name, user_info:userInfo, }, success : function(result){ if(result.error_msg=='SUCCESS'){ layer.open({ title: '舒適提示', content: '人臉用戶註冊成功', yes: function(index, layero){ layer.close(index); //若是設定了yes回調,需進行手工關閉 } }); }else{ layer.open({ title: '舒適提示', content: "註冊失敗:"+result.error_msg, yes: function(index, layero){ //把畫布上的圖清空 context.clearRect(0, 5, 320,160); layer.close(index); //若是設定了yes回調,需進行手工關閉 } }); } } }) } </script> </html>
trackerTask.stop();爲防止人臉搜索接口調用中 屢次提交問題。
<!DOCTYPE html> <html lang="zh" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="utf-8"> <title>人臉識別</title> <link rel="stylesheet" href="../css/layer.css"> <link rel="stylesheet" href="../css/demo.css"> <script type="text/javascript" src="../js/jquery-1.9.1.js"></script> <script type="text/javascript" src="../js/layer.js"></script> <script src="../js/tracking-min.js"></script> <script src="../js/face-min.js"></script> <script src="../js/dat.gui.min.js"></script> <script src="../js/stats.min.js"></script> </head> <body> <div> <p align="center">請確保面部完整,未檢測到請靠近攝像頭</p> </div> <div class="demo-frame"> <div class="demo-container"> <div id="face1"> <video id="video" width="640" height="480" preload autoplay loop muted></video> <canvas id="canvas" width="640" height="480"></canvas> </div> </div> </div> <div id="face2"> <canvas id="canvas1"></canvas> </div> <script type="text/javascript" th:inline="javascript"> /*<![CDATA[*/ var ctx = /*[[${#httpServletRequest.getScheme() + "://" + #httpServletRequest.getServerName() + ":" + #httpServletRequest.getServerPort() + #httpServletRequest.getContextPath()}]]*/ window.onload = function() { var video = document.getElementById('video'); var canvas = document.getElementById('canvas'); var canvas1 = document.getElementById('canvas1'); var context = canvas.getContext('2d'); var tracker = new tracking.ObjectTracker('face'); tracker.setInitialScale(4); tracker.setStepSize(2); tracker.setEdgesDensity(0.1); tracking.track('#video', tracker, { camera: true }); tracker.on('track', function(event) { if(event.data.length===0){ console.info('無人臉'); context.clearRect(0, 0, canvas.width, canvas.height); }else{ event.data.forEach(function(rect) { context.strokeStyle = '#a64ceb'; context.strokeRect(rect.x, rect.y, rect.width, rect.height); context.font = '11px Helvetica'; context.fillStyle = "#fff"; context.fillText('x: ' + rect.x + 'px', rect.x + rect.width + 5, rect.y + 11); context.fillText('y: ' + rect.y + 'px', rect.x + rect.width + 5, rect.y + 22); Shoot(); }); } }); var gui = new dat.GUI(); gui.add(tracker, 'edgesDensity', 0.1, 0.5).step(0.01); gui.add(tracker, 'initialScale', 1.0, 10.0).step(0.1); gui.add(tracker, 'stepSize', 1, 5).step(0.1); function Shoot() { var trackerTask = tracking.track(video, tracker); var context = canvas1.getContext('2d'); //把當前視頻幀內容渲染到畫布上 context.drawImage(video, 0, 5, 320, 140); var dom = document.createElement("a"); dom.href = this.canvas.toDataURL("image/png"); dom.download = new Date().getTime() + ".png"; dom.click(); //刪除字符串前的提示信息 "data:image/png;base64," var data = canvas1.toDataURL(); var b64 = data.substring(22); var path = ctx+"/facemanager/search"; $.ajax({ type : 'post', dataType : 'json', url : path, data : { imgdata:b64 }, success : function(result){ if(result.error_code=='0'){ trackerTask.stop(); layer.open({ title: '舒適提示', content: '歡迎 '+result.user_info, yes: function(index, layero){ trackerTask.run(); layer.close(index); //若是設定了yes回調,需進行手工關閉 } }); }else{ trackerTask.stop(); layer.open({ title: '舒適提示', content: result.error_msg, yes: function(index, layero){ trackerTask.run(); layer.close(index); //若是設定了yes回調,需進行手工關閉 } }); } } }) } }; </script> </body> </html>