人脸注册、人脸搜索使用百度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>