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

智慧社区(六)——社区居民人脸识别功能实现详解:从腾讯 API 集成到模拟验证

前端实现:摄像头调用与数据提交

前端采用 Vue+Element UI 实现,核心是人脸采集组件的交互逻辑,包括摄像头权限获取、视频流展示、拍照 / 上传图片、Base64 处理及接口请求。

1. 触发人脸采集入口

在主页面(Person.vue)中,用户通过勾选表格中的一条 “未识别” 记录,点击 “人脸采集” 按钮触发采集流程:

// Person.vue 中触发人脸采集的方法
cameraHandle() {// 校验:只能选择一条记录if (this.ids.length > 1) {this.$message.error('人脸采集只能选择单条数据')return}// 校验:已识别的记录无需重复采集if (this.ids[0].state === 2) {this.$message.error('人脸识别已通过,不需要重复识别')return}// 显示人脸采集对话框,传递当前人员IDthis.faceVisible = truethis.$nextTick(() => {this.$refs.face.init(this.ids[0].personId)})
}

通过faceVisible控制人脸采集组件(Face.vue)的显示,同时通过init方法将选中人员的personId传递给采集组件。

2. 人脸采集组件(Face.vue)核心逻辑

该组件是一个对话框,包含摄像头实时预览拍照图片上传三大功能,最终目的是将人脸图片转为 Base64 格式提交给后端。

(1)摄像头权限获取与视频流展示

组件显示时(visible为 true),调用getCamera方法获取摄像头权限并展示实时视频流,兼容不同浏览器的 API:

// Face.vue 中获取摄像头视频流
getCamera() {this.video = document.getElementById('videoCamera') // 视频DOMthis.canvas = document.getElementById('canvasCamera') // 用于绘制视频帧的画布this.context = this.canvas.getContext('2d')// 错误回调:摄像头打开失败const errocb = () => {this.$message.error('摄像头打开失败!')this.openSuccess = false}// 兼容不同浏览器的媒体设备APIif (navigator.webkitGetUserMedia) {// Chrome/Safari 旧版APInavigator.webkitGetUserMedia({ audio: false, video: true }, (stream) => {this.video.srcObject = streamthis.video.play()}, errocb)} else if (navigator.mediaDevices.getUserMedia) {// 标准API(推荐)const constraints = { audio: false, video: true }navigator.mediaDevices.getUserMedia(constraints).then((stream) => {this.video.srcObject = streamthis.video.onloadedmetadata = () => this.video.play()})} else if (navigator.getUserMedia) {// 旧版Firefox APInavigator.getUserMedia({ audio: false, video: true }, (stream) => {this.video.src = window.webkitURL.createObjectURL(stream)this.video.play()}, errocb)} else {alert('你的浏览器不支持打开摄像头')}
}

通过srcObject将摄像头流绑定到 video 标签,实现实时预览。

(2)拍照功能:将视频帧转为 Base64

点击 “拍照” 按钮时,调用setImage方法将当前视频帧绘制到 canvas,再通过canvas.toDataURL转为 Base64 格式:

// Face.vue 中拍照并处理为Base64
setImage() {// 将视频当前帧绘制到canvas(尺寸与视频一致)this.context.drawImage(this.video,0, 0,this.video.videoWidth,this.video.videoHeight)// 转为Base64(格式:data:image/png;base64,xxxx)this.imgSrc = this.canvas.toDataURL('image/png')// 提取文件扩展名(如png)和纯Base64字符串(去掉前缀)this.dataForm.extName = this.imgSrc.substring(this.imgSrc.indexOf('/') + 1, this.imgSrc.indexOf(';'))this.dataForm.fileBase64 = this.imgSrc.substring(22) // 22是'data:image/png;base64,'的长度// 提交数据到后端this.dataFormSubmit()
}
(3)图片上传功能:文件转 Base64

支持用户上传本地图片,通过el-upload组件重写上传逻辑,将文件转为 Base64:

// Face.vue 中上传图片并转为Base64
fileUpload(file) {// 调用工具方法将文件转为Base64this.fileToBase64(file.file).then(res => {this.imgSrc = res// 提取扩展名和纯Base64this.dataForm.extName = res.substring(res.indexOf('/') + 1, res.indexOf(';'))const len = 19 + this.dataForm.extName.length // 'data:image/xxx;base64,'的长度this.dataForm.fileBase64 = res.substring(len)// 提交数据this.dataFormSubmit()}).catch(err => {this.$message.error(err)})
}// 文件转Base64的工具方法
fileToBase64(file) {return new Promise((resolve, reject) => {const reader = new FileReader()// 限制文件大小(1M以内)if (file.size > 1024 * 1024) {reject('文件大小不能超过1M')}reader.readAsDataURL(file) // 异步转为Base64reader.onloadend = () => resolve(reader.result) // 成功回调reader.onerror = (error) => reject(error) // 失败回调})
}
(4)提交数据到后端

无论是拍照还是上传的图片,最终都通过dataFormSubmit方法构造参数并调用接口:

// Face.vue 中提交数据
dataFormSubmit() {this.$refs['dataForm'].validate((valid) => {if (valid) {const param = {personId: this.dataForm.personId, // 人员IDextName: this.dataForm.extName, // 图片扩展名(如png)fileBase64: this.dataForm.fileBase64 // 纯Base64字符串}// 调用后端接口(API定义在@/api/sys/person)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)}})}})
}

接口调用通过封装的request工具实现,对应后端的POST /sys/person/addPerson接口。

在社区管理系统中,人脸识别技术能有效提升居民身份核验的效率与安全性。本文将详细介绍如何基于腾讯云人脸识别 API 实现社区居民人脸采集功能,包括 API 配置、代码实现、图片处理及模拟验证方案,适合需要集成人脸识别功能的开发者参考。

 后端实现:申请配置功能实现以及测试

1、前期准备:腾讯云 API 申请与配置

要使用腾讯云人脸识别功能,需先完成 API 接口的申请与基础配置,具体步骤如下:

1.1 腾讯云 API 密钥与人员库创建

  • 创建访问密钥:登录腾讯云控制台,进入「访问管理」→「API 密钥管理」,创建SecretIdSecretKey(这是调用 API 的身份凭证)。
  • 创建人员库:进入「人脸识别」服务,创建用于存储居民人脸信息的「人员库」(对应GroupId),后续所有居民人脸将关联到该库。

1.2 项目配置文件设置

application.yml中配置腾讯 API 参数、文件上传路径等核心信息,示例如下:

# 文件上传路径配置
upload:face: D:/community/upload/face/  # 人脸图片本地存储路径excel: D:/community/upload/excel/  # 其他文件路径urlPrefix: http://localhost:8282/  # 图片访问基础URL# 人脸识别API配置
plateocr:secretId: AKID3CXqCeGxiOE1snomp9ThopkZIyXypZEl  # 腾讯云SecretIdsecretKey: c7awCRbecXL0b9e4Sk2HVyfVONVk4VvF  # 腾讯云SecretKeyserverIp: iai.tencentcloudapi.com  # 人脸识别API服务器地址(固定)area: ap-guangzhou  # 服务器区域(固定)groupId: 1001  # 人员库IDused: true  # 是否启用腾讯API(true启用,false模拟)passPercent: 80  # 识别通过率阈值(80%即认为匹配)

1.3 引入依赖

pom.xml中添加腾讯云 SDK 依赖,用于调用人脸识别 API:

<dependency><groupId>com.tencentcloudapi</groupId><artifactId>tencentcloud-sdk-java</artifactId><version>3.1.62</version>
</dependency>

2、项目核心配置类

为了更好地管理配置参数和文件访问,需创建以下配置类:

2.1 人脸识别参数配置类(ApiConfiguration)

通过@ConfigurationProperties绑定application.yml中的plateocr配置,方便在代码中直接使用:

package com.qcby.community.configuration;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@ConfigurationProperties(value = "plateocr")
@Component
@Data
@ApiModel(value = "ApiConfiguration", description = "人脸识别参数描述")
public class ApiConfiguration {@ApiModelProperty("人脸识别secretId")private String secretId;@ApiModelProperty("人脸识别secretKey")private String secretKey;@ApiModelProperty("人脸识别服务器ip")private String serverIp;@ApiModelProperty("人脸识别服务器区域")private String area;@ApiModelProperty("人脸识别默认分组")private String groupId;@ApiModelProperty("人脸识别用户id前缀")private String personIdPre;@ApiModelProperty("人脸识别随机数")private String nonceStr;@ApiModelProperty("是否启用人脸识别功能")private boolean used = false;@ApiModelProperty("人脸识别比对准确度阈值")private float passPercent;
}

2.2 文件访问路径映射(WebMvcConfiguration)

配置本地文件与 URL 的映射关系,使前端能通过 URL 直接访问上传的人脸图片:

package com.qcby.community.configuration;import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {@Value("${upload.face}")String facePath;  // 本地人脸图片路径@Value("${upload.excel}")String excelPath;  // 本地Excel路径@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {// 映射规则:URL路径 -> 本地文件路径registry.addResourceHandler("/community/upload/face/**").addResourceLocations("file:" + facePath);registry.addResourceHandler("/community/upload/excel/**").addResourceLocations("file:" + excelPath);}
}

3、核心功能实现:人脸采集接口

人脸采集接口是核心功能,负责接收前端上传的人脸图片(Base64 格式),通过腾讯 API 验证后保存图片并更新居民信息。

3.1 接口参数定义

  • 传入参数(JSON 格式):

    {"personId": 98,  // 居民ID(关联数据库中的居民记录)"extName": "png",  // 图片格式(如png、jpg)"fileBase64": "iVBORw0KGgoAAAANSUhEUgAAAJs...",  // Base64编码的图片内容
    }
    
  • 返回参数(JSON 格式):

    {"msg": "操作成功",  // 提示信息"code": 200  // 状态码(200成功,其他失败)
    }
    

3.2 实现思路

  1. 严谨性判断:验证居民是否存在、是否已完成人脸采集、图片是否为有效 Base64 编码。
  2. 人脸检测:调用腾讯 API 验证图片中是否包含人脸。
  3. 图片处理:将 Base64 图片解码并保存到本地,生成访问 URL。
  4. 信息更新:更新居民表中的人脸图片 URL 和识别状态。

3.3 代码实现

package com.qcby.community.controller;import com.qcby.community.configuration.ApiConfiguration;
import com.qcby.community.entity.Person;
import com.qcby.community.form.PersonFaceForm;
import com.qcby.community.service.PersonService;
import com.qcby.community.util.Base64Util;
import com.qcby.community.util.FaceApi;
import com.qcby.community.util.RootResp;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;@RestController
public class FaceController {@Autowiredprivate ApiConfiguration apiConfiguration;  // 人脸识别配置@Autowiredprivate PersonService personService;  // 居民服务@Value("${upload.face}")private String faceSavePath;  // 人脸图片本地保存路径@Value("${upload.urlPrefix}")private String urlPrefix;  // 图片访问基础URL/*** 人脸采集接口*/@PostMapping("/addPerson")public Result addPerson(@RequestBody PersonFaceForm personFaceForm) {// 1. 严谨性判断:验证居民是否存在Person person = personService.getById(personFaceForm.getPersonId());if (person == null) {return Result.error("居民不存在");}// 2. 验证是否已完成人脸采集(state=2表示已通过)if (person.getState() == 2) {return Result.error("人脸识别已通过,不需要重复识别");}// 3. 验证图片是否为有效Base64编码if (personFaceForm.getFileBase64() == null || personFaceForm.getFileBase64().isEmpty()) {return Result.error("请上传Base64编码的图片");}// 4. 调用腾讯API或模拟验证if (apiConfiguration.isUsed()) {// 启用腾讯API:调用接口添加人脸String faceId = newPerson(personFaceForm, person.getUserName());if (faceId == null) {return Result.error("人脸识别失败");}// 5. 保存图片并更新居民信息String filename = faceId + "." + personFaceForm.getExtName();String faceUrl = urlPrefix + "community/upload/face/" + filename;  // 生成图片访问URLperson.setFaceUrl(faceUrl);person.setState(2);  // 更新状态为“已通过”personService.updateById(person);return Result.ok();} else {// 未启用腾讯API:使用模拟验证simulateFaceRecognition(personFaceForm, person);return Result.ok();}}/*** 调用腾讯API添加人脸*/private String newPerson(PersonFaceForm form, String personName) {String faceId = null;String faceBase64 = form.getFileBase64();String personId = form.getPersonId().toString();if (faceBase64 != null && !faceBase64.isEmpty()) {FaceApi faceApi = new FaceApi();// 调用腾讯API的“创建人员”接口RootResp resp = faceApi.newperson(apiConfiguration, personId, personName, faceBase64);if (resp.getRet() == 0) {// 解析返回结果,获取FaceId(腾讯返回的人脸唯一标识)JSONObject data = JSON.parseObject(resp.getData().toString());faceId = data.getString("FaceId");// 保存Base64图片到本地String savePath = faceSavePath + faceId + "." + form.getExtName();try {Base64Util.decoderBase64File(faceBase64, savePath);} catch (Exception e) {e.printStackTrace();return null;}}}return faceId;}/*** 模拟人脸识别(未启用腾讯API时使用)*/private void simulateFaceRecognition(PersonFaceForm form, Person person) {// 生成随机人脸ID(模拟腾讯返回的FaceId)String faceId = RandomUtil.getBitRandom();// 简单验证:通过图片Base64前缀判断是否为有效人脸(实际项目可增强验证逻辑)String faceBasePrefix = form.getFileBase64().substring(0, 60);if (faceBasePrefix.equals("iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAAXNSR0IArs4c")) {throw new RuntimeException("人脸识别失败(模拟)");}// 保存图片到本地String filename = faceId + "." + form.getExtName();String savePath = faceSavePath + filename;try {Base64Util.decoderBase64File(form.getFileBase64(), savePath);} catch (Exception e) {e.printStackTrace();}// 更新居民信息String faceUrl = urlPrefix + "community/upload/face/" + filename;person.setFaceUrl(faceUrl);person.setState(2);  // 标记为“已通过”person.setFaceBase(faceBasePrefix);  // 保存前缀用于后续验证(模拟)personService.updateById(person);}
}

 

 

 

 

4、工具类详解

为了简化开发,封装了 3 个核心工具类,分别处理 API 调用、响应封装和 Base64 编码转换。

4.1 人脸识别 API 工具类(FaceApi)

封装腾讯云人脸识别 API 的各种操作(创建人员、删除人员、人脸验证等),核心方法如下:

package com.qcby.community.util;import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.qcby.community.configuration.ApiConfiguration;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.iai.v20180301.IaiClient;
import com.tencentcloudapi.iai.v20180301.models.*;
import org.apache.log4j.Logger;public class FaceApi {private Logger logger = Logger.getLogger(FaceApi.class);/*** 添加人员(将居民人脸信息录入腾讯云人员库)*/public RootResp newperson(ApiConfiguration config, String personId, String personName, String image) {RootResp result = new RootResp();try {// 1. 初始化腾讯API客户端Credential cred = new Credential(config.getSecretId(), config.getSecretKey());HttpProfile httpProfile = new HttpProfile();httpProfile.setEndpoint(config.getServerIp());  // 腾讯人脸识别API地址ClientProfile clientProfile = new ClientProfile();clientProfile.setHttpProfile(httpProfile);IaiClient client = new IaiClient(cred, config.getArea(), clientProfile);// 2. 构建请求参数JSONObject paramObj = new JSONObject();paramObj.put("GroupId", config.getGroupId());  // 人员库IDparamObj.put("PersonId", config.getPersonIdPre() + personId);  // 居民唯一标识paramObj.put("PersonName", personName);  // 居民姓名paramObj.put("Image", image);  // Base64图片// 3. 发送请求并获取响应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("腾讯API调用失败:" + e.toString());}return result;}// 其他方法:detectFace(人脸分析)、delperson(删除人员)、addface(增加人脸)等
}

4.2 响应结果封装类(RootResp)

统一 API 响应格式,方便处理成功 / 失败状态:

package com.qcby.community.util;import com.alibaba.fastjson.JSON;public class RootResp {private int ret = 0;  // 0成功,-1失败private String msg;   // 提示信息private Object data;  // 响应数据// getter和setter省略@Overridepublic String toString() {return JSON.toJSONString(this);  // 转为JSON字符串}
}

4.3 Base64 编码工具类(Base64Util)

处理 Base64 编码与文件的相互转换,核心方法如下:

package com.qcby.community.util;import org.apache.commons.codec.binary.Base64;
import java.io.*;public class Base64Util {/*** Base64编码字符串转文件*/public static void decoderBase64File(String base64Code, String targetPath) throws Exception {byte[] buffer = Base64.decodeBase64(base64Code.getBytes("UTF-8"));  // 解码try (FileOutputStream out = new FileOutputStream(targetPath)) {out.write(buffer);  // 写入文件}}/*** 文件转Base64编码*/public static String encodeBase64File(String path) throws Exception {try (FileInputStream inputFile = new FileInputStream(path)) {byte[] buffer = new byte[(int) new File(path).length()];inputFile.read(buffer);return new String(Base64.encodeBase64(buffer), "UTF-8");  // 编码}}// 其他方法:网络图片转Base64、输入流转字节数组等
}

http://www.dtcms.com/a/313714.html

相关文章:

  • Mysql深入学习:索引篇一
  • Linux操作系统的相关操作介绍
  • Android 之 MVP架构
  • python---可变对象、不可变对象
  • SpringBoot学习总结
  • 在不可更改系统上构建数据响应机制的可选策略
  • 彻底屏蔽夸克浏览器更新
  • ORA-12514:TNS: 监听程序当前无法识别连接描述符中请求的服务
  • 【Spring】Bean的生命周期,部分源码解释
  • 【高等数学】第七章 微分方程——第九节 欧拉方程
  • Java基础:代码块/内部类/Lambda函数/常用API/GUI编程
  • LeetCode - 合并两个有序链表 / 删除链表的倒数第 N 个结点
  • 三角洲行动ACE反作弊VT-d报错?CPU虚拟化如何开启!
  • MySQL架构全面理解
  • 克罗均线策略思路
  • 无刷电机母线电容计算
  • SpringBoot AI自动化测试实战案例
  • 大模型能力测评(提示词请帮我把这个项目改写成为python项目)
  • 译|数据驱动智慧供应链的构成要素与关联思考
  • 死锁深度解析:原理、检测与解决之道
  • C++ <type_traits> 应用详解
  • 志邦家居PMO负责人李蓉蓉受邀为PMO大会主持人
  • 【深度学习新浪潮】谷歌新推出的AlphaEarth是款什么产品?
  • ZStack Cloud 5.3.40正式发布
  • 《测试驱动的React开发:从单元验证到集成协同的深度实践》
  • JAVA中的String类方法介绍
  • 【Bluetooth】【Transport层篇】第三章 基础的串口(UART)通信
  • 智能图书馆管理系统开发实战系列(六):Google Test单元测试实践
  • SAP 服务号传输(同环境的不同客户端SCC1,跨环境的STMS)
  • 一个网页的加载过程详解