我这里使用的是百度云的人脸库,没有的可以申请一下
直接上代码实例
我是在若依集成的人脸识别登录
这里先添加人脸 具体参数可以去看一下
配置文件
package com.shopgoods.auth.config;
import com.baidu.aip.face.AipFace;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
*@Author:FengZekun
*@Description:
*@name:Buida
*@Date:2024/11/24 19:40
*/
@Component
public class BaiduFaceApi {
@Value("${baidu.face.appId}")
public String APP_ID;
@Value("${baidu.face.apiKey}")
public String API_KEY;
@Value("${baidu.face.secretKey}")
public String SECRET_KEY;
public AipFace getAipFace() {
// 初始化一个AipFace
return new AipFace(APP_ID, API_KEY, SECRET_KEY);
}
}
@RequestMapping("/face")
@RestController
@CrossOrigin
public class FaceController {
@Autowired
private BaiduFaceApi baiduFaceApi;
@Autowired
private SysLoginService sysLoginService;
/**
* 人脸识别用户信息
**/
@PostMapping("/faceLogin")
@ResponseBody
public Result<SysUser> faceLogin(@RequestParam("file") MultipartFile file) {
SysUser userInfo = sysLoginService.faceLogin(file);
return Result.success(userInfo);
}
/**
* 人脸信息注册
**/
@PostMapping("/registerFace")
@ResponseBody
public Result registered(@RequestParam("file") MultipartFile file,
@RequestParam("id") String id) {
// 传入可选参数调用接口
HashMap<String, String> options = new HashMap<>();
options.put("user_info", "user's info");
options.put("quality_control", "NORMAL");
options.put("liveness_control", "NONE");
options.put("action_type", "REPLACE");
String image = sysLoginService.getImages(file);
String imageType = "BASE64";
String groupId = "demo";
String userId = id;
// 人脸注册
JSONObject res = baiduFaceApi.getAipFace().addUser(image, imageType, groupId, userId, options);
System.out.println(res);
System.out.println(res.toString(2));
return Result.success(res.get("result").toString());
}
这是人脸登录接口
import request from '@/utils/request'
/**
* 人脸识别返回用户信息
* @param formData
* @returns {*}
*/
export function faceLogin(formData) {
return request({
url: '/auth/face/faceLogin',
method: 'post',
data: formData,
headers: { //设置上传请求头
'Content-Type': 'multipart/form-data'
},
})
}
/**
*
*人脸注册
*/
export function registered(formData, id) {
return request({
url: '/auth/face/registerFace',
method: 'post',
data: formData,
params: {
id
}
,
headers: { //设置上传请求头
'Content-Type': 'multipart/form-data'
},
})
}
人脸登录前端vue代码
<template>
<div id="bbb">
<router-view></router-view>
<h1>人脸登录</h1>
<video
id="videoCamera"
:width="videoWidth"
:height="videoHeight"
:x5-video-player-fullscreen="true"
autoplay
></video>
<canvas
style="display: none"
id="canvasCamera"
:width="videoWidth"
:height="videoHeight"
></canvas>
<br>
<el-button type="primary" plain @click="setImage()">手动拍照</el-button>
<!-- <p class="fail_tips"></p>
// 给外面盒子设置宽高,可以限制拍照图片的大小位置范围
<div class="result_img">
<img :src="imgSrc" alt class="tx_img" width="100%" height="100%" />
</div>
<p class="res_tips">效果展示</p> -->
</div>
</template>
<script>
import Cookies from 'js-cookie'
import { faceLogin } from '../api/face/face'
export default {
name: 'FaceIndex',
data() {
return {
// 视频调用相关数据开始
videoWidth: 500,
videoHeight: 400,
imgSrc: '',
thisCancas: null,
thisContext: null,
thisVideo: null,
openVideo: false,
//视频调用相关数据结束
postVideoImg: '',// 图片上传后获取的url链接,
loginForm: {
username: 'admin',
password: 'admin123',
rememberMe: false,
code: '',
uuid: '',
typeId: 1
}
}
},
mounted() {
// 第一步打开摄像头
this.getCompetence() //调用摄像头
},
methods: {
// 第三步、拍照图转换file格式上传,
// 第四步、获取图片url链接
async postImg() {
let formData = new FormData()
formData.append('file', this.base64ToFile(this.imgSrc, 'png'))
formData.append('flag', 'videoImg') // 额外参数
//使用axios对应的后台上传图片接口
let result = await faceLogin(formData)
console.log(result)
if (result.code == 200) {
this.loginForm.username = result.data.userName
this.$store.dispatch('Login', this.loginForm).then(() => {
this.$router.push({ path: this.redirect || '/' }).catch(() => {
})
})
} else {
this.$message({
message: '登录失败,图像不合格',
center: true,
type: 'error',
showClose: true
})
}
return false
},
// 调用权限(打开摄像头功能)
getCompetence() {
var _this = this
_this.thisCancas = document.getElementById('canvasCamera')
_this.thisContext = this.thisCancas.getContext('2d')
_this.thisVideo = document.getElementById('videoCamera')
_this.thisVideo.style.display = 'block'
// 获取媒体属性,旧版本浏览器可能不支持mediaDevices,我们首先设置一个空对象
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {}
}
// 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
// 使用getUserMedia,因为它会覆盖现有的属性。
// 这里,如果缺少getUserMedia属性,就添加它。
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function(constraints) {
// 首先获取现存的getUserMedia(如果存在)
var getUserMedia =
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.getUserMedia
// 有些浏览器不支持,会返回错误信息
// 保持接口一致
if (!getUserMedia) {
//不存在则报错
return Promise.reject(
new Error('getUserMedia is not implemented in this browser')
)
}
// 否则,使用Promise将调用包装到旧的navigator.getUserMedia
return new Promise(function(resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject)
})
}
}
var constraints = {
audio: false,
video: {
width: this.videoWidth,
height: this.videoHeight,
transform: 'scaleX(-1)'
}
}
navigator.mediaDevices
.getUserMedia(constraints)
.then(function(stream) {
// 旧的浏览器可能没有srcObject
if ('srcObject' in _this.thisVideo) {
_this.thisVideo.srcObject = stream
} else {
// 避免在新的浏览器中使用它,因为它正在被弃用。
_this.thisVideo.src = window.URL.createObjectURL(stream)
}
_this.thisVideo.onloadedmetadata = function(e) {
_this.thisVideo.play()
}
})
.catch((err) => {
console.log(err)
})
},
// 第二步、绘制图片(拍照功能)
setImage() {
var _this = this
// canvas画图
_this.thisContext.drawImage(_this.thisVideo, 0, 0)
// 获取图片base64链接
var image = this.thisCancas.toDataURL('image/png')
_this.imgSrc = image //赋值并预览图片
//这里是调用上传图片接口=====
this.postImg() // 绘制完图片调用图片上传接口
},
// 关闭摄像头
stopNavigator() {
this.thisVideo.srcObject.getTracks()[0].stop()
},
// base64 转为 file
base64ToFile(urlData, fileName) {
let arr = urlData.split(',')
let mime = arr[0].match(/:(.*?);/)[1]
let bytes = atob(arr[1]) // 解码base64
let n = bytes.length
let ia = new Uint8Array(n)
while (n--) {
ia[n] = bytes.charCodeAt(n)
}
return new File([ia], fileName, { type: mime })
}
},
destroyed: function() {
// 离开当前页面
this.stopNavigator() // 关闭摄像头
}
}
</script>
<style>
.result_img {
width: 226px;
height: 195px;
background: #d8d8d8;
}
#bbb {
width: 500px;
text-align: center;
margin: auto;
}
</style>
注册人脸前端代码
<template>
<div id="aaa">
<h1>人脸信息注册</h1>
<video
id="videoCamera"
:width="videoWidth"
:height="videoHeight"
:x5-video-player-fullscreen="true"
autoplay
></video>
<canvas
style="display: none"
id="canvasCamera"
:width="videoWidth"
:height="videoHeight"
></canvas>
<br>
<el-button type="primary" plain @click="setImage()">手动拍照</el-button>
<p class="fail_tips"></p>
<!-- <div class="result_img">
<img :src="imgSrc" alt class="tx_img" width="100%" height="100%" />
</div>
<p class="res_tips">效果展示</p> -->
</div>
</template>
<script>
import { registered } from '../../../api/face/face'
export default {
data() {
return {
id: localStorage.getItem("userId"),
// 视频调用相关数据开始
videoWidth: 500,
videoHeight: 400,
imgSrc: "",
thisCancas: null,
thisContext: null,
thisVideo: null,
openVideo: false,
//视频调用相关数据结束
postVideoImg: "", // 图片上传后获取的url链接
};
},
mounted() {
// 第一步打开摄像头
this.getCompetence(); //调用摄像头
},
methods: {
// 第三步、拍照图转换file格式上传,
// 第四步、获取图片url链接
async postImg() {
let formData = new FormData();
formData.append("file", this.base64ToFile(this.imgSrc, "png"));
formData.append("flag", "videoImg"); // 额外参数
//使用axios对应的后台上传图片接口
await registered(formData, this.id).then(result=>{
console.log(result.data);
if (result.data.data != "null") {
this.$message({
message: "上传成功",
type: "success",
center: true,
showClose: true,
});
} else {
this.$message({
message: "上传失败,图像不合格",
center: true,
type: "error",
showClose: true,
});
}
})
},
// 调用权限(打开摄像头功能)
getCompetence() {
var _this = this;
_this.thisCancas = document.getElementById("canvasCamera");
_this.thisContext = this.thisCancas.getContext("2d");
_this.thisVideo = document.getElementById("videoCamera");
_this.thisVideo.style.display = "block";
// 获取媒体属性,旧版本浏览器可能不支持mediaDevices,我们首先设置一个空对象
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
// 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
// 使用getUserMedia,因为它会覆盖现有的属性。
// 这里,如果缺少getUserMedia属性,就添加它。
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function (constraints) {
// 首先获取现存的getUserMedia(如果存在)
var getUserMedia =
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.getUserMedia;
// 有些浏览器不支持,会返回错误信息
// 保持接口一致
if (!getUserMedia) {
//不存在则报错
return Promise.reject(
new Error("getUserMedia is not implemented in this browser")
);
}
// 否则,使用Promise将调用包装到旧的navigator.getUserMedia
return new Promise(function (resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject);
});
};
}
var constraints = {
audio: false,
video: {
width: this.videoWidth,
height: this.videoHeight,
transform: "scaleX(-1)",
},
};
navigator.mediaDevices
.getUserMedia(constraints)
.then(function (stream) {
// 旧的浏览器可能没有srcObject
if ("srcObject" in _this.thisVideo) {
_this.thisVideo.srcObject = stream;
} else {
// 避免在新的浏览器中使用它,因为它正在被弃用。
_this.thisVideo.src = window.URL.createObjectURL(stream);
}
_this.thisVideo.onloadedmetadata = function (e) {
_this.thisVideo.play();
};
})
.catch((err) => {
console.log(err);
});
},
// 第二步、绘制图片(拍照功能)
setImage() {
var _this = this;
// canvas画图
_this.thisContext.drawImage(_this.thisVideo, 0, 0);
// 获取图片base64链接
var image = this.thisCancas.toDataURL("image/png");
_this.imgSrc = image; //赋值并预览图片
//这里是调用上传图片接口=====
this.postImg(); // 绘制完图片调用图片上传接口
},
// 关闭摄像头
stopNavigator() {
this.thisVideo.srcObject.getTracks()[0].stop();
},
// base64 转为 file
base64ToFile(urlData, fileName) {
let arr = urlData.split(",");
let mime = arr[0].match(/:(.*?);/)[1];
let bytes = atob(arr[1]); // 解码base64
let n = bytes.length;
let ia = new Uint8Array(n);
while (n--) {
ia[n] = bytes.charCodeAt(n);
}
return new File([ia], fileName, {type: mime});
},
},
destroyed: function () {
// 离开当前页面
this.stopNavigator(); // 关闭摄像头
},
};
</script>
<style>
.result_img {
width: 226px;
height: 195px;
background: #d8d8d8;
position: absolute;
top: 100px;
right: -100px;
}
#aaa {
width: 500px;
text-align: center;
margin: auto;
position: relative;
}
</style>
这里是一个页面效果就不展示小编帅气的俊脸了