当前位置: 首页 > article >正文

AI智慧社区--人脸识别

前端

人脸的采集按钮:

首先对于选中未认证的居民记录,进行人脸采集

前端的按钮

  <el-form-item>
          <el-button v-has="'sys:person:info'" type="info" icon="el-icon-camera" :disabled="ids.length <= 0" @click="cameraHandle()">人脸采集</el-button>
        </el-form-item>

对应的采集方法:

    cameraHandle() {
      //选择多条数据的情况下
      if (this.ids.length > 1) {
        this.$message.error('人脸采集只能选择单条数据')
        return
      }
      //已经认证的情况下
      if (this.ids[0].state === 2) {
        this.$message.error('人脸识别已通过,不需要重复识别')
        return
      }
      this.faceVisible = true
      this.$nextTick(() => {
        this.$refs.face.init(this.ids[0].personId)
      })
    },

 跳转到人脸采集的弹窗

弹窗代码代码

<template>
  <el-dialog
    :title="'采集人脸相片'"
    :close-on-click-modal="false"
    :visible.sync="visible"
    width="1100px"
  >
    <el-form ref="dataForm" :model="dataForm" label-width="100px" style="width:95%;">
      <el-row>
        <el-col :span="9">
          <el-form-item label="" style="margin: 0;">
            <video v-if="openSuccess" id="videoCamera" autoplay width="260" height="200" style="border: none;" />
          </el-form-item>
        </el-col>
        <el-col :span="3" style="height: 200px;display: flex; justify-content: center;align-items: center;flex-wrap: wrap;">
          <el-button v-if="openSuccess" size="small" type="primary" style="width: 80px; text-align: center;" @click="setImage()">拍照</el-button>
          <el-upload
            class="upload-demo"
            action="#"
            :show-file-list="false"
            :http-request="fileUpload"
          >
            <el-button size="small" type="primary">上传人脸</el-button>
          </el-upload>
        </el-col>
        <el-col :span="8" style="display: flex; justify-content: center; align-items: center;">
          <canvas id="canvasCamera" style="display:none;" width="640" height="480" />
          <img v-if="imgSrc" :src="imgSrc" alt height="200">
        </el-col>
      </el-row>
      <hr>
      <el-row>
        <el-col :span="12">
          <el-card>
            <div class="text item">
              <b><font color="red">常见问题:</font></b><br><br>
              1、不支持IE浏览器,建议使用火狐、谷歌、Edge浏览器进行考试<br><br>
              2、若浏览器弹出是否允许调用摄像头,请点击允许<br><br>
              3、<font color="red">必须使用https加密协议,摄像头方能正常使用</font><br><br>
              4、如果问题还存在,请按<a
                href="https://examai.cn/pc/zhinan.pdf"
                target="_blank"
              ><font color="red"><b>启用摄像头操作指南</b></font></a>进行操作><br><br>
              5、本模块仅供测试接口,具体使用请以实际情况为准
            </div>
          </el-card>
        </el-col>
        <el-col :span="12">
          <img src="@/assets/images/cm.png" width="100%">
        </el-col>
      </el-row>
    </el-form>
  </el-dialog>
</template>
<script>
import { addPerson } from '@/api/sys/person'
export default {
  data() {
    return {
      visible: false,
      dataForm: {
        personId: '',
        extName: '',
        fileBase64: ''
      },
      imgSrc: '',
      video: null,
      context: null,
      canvas: null,
      openSuccess: true
    }
  },
  watch: {
    visible(val) {
      if (val) {
        this.imgSrc = ''
        setTimeout(() => {
          this.getCamera()
        }, 1000)
      } else {
        if (this.openSuccess) {
          this.closeCamera()
        }
      }
    }
  },
  created() {
    setTimeout(() => {
      this.getCamera()
    }, 1000)
    this.init()
  },
  methods: {
    init(personId) {
      this.visible = true
      this.dataForm.personId = personId
    },
    // 表单提交
    dataFormSubmit() {
      const _this = this
      this.$refs['dataForm'].validate((valid) => {
        if (valid) {
          const param = {
            //人员的ID
            'personId': this.dataForm.personId,
            //文件的后缀
            'extName': this.dataForm.extName,
            //文件的Base64编码
            'fileBase64': this.dataForm.fileBase64
          }
          addPerson(param).then(res => {
            if (res.code === 200) {
              _this.visible = false
              _this.$emit('refreshDataList')
              _this.$message.success(res.msg)
            } else {
              _this.$message.error(res.msg)
            }
          })
        }
      })
    },
    // 打开摄像头
    getCamera() {
      this.video = document.getElementById('videoCamera')
      this.canvas = document.getElementById('canvasCamera')
      this.context = this.canvas.getContext('2d')
      const errocb = () => {
        this.$message.error('摄像头打开失败!')
        this.openSuccess = false
      }
      if (navigator.webkitGetUserMedia) {
        navigator.webkitGetUserMedia({ audio: false, video: true }, (stream) => {
          // video.src=window.URL.createObjectURL(stream);
          this.video.srcObject = stream
          this.video.play()
        }, errocb)
      } else if (navigator.mediaDevices.getUserMedia) {
        // var constraints = { audio: true, video: { width: 1280, height: 720 } };
        const constraints = { audio: false, video: true }
        navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
          // var video = document.querySelector('video');
          this.video.srcObject = stream
          this.video.onloadedmetadata = (e) => {
            this.video.play()
          }
        })
      } else if (navigator.getUserMedia) {
        navigator.getUserMedia({ audio: false, video: true }, (stream) => {
          this.video.src = window.webkitURL.createObjectURL(stream)
          this.video.srcObject = stream
          this.video.play()
        }, errocb)
      } else {
        alert('你的浏览器不支持打开摄像头')
      }
    },
    //  绘制图片(拍照功能)
    setImage() {
      this.context.drawImage(
        this.video,
        0,
        0,
        this.video.videoWidth,
        this.video.videoHeight
      )
      this.imgSrc = this.canvas.toDataURL('image/png')
      this.dataForm.extName = this.imgSrc.substring(this.imgSrc.indexOf('/') + 1, this.imgSrc.indexOf(';'))
      this.dataForm.fileBase64 = this.imgSrc.substring(22)
      this.dataFormSubmit()
    },
    // 关闭摄像头
    closeCamera() {
      this.video.srcObject.getTracks()[0].stop()
    },
    // 关闭弹出层
    closeDialog() {
      this.visible = false
    },
    // 重写文件上传方法
    fileUpload(file) {
      this.fileToBase64(file.file).then(res => {
        // console.log(res)
        this.imgSrc = res
        this.dataForm.extName = res.substring(res.indexOf('/') + 1, res.indexOf(';'))
        const len = 19 + this.dataForm.extName.length
        this.dataForm.fileBase64 = res.substring(len)
        // console.log(this.dataForm.fileBase64)
        this.dataFormSubmit()
      }).catch(err => {
        console.log(err)
        this.$message.error(err)
      })
    },
    // 转base64
    fileToBase64(file) {
      return new Promise((resolve, reject) => {
        const reader = new FileReader()
        let fileResult = ''
        if (file.size > 1024 * 1024) {
          reject('文件大小不能超过1M')
        }
        reader.readAsDataURL(file)
        // 开始转
        reader.onload = () => {
          fileResult = reader.result
          // data:image/jpeg;base64,
        }
        // 转 失败
        reader.onerror = function(error) {
          reject(error)
        }
        // 转 结束  咱就 resolve 出去
        reader.onloadend = function() {
          resolve(fileResult)
        }
      })
    }
  }
}
</script>
<style>
  .avatar-uploader .el-upload {
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
  }
  .avatar-uploader .el-upload:hover {
    border-color: #409EFF;
  }
  .avatar-uploader-icon {
    font-size: 28px;
    color: #8c939d;
    width: 178px;
    height: 178px;
    line-height: 178px;
    text-align: center;
  }
  .avatar {
    width: 178px;
    height: 178px;
    display: block;
  }
</style>

 调用后端接口

export function addPerson(data) {
  return request({
    //人脸录入
    url: '/sys/person/addPerson',
    method: 'post',
    data
  })
}

后端

后端代码

    @LogAnnotation("人脸采集")
    @PostMapping("/addPerson")
    public Result addPerson(@RequestBody PersonFaceForm personFaceForm){
        //通过传入的表单信息中的ID 查询居民信息
        Person person = this.personService.getById(personFaceForm.getPersonId());
        //如果没有查询到相应的居民信息 则说明居民不存在
        if(person == null){
            return Result.error("居民不存在");
        }
        //数据库表中的state字段说明 人脸是否已经录入
        if(person.getState() == 2){
            return Result.error("人脸识别已通过,不需要重复识别");
        }
        //文件的Base64位编码是否已经存在  如果为空说明没有人脸图片
        if(personFaceForm.getFileBase64() == null || personFaceForm.getFileBase64().equals("")){
            return Result.error("请上传Base64编码的图片");
        }
        //如果相关的关于人脸上传的配置信息已经配置,则进行下面的内容
        if(apiConfiguration.isUsed()){

//          方式二:调用腾讯API人脸识别
            //1.人脸认证账号创建
            //获取人脸识别的ID
            String faceId = newPerson(personFaceForm,person.getUserName());
            if(faceId == null){
                return Result.error("人脸识别失败");
            }
            if (faceId != null) {
                //生成头像访问路径
                String filename = faceId + "." + personFaceForm.getExtName();
                String faceUrl = urlPrefix + "community/upload/face/" + filename;
                person.setFaceUrl(faceUrl);
                person.setState(2);
                //更新人脸识别状态及图片地址
                this.personService.updateById(person);
                return Result.ok();
            }

            //方式一:
            //模拟人脸识别
            //调用随机数的工具类  随机生成模拟id
//            String faceId = RandomUtil.getBitRandom();
//            //获取Base64编码的前60位
//            String faceBase = personFaceForm.getFileBase64().substring(0, 60);
//            //如果不是头像
//            if(faceBase.equals("iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAAXNSR0IArs4c")) {
//                return Result.error("人脸识别失败");
//            }
//            //存储头像
//            //生成文件名  随机数+前端传入的文件首字母
//            String filename = faceId + "." + personFaceForm.getExtName();
//            //本地存储路径:D:/community/upload/face/+生成的文件名
//            String savePath = face + filename;
//            try {
//            //将 Base64 编码的字符串解码,并将解码后的二进制数据写入到指定路径(savePath)的文件中
//                Base64Util.decoderBase64File(personFaceForm.getFileBase64(), savePath);
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//            //生成头像访问路径 http://localhost:8181/community/upload/face/+生成的文件名
//            String faceUrl = urlPrefix + "community/upload/face/" + filename;//文件协议
//            //将更新的信息封装到实体类,从而更新数据库
//            person.setFaceUrl(faceUrl);
//            person.setState(2);
//            person.setFaceBase(faceBase);
//            //更新人脸识别状态及图片地址
//            this.personService.updateById(person);
//            return Result.ok();
        }
        return Result.error("未开启人脸识别");
    }

两种人脸识别的方式:

第一种:模拟人脸识别
基本思路:

1.通过传入的表单信息中的ID 查询居民信息

  • 没有查询到相应的居民信息 则说明居民不存在
  • 检查居民是否已经完成人脸认证
  • 文件的Base64位编码是否已经存在 如果为空说明没有人脸图片

2.进行人脸认证

  • 生成模拟的faceid 和 文件的Base64位编码
  • 将人脸信息存储在本地
  • 更新数据库中的信息
实现代码
package com.southwind.form;

import lombok.Data;

@Data
public class PersonFaceForm {
    //居民ID
    private Integer personId;
    //人脸图片的后缀
    private String extName;
    //文件的Base64编码
    private String fileBase64;
}
    @LogAnnotation("人脸采集")
    @PostMapping("/addPerson")
    public Result addPerson(@RequestBody PersonFaceForm personFaceForm){
        //通过传入的表单信息中的ID 查询居民信息
        Person person = this.personService.getById(personFaceForm.getPersonId());
        //如果没有查询到相应的居民信息 则说明居民不存在
        if(person == null){
            return Result.error("居民不存在");
        }
        //数据库表中的state字段说明 人脸是否已经录入
        if(person.getState() == 2){
            return Result.error("人脸识别已通过,不需要重复识别");
        }
        //文件的Base64位编码是否已经存在  如果为空说明没有人脸图片
        if(personFaceForm.getFileBase64() == null || personFaceForm.getFileBase64().equals("")){
            return Result.error("请上传Base64编码的图片");
        }
        //如果相关的关于人脸上传的配置信息已经配置,则进行下面的内容
        if(apiConfiguration.isUsed()){

            //方式一:
            //模拟人脸识别
            //调用随机数的工具类  随机生成模拟id
            String faceId = RandomUtil.getBitRandom();
            //获取Base64编码的前60位
            String faceBase = personFaceForm.getFileBase64().substring(0, 60);
            //如果不是头像
            if(faceBase.equals("iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAAXNSR0IArs4c")) {
                return Result.error("人脸识别失败");
            }
            //存储头像
            //生成文件名  随机数+前端传入的文件首字母
            String filename = faceId + "." + personFaceForm.getExtName();
            //本地存储路径:D:/community/upload/face/+生成的文件名
            String savePath = face + filename;
            try {
            //将 Base64 编码的字符串解码,并将解码后的二进制数据写入到指定路径(savePath)的文件中
                Base64Util.decoderBase64File(personFaceForm.getFileBase64(), savePath);
            } catch (Exception e) {
                e.printStackTrace();
            }
            //生成头像访问路径 http://localhost:8181/community/upload/face/+生成的文件名
            String faceUrl = urlPrefix + "community/upload/face/" + filename;//文件协议
            //将更新的信息封装到实体类,从而更新数据库
            person.setFaceUrl(faceUrl);
            person.setState(2);
            person.setFaceBase(faceBase);
            //更新人脸识别状态及图片地址
            this.personService.updateById(person);
            return Result.ok();
        }
        return Result.error("未开启人脸识别");
    }
    第二种:利用腾讯云的人脸识别
    人员库的创建

    1.创建密钥

    在控制台中,进入访问管理

    API密钥管理---新建密钥   切记复制密钥

    在项目的配置文件当中,配置密钥的信息

    2.创建人员库

    搜索人脸认证,创建人员库

     配置相关的人员库信息

     

    serverIp area 不需要修改
    used 表示启用
    passPercent 表示识别率,比如 80 表示图片相似度 80即认为通过
    基本思路

    腾讯云的人脸识别:

    • 创建人脸认证账号
    • 将人脸信息保存到腾讯云
    • 将人脸信息保存到本地
    实现代码:
        @LogAnnotation("人脸采集")
        @PostMapping("/addPerson")
        public Result addPerson(@RequestBody PersonFaceForm personFaceForm){
            //通过传入的表单信息中的ID 查询居民信息
            Person person = this.personService.getById(personFaceForm.getPersonId());
            //如果没有查询到相应的居民信息 则说明居民不存在
            if(person == null){
                return Result.error("居民不存在");
            }
            //数据库表中的state字段说明 人脸是否已经录入
            if(person.getState() == 2){
                return Result.error("人脸识别已通过,不需要重复识别");
            }
            //文件的Base64位编码是否已经存在  如果为空说明没有人脸图片
            if(personFaceForm.getFileBase64() == null || personFaceForm.getFileBase64().equals("")){
                return Result.error("请上传Base64编码的图片");
            }
            //如果相关的关于人脸上传的配置信息已经配置,则进行下面的内容
            if(apiConfiguration.isUsed()){
    
    //          方式二:调用腾讯API人脸识别
    //            1.人脸认证账号创建
    //            获取人脸识别的ID
                String faceId = newPerson(personFaceForm,person.getUserName());
                if(faceId == null){
                    return Result.error("人脸识别失败");
                }
                if (faceId != null) {
                    //生成头像访问路径
                    String filename = faceId + "." + personFaceForm.getExtName();
                    String faceUrl = urlPrefix + "community/upload/face/" + filename;
                    person.setFaceUrl(faceUrl);
                    person.setState(2);
                    //更新人脸识别状态及图片地址
                    this.personService.updateById(person);
                    return Result.ok();
                }
    
            }
            return Result.error("未开启人脸识别");
        }
     
    private String newPerson(PersonFaceForm vo,String personName) {
            String faceId = null;
            //获取PersonFaceForm中的属性值
            String faceBase64 = vo.getFileBase64();
            String extname = vo.getExtName();
            String personId = vo.getPersonId()+"";
            //保存路径为 D:/community/upload/face/
            String savePath = face;
            //
            if (faceBase64!=null && !faceBase64.equals("")) {
                FaceApi faceApi = new FaceApi();
                RootResp resp = faceApi.newperson(apiConfiguration, personId, personName, faceBase64);
                if(resp.getRet()==0) {
                    JSONObject data = JSON.parseObject(resp.getData().toString());
                    faceId = data.getString("FaceId");
                    if(faceId!=null) {
                        String filename = faceId + "." + extname;
                        savePath += filename;
                        try {
                            Base64Util.decoderBase64File(faceBase64, savePath);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
                else {
                    return faceId;
                }
            }
            return faceId;
        }

    调用的faceApi的newperson

      public RootResp newperson(ApiConfiguration config, String personId, String personName, String image) {
            RootResp result = new RootResp();
            try{
                //使用配置对象中的 SecretId 和 SecretKey 创建一个 Credential 对象,用于身份验证
                Credential cred = new Credential(config.getSecretId(), config.getSecretKey());
                //用于配置HTTP请求
                HttpProfile httpProfile = new HttpProfile();
                //设置请求发送的目标服务器地址
                httpProfile.setEndpoint(config.getServerIp());
                //配置客户端的相关信息
                ClientProfile clientProfile = new ClientProfile();
                clientProfile.setHttpProfile(httpProfile);
                //与腾讯云真正进行交互的对象
                IaiClient client = new IaiClient(cred, config.getArea(), clientProfile);
                //创建一个 JSONObject 对象,用于存储请求参数
                JSONObject paramObj = new JSONObject();
                paramObj.put("GroupId", config.getGroupId());
                paramObj.put("PersonId", config.getPersonIdPre() + personId);
                paramObj.put("PersonName", personName);
                paramObj.put("Image", image);
    
                CreatePersonRequest req = CreatePersonRequest.fromJsonString(paramObj.toJSONString(), CreatePersonRequest.class);
                CreatePersonResponse resp = client.CreatePerson(req);
                result.setData(CreatePersonResponse.toJsonString(resp));
            } catch (TencentCloudSDKException e) {
                result.setRet(-1);
                result.setMsg(e.toString());
                logger.error(e.toString());
            }
            logger.info(result);
            return result;
        }
    


    http://www.kler.cn/a/529385.html

    相关文章:

  • 【LLM-agent】(task4)搜索引擎Agent
  • Gradle配置指南:深入解析settings.gradle.kts(Kotlin DSL版)
  • 基于FPGA的BT656编解码
  • TensorFlow 示例摄氏度到华氏度的转换(一)
  • 2025:影刀RPA使用新实践--CSDN博客下载
  • MySQL CTE:解锁SQL查询新模式
  • 详解CSS `clear` 属性及其各个选项
  • Rust 控制流语法详解
  • 蓝桥杯之c++入门(二)【输入输出(上)】
  • Lesson 129 70 miles an hour
  • 【C++】 STL -- 容器(2)
  • AI-on-the-edge-device - 将“旧”设备接入智能世界
  • 【开源免费】基于Vue和SpringBoot的校园网上店铺系统(附论文)
  • 区间加法 II - 解题思路与代码解析
  • 14-9-2C++STL的set容器
  • PHP XML操作指南
  • 音视频入门基础:RTP专题(8)——使用Wireshark分析RTP
  • 【Convex Optimization Stanford】Lec5. Duality 对偶问题
  • Java设计模式:行为型模式→访问者模式
  • 基于直觉的理性思维入口:相提并论的三者 以“网络”为例
  • 【SLAM】于AutoDL云上GPU运行GCNv2_SLAM的记录
  • ResNet--深度学习中的革命性网络架构
  • Unity 2D实战小游戏开发跳跳鸟 - 跳跳鸟碰撞障碍物逻辑
  • 人工智能第2章-知识点与学习笔记
  • LabVIEW如何有效地进行数据采集?
  • MySQL数据库——事务和索引_龍弟idea