百度智能云
1、先去百度智能云注册一个百度智能云账号
2、创建人脸识别应用
进入页面后,在侧边栏选择人脸识别,在应用列表中创建一个新的应用,填写【应用名称】和【应用描述】,其他的使用默认值就可以了
3、获取秘钥
应用创建成功后,记录下自己的API Key、Secret Key
koa 后端
1.app.ts配置跨域和引入koa
import Koa from 'koa';
import Cors from 'koa2-cors';
import { corsHandler } from './middleware/cors';
import koaBody from 'koa-body';
import router from './router/packaging/index';
const app = new Koa();
// 处理静态资源
// app.use(Static(path.join(__dirname,'./public/img')));
// 跨域请求
// console.log(router);
app.use(Cors(corsHandler));
app.use(koaBody());
// 传递到 中间件里面
app.use(router.routes()).use(router.allowedMethods());
const PORT = 4001;
app.listen(PORT,()=>{
console.log(`http://localhost:${PORT},已启动`);
});
2.获取Access Token的接口
// 人脸识别 获取Acess Token
export const getToken = async (ctx: any) => {
console.log('----我是人脸识别接口');
const param = qs.stringify({
'grant_type': 'client_credentials',
'client_id': '百度云应用id',
'client_secret': '百度云应用秘钥'
});
const axs = await axios.post('https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=iZnI34PU6myzxi1sDYQrI6Fp&client_secret=uWL8ufxX8bz2Zus2r60tlQUXBsu9PtdG&', param);
// console.log(axs);
ctx.body = axs.data;
};
3.人脸比对
export const checkFace = async (ctx: any) => {
// console.log(ctx.request.body);
// 请求接口
const url = 'https://aip.baidubce.com/rest/2.0/face/v3/match?access_token=' + ctx.request.body.access_token;
// 请求的图片数据
console.log('woshi');
// 请求数据
// const data = {
// image_type: 'BASE64',
// image: ctx.request.body.img,
// // group_id_list: 'test_add', // 之前注册人脸管理库的名字
// // liveness_control: 'HIGH' // 活体监测
// };
const dir = path.join(__dirname, ctx.request.body.urls[0].urls);
console.log(dir);
const base64 = fs.readFileSync(dir, 'base64'); // 文件流并转 base64
console.log();
const data = [
{
"image": ctx.request.body.img,
"image_type": "BASE64",
"face_type": "LIVE",
"quality_control": "LOW",
"liveness_control": "HIGH"
},
{
"image": base64,//要比对的照片
"image_type": "BASE64",
"face_type": "LIVE",
"quality_control": "LOW",
"liveness_control": "HIGH"
},
];
const sxs = await axios({
method: "POST",
// headers: { "Content-Type": "application/x-www-form-urlencoded" },
url: url,
data: data,
});
ctx.body = sxs.data;
console.log(sxs.data);
};
前端部分
完整代码
1.主要页面
<template>
<div class="box">
<div class="aut">
<h2>请将脸部对准识别框</h2>
<div class="user-icon">
<video
width="320"
height="240"
ref="videoDom"
id="video"
preload
autoplay
loop
muted
></video>
<canvas width="630" height="490" ref="canvasDOM"></canvas>
</div>
<div>{{ loding }}</div>
<el-button class="button" type="warning" @click="initTracker"
>去考试</el-button
>
<el-button type="primary" class="button1" @click="fan"
>返回登录</el-button
>
<div class="shenfen">
<!-- <img src="require('@')" alt=""> -->
<p>姓名:{{ Routerdata.username }}<br /></p>
<p>电话:{{ Routerdata.phone }}<br /></p>
<p>班级:{{ Routerdata.ClassA }}<br /></p>
<p>考生号:{{ Routerdata.candidate }}</p>
</div>
</div>
<div class="soild_text_one">
<fieldset>
<legend>注意事项</legend>
<p>1.不允许切屏、刷新页面,数量达到3次将会强制提交试卷</p>
<p>2.不允许交头接耳</p>
<p>3.遵守考场纪律</p>
</fieldset>
</div>
<!-- <Alert /> -->
</div>
</template>
<script>
import("tracking/build/tracking-min.js");
import("tracking/build/data/face-min.js");
import { getTopics, getToken, checkFace } from "../../api/gxf";
import { getApp, getTestListA } from "../../api/hjr";
import Alert from "./alert.vue";
import { timeToNum } from "../../utils/timechange";
// 嘴巴等特征,后期可添加
// import('tracking/build/data/mouth-min.js')
// import('tracking/build/data/eye-min.js')
// import('tracking/examples/assets/stats.min.js')
// var objects = new tracking.ObjectTracker(['face', 'eye', 'mouth']);
// console.log(objects)
export default {
components: {
// Alert,
},
name: "testTracking",
data() {
return {
// 记录拍照到了几次
count: 0,
isdetected: "请您保持脸部在画面中央",
loding: "",
access_token: "",
dialogVisible: false,
fullscreenLoading: false,
Routerdata: [],
datalist: [],
TestResultData:[],
AppData:[]
};
},
methods: {
// 初始化racker
initTracker() {
// alert('进来了')
// alert(navigator.mediaDevices)
// 启用摄像头,这一个是原生调用摄像头的功能,不写的话有时候谷歌浏览器调用摄像头会失败
navigator.mediaDevices
.getUserMedia({ video: true, audio: true })
.then(this.getMediaStreamSuccess)
.catch(this.getMediaStreamError);
this.context = this.canvas.getContext("2d");
// 初始化tracking参数
this.tracker = new tracking.ObjectTracker("face");
this.tracker.setInitialScale(4);
this.tracker.setStepSize(2);
this.tracker.setEdgesDensity(0.1);
this.tracker.on("track", (event) => {
this.onTracked(event);
});
// tracking启用摄像头,这里我选择调用原生的摄像头
// tracking.track(this.video, this.tracker, { camera: true });
// 如果是读取视频,可以用trackerTask.stop trackerTask.run来暂停、开始视频
this.trackerTask = tracking.track(this.video, this.tracker);
},
// 监听中
onTracked(event) {
// 判断终止条件, stop是异步的,不返回的话,还会一直截图
if (this.count >= 21) {
this.onStopTracking();
return;
}
// 画框框
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
event.data.forEach((rect) => {
this.context.lineWidth = 1;
this.context.strokeStyle = "#a64ceb";
//'#a64ceb';
this.context.strokeRect(rect.x, rect.y, rect.width, rect.height);
this.context.font = "11px Helvetica";
this.context.fillStyle = "#fff";
// 截图
if (event.data.length > 0 && this.count <= 20) {
if (this.count < 0) {
this.count = 0;
}
this.count += 1;
if (this.count > 20) {
this.isdetected = "已检测到人脸,正在识别";
this.getPhoto();
}
} else {
this.count -= 1;
if (this.count < 0) {
this.isdetected = "请您保持脸部在画面中央";
}
}
});
// 视频中心展示文字
this.context.fillText(this.isdetected, 100, 30);
},
// 停止监听
onStopTracking() {
this.trackerTask.stop();
this.video.pause();
// 关闭摄像头
this.video.srcObject = null;
window.stream.getTracks().forEach((track) => track.stop());
},
// 获取人脸照片
getPhoto() {
console.log(this.isdetected);
this.isdetected = "";
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
let video = document.getElementById("video");
this.context.drawImage(
video,
0,
0,
this.canvas.width,
this.canvas.height
);
let dataUrl = this.canvas.toDataURL("image/jpeg", 1);
// console.log(dataUrl)
this.imgbase64 = dataUrl.replace(/^data:image\/\w+;base64,/, "");
// 开始人脸识别
this.postFace();
},
// 初始化调用Token
getToken() {
getToken().then((res) => {
this.access_token = res.access_token;
console.log(res);
console.log(this.access_token);
});
},
// 人脸验证
postFace() {
const loading = this.$loading({
lock: true,
text: "正在识别中,请稍后................",
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.7)",
});
setTimeout(() => {
loading.close();
}, 2000);
checkFace({
access_token: this.access_token,
img: this.imgbase64,
urls: this.datalist,
}).then((res) => {
console.log(res);
this.loding = "";
if (res.error_code !== 0) {
if (res.error_code == 223120) {
this.video.srcObject = null;
window.stream.getTracks().forEach((track) => track.stop());
this.$message({
message: "检测失败,请从新检测",
type: "warning",
});
this.count = 0;
this.onStopTracking();
}
} else {
if (res.result.score > 80) {
this.$message({
message: "人脸识别成功,3秒后跳转",
type: "success",
});
setTimeout(() => {
localStorage.setItem("wxToken", "1");
this.$router.push({
path: "/",
query: this.Routerdata,
});
}, 3000);
} else {
this.$message({
message: "人脸识别失败,未找到",
type: "warning",
});
this.count = 0;
this.onStopTracking();
}
}
});
// this.$axios
// .post("http://192.168.50.35:3000/checkFace", {})
// .then((res) => {
// });
},
// openFullScreen2() {
// },
// 视频流启动
getMediaStreamSuccess(stream) {
window.stream = stream;
this.video.srcObject = stream;
},
// 视频媒体流失败
getMediaStreamError(error) {
alert("视频媒体流获取错误" + error);
},
fan() {
this.$router.push("/login");
},
},
mounted() {
this.dialogVisible = true;
this.video = this.$refs.videoDom;
this.canvas = this.$refs.canvasDOM;
window.addEventListener("beforeunload", localStorage.setItem('leaves',0), false);
//初始化获取tonken
this.getToken();
let url = this.$route.fullPath;
// const {username,classA,phone,candidate} = this.$route.query;
this.Routerdata = this.$route.query;
getApp({ a: 1, b: 2 }).then((res) => {
let a = res.filter((item, index) => {
return this.Routerdata.phone === item.phone;
});
// console.log(a);
this.datalist = a;
});
getTestListA().then((TestResult) => {
this.TestResultData = TestResult
});
getApp().then((AppResult)=>{
this.AppData = AppResult
})
},
destroyed() {},
};
</script>
<style scoped>
.soild_text_one {
width: 100%;
margin: 0 auto;
}
fieldset {
height: 500px;
border-left: none;
border-right: none;
border-bottom: none;
color: gray;
border-color: #e7f8f7f8;
height: 20px;
margin-top: 60px;
}
legend {
text-align: center;
padding: 0 10px;
font-size: 18px;
}
.aut {
width: 70%;
height: 651px;
margin: 0 auto;
}
.box {
width: 100%;
height: 850px;
}
h2 {
font-family: "宋体";
font-weight: bold;
text-align: center;
}
.shenfen {
width: 300px;
height: 300px;
border: 1px solid rgb(235, 223, 223);
padding: 20px;
margin-left: 57px;
margin-top: 30px;
}
.user-icon {
position: relative;
margin: 0 auto;
margin-top: 10px;
width: 890px;
height: 489px;
background: #000;
float: right;
}
.button1 {
width: 300px;
height: 50px;
line-height: 50px;
margin: 0 auto;
float: left;
font-size: 16px;
position: absolute;
position: absolute;
left: 70%;
top: 630px; /*参照物是父容器*/
transform: translate(-50%, -50%); /*百分比的参照物是自身*/
}
.button {
width: 300px;
height: 50px;
line-height: 50px;
margin: 0 auto;
float: left;
font-size: 16px;
position: absolute;
position: absolute;
left: 50%;
top: 630px; /*参照物是父容器*/
transform: translate(-50%, -50%); /*百分比的参照物是自身*/
}
video,
canvas {
width: 630px;
height: 100%;
position: absolute;
left: 50%;
top: 50%; /*参照物是父容器*/
transform: translate(-50%, -50%); /*百分比的参照物是自身*/
}
</style>
2.提示页面
<template>
<div class="divAlert"></div>
<!-- <el-button type="text" @click="">Click to open the Message Box</el-button> -->
</template>
<script lang="ts">
import {onMounted} from 'vue'
import { ElMessageBox, ElMessage } from 'element-plus'
import type { Action } from 'element-plus'
export default {
props: {},
setup(props) {
const open = () => {
ElMessageBox.alert("即将进行人脸识别", "提示", {
confirmButtonText: "OK",
callback: (action: Action) => {
},
});
};
onMounted(()=>{open()})
return {
open
};
},
};
</script>
<style>
</style>
3.axios请求封装
import axios from 'axios';
// import { message } from 'antd';
// const apiV1 = 'http://localhost:4001/';
// const apiV1 = 'http://192.168.5.104:5003/';
const apiV1='/api'
export const httpProvider = axios.create({
// baseURL:process.env.NODE_ENV === 'production'? apiV1+'/api/v1':'/api',
baseURL: apiV1,
timeout: 6000
});
// 拦截 : 请求拦截
httpProvider.interceptors.request.use(
(config: any) => {
const token = window.localStorage.getItem('token');
if (token) { // 有token,请求头里Authorization: Bearer "1"
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
() => {
throw new Error('发起请求出错');
}
);
httpProvider.interceptors.response.use(
(res) => {
return res.data;
},
(err) => {
if (err && err.response && err.response.status) {
const status = err.response.status;
switch (status) {
case 504:
case 500:
case 404:
// message.error('服务器异常');
break;
case 401:
// message.error('未授权');
break;
case 403:
// message.error('无权访问');
break;
case 422:
// message.error('参数出错');
break;
// case 400: // 请求出错
// message.error('未授权');
// break;
default:
// message.error('未知错误');
}
}
}
);
4.接口
import { httpProvider } from "../utils/request";
// 人脸识别 获取Acess Token
export function getToken(data:any):any{
console.log(data)
return httpProvider.request({
method:'POST',
url:'/getToken',
data
});
}
// 监测人脸
export function checkFace(data:any):any{
console.log(data)
return httpProvider.request({
method:'POST',
url:'/checkFace',
data
});
}
export function getTestListA(data:any):any{
return httpProvider.request({
method:'POST',
url:'/getTestListA',
data
});
}
export function getApp(data:any):any{
return httpProvider.request({
method:'POST',
url:'/getApp',
data
完整的代码中包含了,人脸识别认证后自动截图,自动关闭摄像头等功能