Spring Boot集成腾讯云人脸识别实现智能小区门禁系统
本文介绍了基于SpringBoot集成腾讯云人员库的人脸识别门禁系统实现方案。系统采用前后端分离架构,前端实现拍照上传、小区选择等功能,后端通过FaceApi调用腾讯云AI接口进行人脸识别。核心功能包括:身份验证(相似度需≥80)、小区归属校验、生成出入记录(区分进入/离开状态)及保存人脸图片。系统主要包含出入记录控制器、表单处理和腾讯云接口封装三大模块,采用本地数据库存储出入记录和图片路径。关键
·
1. 项目概述
本文将介绍如何基于Spring Boot集成腾讯云人员库实现人脸识别门禁系统。系统功能包括:
- 前端拍照或上传人脸照片
- 调用腾讯云AI接口进行人脸识别
- 验证人员身份及小区归属
- 生成出入记录并保存人脸图片
- 数据库实时更新出入状态
2. 系统架构设计
前端页面 → Spring Boot后端 → 腾讯云AI接口 → 本地数据库
↑ ↑
人脸图片 出入记录
3. 前端页面实现
前端页面需要实现以下功能:
- 摄像头实时拍照功能
- 人脸图片上传功能
- 小区选择下拉菜单
- 识别结果展示区域
- 出入记录显示面板
4. 后端接口实现
4.1 出入记录控制器(InOurRecordController)
@PostMapping("/add")
public Result add(@RequestBody InOutForm inOutFaceForm) {
// 调用腾讯AI接口进行人脸识别
FaceApi faceApi = new FaceApi();
RootResp resp = faceApi.searchPersonsReturnsByGroup(
apiConfiguration,
inOutFaceForm.getFileBase64()
);
if (resp.getRet() != 0) {
return Result.error("人脸识别失败: " + resp.getMsg());
}
// 解析腾讯云返回数据
JSONObject result = parseTencentResponse(resp);
if (result == null) {
return Result.error("未识别到有效人脸信息");
}
// 验证人员身份和小区归属
Person person = validatePerson(result, inOutFaceForm.getCommunityId());
if (person == null) {
return Result.error("身份验证失败");
}
// 生成出入记录
return generateInOutRecord(inOutFaceForm, person);
}
// 解析腾讯云返回数据
private JSONObject parseTencentResponse(RootResp resp) {
JSONObject object = JSONObject.parseObject(resp.getData().toString());
JSONArray resultsReturnsByGroup = object.getJSONArray("ResultsReturnsByGroup");
JSONObject returnsByGroup = resultsReturnsByGroup.getJSONObject(0);
JSONArray groupCandidates = returnsByGroup.getJSONArray("GroupCandidates");
JSONObject groupCandidate = groupCandidates.getJSONObject(0);
JSONArray candidates = groupCandidate.getJSONArray("Candidates");
// 获取相似度最高的候选人
JSONObject candidate = candidates.getJSONObject(0);
if (candidate.getInteger("Score") < 80) {
return null; // 相似度过低
}
return candidate;
}
// 验证人员信息
private Person validatePerson(JSONObject candidate, Integer communityId) {
String personId = candidate.getString("PersonId").substring(4);
Person person = personService.getById(Long.parseLong(personId));
if (person == null) {
return null;
}
if (!communityId.equals(person.getCommunityId())) {
throw new BusinessException("非本小区居民");
}
return person;
}
// 生成出入记录
private Result generateInOutRecord(InOutForm form, Person person) {
InOutRecord record = new InOutRecord();
record.setCommunityId(person.getCommunityId());
record.setPersonId(person.getPersonId());
try {
// 保存人脸图片
String fileName = saveFaceImage(form.getFileBase64(), form.getExtName());
String imagePath = urlPrefix + "community/upload/face/" + fileName;
// 检查现有记录
InOutRecord existingRecord = inOutRecordMapper.getInOutRecord(record);
if (existingRecord == null) {
// 进入记录
record.setInTime(LocalDateTime.now());
record.setInPic(imagePath);
inOutRecordMapper.insert(record);
return Result.ok("【" + person.getUserName() + "】进入小区");
} else {
// 离开记录
existingRecord.setOutTime(LocalDateTime.now());
existingRecord.setOutPic(imagePath);
inOutRecordMapper.updateById(existingRecord);
return Result.ok("【" + person.getUserName() + "】离开小区");
}
} catch (Exception e) {
logger.error("记录生成失败", e);
return Result.error("系统异常");
}
}
// 保存图片到本地
private String saveFaceImage(String base64Data, String extName) {
String fileName = UUID.randomUUID() + "." + extName;
Base64Util.decoderBase64File(base64Data, faceImagePath + fileName);
return fileName;
}
4.2 出入记录表单(InOutForm)
@Data
public class InOutForm {
private Integer communityId; // 小区ID
private String extName; // 图片扩展名
private String fileBase64; // Base64编码的图片数据
}
5. 腾讯云接口封装(FaceApi)
5.1 关键方法:人员搜索
public RootResp searchPersonsReturnsByGroup(ApiConfiguration config, String image) {
RootResp result = new RootResp();
try {
Credential cred = new Credential(config.getSecretId(), config.getSecretKey());
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint(config.getServerIp());
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
IaiClient client = new IaiClient(cred, config.getArea(), clientProfile);
JSONObject paramObj = new JSONObject();
paramObj.put("GroupIds", new String[]{config.getGroupId()});
paramObj.put("Image", image);
paramObj.put("MaxPersonNumPerGroup", 5); // 返回最相似的5个候选人
paramObj.put("NeedPersonInfo", 1); // 返回人员详细信息
paramObj.put("MaxFaceNum", 1); // 最多识别1张人脸
SearchFacesReturnsByGroupRequest req = SearchFacesReturnsByGroupRequest.fromJsonString(
paramObj.toJSONString(),
SearchFacesReturnsByGroupRequest.class
);
SearchFacesReturnsByGroupResponse resp = client.SearchFacesReturnsByGroup(req);
result.setData(SearchFacesReturnsByGroupResponse.toJsonString(resp));
} catch (TencentCloudSDKException e) {
result.setRet(-1);
result.setMsg(e.toString());
logger.error("腾讯云接口调用失败", e);
}
return result;
}
6. 数据库设计与关键SQL
6.1 出入记录表(in_out_record)
字段 | 类型 | 描述 |
---|---|---|
id | BIGINT | 主键ID |
community_id | INT | 小区ID |
person_id | BIGINT | 人员ID |
in_time | DATETIME | 进入时间 |
out_time | DATETIME | 离开时间 |
in_pic | VARCHAR(255) | 进入时照片路径 |
out_pic | VARCHAR(255) | 离开时照片路径 |
6.2 关键SQL:判断进出状态
<select id="getInOutRecord" resultType="com.qcby.AICommunity.entity.InOutRecord">
SELECT * FROM in_out_record
WHERE community_id = #{communityId}
AND person_id = #{personId}
AND out_time IS NULL
</select>
更多推荐
所有评论(0)