补发团队项目开发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;
    }
}

这边关于配置类注入属性的步骤省略
以上便实现了人脸识别开发,仅作参考

posted @ 2025-06-08 15:40  好像是Cwk  阅读(14)  评论(0)    收藏  举报