补发团队项目开发03——基于百度云的人脸识别
按照要求实现开发人脸审核,通过百度云人脸识别,这边要先注册,注册步骤省略,这边识别仅作参考,仅做了简单的人脸识别,因为时间有限
这边先给出前端页面
前面绑定按钮事件省略 script代码如下
// 确认审核通过!
private passAudit() {
if (!this.remark) {
this.$message.error('请填写销号备注');
return;
}
// 关闭当前对话框
this.clearDialogVisible = false;
// 跳转到人脸识别页面
this.$router.push({
path: '/sectionLeader/deviceReview/faultClear/face-recognition',
query: {
faultId: this.row.faultId,
remark: this.remark
}
});
}
这边要写上路由 在路由文件里(全部路由文件在上一个博客里)
{
path: "faultClear",
component: () =>
import(/* webpackChunkName: "faultClear" */ "@/views/sectionLeader/deviceReview/faultClear/index.vue"),
meta: {
title: "故障销号",
icon: "icon-dish",
}
},
{
path: '/sectionLeader/deviceReview/faultClear/face-recognition',
component: () => import('@/views/sectionLeader/deviceReview/faultClear/FaceRecognition.vue'),
name: 'FaceRecognition',
meta: {
title: '人脸识别验证',
icon: 'dashboard',
hidden: true
},
},
人脸识别文件如下
<template>
<div class="face-recognition-container">
<div class="camera-container">
<video ref="videoElement" class="video-element" autoplay playsinline></video>
<canvas ref="canvasElement" class="canvas-element" style="display: none;"></canvas>
<div class="camera-overlay">
<div class="face-frame"></div>
</div>
</div>
<div class="button-container">
<el-button type="primary" @click="captureAndVerify">确认拍摄</el-button>
<el-button @click="cancelCapture">取消</el-button>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { auditFault2 } from '@/api/fault';
@Component
export default class FaceRecognition extends Vue {
private faultId: number = 0;
private remark: string = '';
private stream: MediaStream | null = null;
private videoElement: HTMLVideoElement | null = null;
private canvasElement: HTMLCanvasElement | null = null;
created() {
// 从路由参数中获取数据
const { faultId, remark } = this.$route.query;
if (faultId) this.faultId = Number(faultId);
if (remark) this.remark = remark as string;
// 验证参数
if (!this.faultId || !this.remark) {
this.$message.error('参数错误,请重新操作');
this.$router.go(-1);
}
}
mounted() {
this.videoElement = this.$refs.videoElement as HTMLVideoElement;
this.canvasElement = this.$refs.canvasElement as HTMLCanvasElement;
this.startCamera();
}
beforeDestroy() {
this.stopCamera();
}
private async startCamera() {
try {
this.stream = await navigator.mediaDevices.getUserMedia({
video: {
width: { ideal: 1280 },
height: { ideal: 720 },
facingMode: 'user'
}
});
if (this.videoElement) {
this.videoElement.srcObject = this.stream;
}
} catch (error) {
console.error('Error accessing camera:', error);
this.$message.error('无法访问摄像头,请检查权限设置');
this.$router.go(-1);
}
}
private stopCamera() {
if (this.stream) {
this.stream.getTracks().forEach(track => track.stop());
this.stream = null;
}
}
private captureAndVerify() {
if (!this.videoElement || !this.canvasElement) return;
const context = this.canvasElement.getContext('2d');
if (!context) return;
// 设置canvas尺寸与视频一致,确保不超过1920*1080
const maxWidth = 1280; // 确保分辨率不超过1920*1080
const maxHeight = 720;
const videoWidth = this.videoElement.videoWidth;
const videoHeight = this.videoElement.videoHeight;
// 计算适合的尺寸,保持宽高比
let width = videoWidth;
let height = videoHeight;
if (width > maxWidth) {
width = maxWidth;
height = (videoHeight / videoWidth) * maxWidth;
}
if (height > maxHeight) {
height = maxHeight;
width = (videoWidth / videoHeight) * maxHeight;
}
this.canvasElement.width = width;
this.canvasElement.height = height;
// 在canvas上绘制当前视频帧
context.drawImage(this.videoElement, 0, 0, width, height);
// 获取图像的base64编码 - 修改为JPEG格式,并设置较低的质量以减小文件大小
const imageBase64 = this.canvasElement.toDataURL('image/jpeg', 0.8);
// 处理base64字符串,移除前缀
const base64Data = imageBase64.split(',')[1];
// 发送到服务器进行验证
this.sendImageToServer(base64Data);
}
private async sendImageToServer(imageBase64: string) {
try {
this.$message.info('正在进行人脸识别验证...');
const response = await fetch('/api/face_recognition/search', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
base64Image: imageBase64, // 修改键名为image,符合API要求
groupId: 'device_management_demo', // 修改为group_id_list,符合百度云API命名
}),
});
console.log('Face recognition result:', response);
const data = await response.json();
console.log('Face recognition result:', data);
if (data.code === 1) {
// 人脸识别成功,继续进行审核逻辑
this.submitAudit();
} else {
this.$message.error('人脸识别未通过,审核不通过');
setTimeout(() => {
this.$router.go(-1);
}, 1500);
}
} catch (error) {
console.error('Error sending image to server', error);
this.$message.error('人脸识别服务异常,请稍后重试');
setTimeout(() => {
this.$router.go(-1);
}, 1500);
}
}
private submitAudit() {
const params = {
approved: true,
faultId: this.faultId,
satisfactionScore: null,
verifyId: 1,
verifyOpinion: this.remark,
};
auditFault2(params).then(res => {
if (res.data.code === 1) {
this.$message.success('审核通过成功!');
// 返回上一页并刷新
this.$router.push({
path: '/sectionLeader/deviceReview/faultClear',
query: { refresh: 'true' }
});
} else {
this.$message.error(res.data.msg || '操作失败');
this.$router.go(-1);
}
}).catch(() => {
this.$message.error('服务器繁忙,请稍后重试');
this.$router.go(-1);
});
}
private cancelCapture() {
this.stopCamera();
this.$router.go(-1);
}
}
</script>
<style lang="scss" scoped>
.face-recognition-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
background-color: #f5f5f5;
}
.camera-container {
position: relative;
width: 100%;
height: 100%;
margin-bottom: 20px;
border: 2px solid #dcdfe6;
border-radius: 4px;
overflow: hidden;
}
.video-element {
width: 100%;
height: 100%;
object-fit: cover;
}
.camera-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
.face-frame {
position: absolute;
top: 50%;
left: 50%;
width: 600px; /* 调整:从200px增加到300px */
height: 600px; /* 调整:从200px增加到300px */
transform: translate(-50%, -50%);
border: 3px solid #409EFF; /* 调整:边框加粗 */
border-radius: 50%;
box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.5);
}
.button-container {
display: flex;
gap: 20px;
}
</style>
接下来给出后端实现
这边先需要导入依赖(也可以自己仿照实现发送https请求 都要先获取token)我这边发现日志相关依赖异常 所以加了排除部分依赖
<!--百度云人脸识别-->
<dependency>
<groupId>com.baidu.aip</groupId>
<artifactId>java-sdk</artifactId>
<version>4.16.0</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
</exclusions>
</dependency>
之后给出工具类 这边token是没有用的 不过假如要自己模拟https请求可以使用这里的getAccessToken 因为百度云提供的依赖是封装了获取token的过程
package com.device.utils;
import com.baidu.aip.face.AipFace;
import com.device.properties.BaiduProperties;
import okhttp3.*;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
@Component
public class BaiduFaceRecognitionUtil {
@Autowired
BaiduProperties baiduProperties;
public boolean searchFaceInLibrary(String base64Image,String groupId) {
AipFace aipFace = new AipFace(baiduProperties.getAppId(), baiduProperties.getKey(), baiduProperties.getSecret());
// 构建请求URL
String url = "https://aip.baidubce.com/rest/2.0/face/v3/search";
// 构造模拟人像图片。 取决于image_type参数,传入BASE64字符串或URL字符串或FACE_TOKEN字符串
// 传入可选参数调用接口
HashMap<String, String> options = new HashMap<>();
options.put("match_threshold", "70");
options.put("quality_control", "NORMAL");
options.put("liveness_control", "NORMAL");
//options.put("user_id", "user1");
options.put("max_user_num", "1");
//人脸搜索
JSONObject res = aipFace.search(base64Image, "BASE64", baiduProperties.getGroupId(), options);
System.out.println(res);
System.out.println(res.getString("error_msg"));
System.out.println(res.getString("error_msg").getClass());
return res.getString("error_msg").equals("SUCCESS");
}
private String getAccessToken() {
String authUrl = "https://aip.baidubce.com/oauth/2.0/token";
String params = "grant_type=client_credentials&client_id=" + baiduProperties.getAppId() + "&client_secret=" + baiduProperties.getKey();
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = RequestBody.create(MediaType.parse("application/x-www-form-urlencoded"), params);
Request request = new Request.Builder()
.url(authUrl)
.post(requestBody)
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
String responseBody = response.body().string();
JSONObject jsonResponse = new JSONObject(responseBody);
return jsonResponse.getString("access_token");
}
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
throw new RuntimeException(e);
}
return null;
}
}
这边关于配置类注入属性的步骤省略
以上便实现了人脸识别开发,仅作参考
浙公网安备 33010602011771号