基於百度AI使用H5實現呼叫攝像頭進行人臉註冊、人臉搜尋功能(Java)
阿新 • • 發佈:2019-01-04
人臉註冊、人臉搜尋使用百度AI介面。不支援H5活體檢測(需要活體檢測請參考百度AI-H5活體檢測)
前期準備工作
1.http://ai.ai/ 註冊賬戶 實名認證 建立人臉應用 儲存APPID、APIKEY、SECRETKEY 三個值備用
2.需要必須的Java經驗(最好是會用SpringBoot、Maven)
3.https://trackingjs.com/ 瞭解一下trackingjs(進行視訊中的人臉檢測。更多功能自行閱讀文件)
4.專案原始碼地址:https://gitee.com/xshuai/faceRecognition
簡易流程圖
示例圖(先看下效果)
使用者名稱為空提示
百度AI人臉註冊需要userid groupid 演示功能 直接寫固定的值 userid是UUID生成的一個字串。大家根據實際情況更改即可
圖片不包含人臉
確保圖片中包含人臉即可。未做活體檢測。活體檢測請參考百度AI官方文件的H5活體檢測
人臉註冊成功
人臉搜尋
trackingjs提供人臉檢測功能。需要完整面部 缺少下顎也是不行的。搜尋是使用百度AI介面。成功搜尋返回註冊給的使用者名稱稱
無需使用者主動拍照。只要攝像頭中包含完整面部即可。同樣也不支援活體檢測
搭建SpringBoot專案
專案地址 https://gitee.com/xshuai/faceRecognition
pom配置相關庫
百度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>
application.yml配置
server:
port: 8888
#只簡單配置了專案啟動埠
FaceManagerController(人臉註冊、搜尋)
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(facePageResponse.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) {
context.clearRect(0, 0, canvas.width, canvas.height);
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>