「这是我参与11月更文挑战的第 8 天,活动详情查看:2021最后一次更文挑战」
1、前言
在前几次的分享中,我们说到了人脸识别、人脸库管理、批量同步人脸数据这几个功能,本次我们介绍下人脸检测功能的使用。人脸检测主要是为了检测照片中是否存在真实的人脸,并获取一些人脸附加数据,那么接口返回的信息主要有:1)照片中人脸的位置信息;2)人脸的关键点信息(即人脸特征坐标)3)人脸的年龄、性别等信息;4)照片中的人脸是否存在遮挡、置信度等。那么下面就来详细介绍下,实际开发应用以及遇到的一些问题。
2、人脸检测
1、首先当用户进行人脸识别后,会上传一张人脸照片,我们会先把照片存入服务器临时文件夹,然后加入到当前任务队列中,消费者依次去调用人脸检测接口。然后我们再根据返回信息,决定用户能否正常建档。判断的依据主要有:1)人脸各部分遮挡的概率;2)人脸模糊程度;3)真实人脸置信度;下面我们就结合代码详细说明下:
人脸检测代码:
/**
* 百度API 人脸检测
* */
public MessageModel imageDetect(String cert_id) {
try {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date dayStart=new Date();
AipFace client = createClient();
if (client == null) {
messageModel.setErrorCode(messageModel.constErrorCode);
messageModel.setErrMsg("创建人脸检测API失败");
return messageModel;
}
// 传入可选参数调用接口
HashMap<String, String> options = new HashMap<String, String>();
options.put("max_face_num", "10");
options.put("face_fields", "age,beauty,expression,gender,glasses,race,qualities");
Properties properties = ResourceUtil.getResourceProperties();
// 参数为本地图片路径
String path=properties.getProperty("common.photopath")+"temp/" + cert_id + ".jpg";
JSONObject res = client.detect(path, options);
getMillSecond(dayStart,end);
messageModel= getDetectResult(res);
if (messageModel.constOKCode.equals(messageModel.getErrorCode())) {//验证通过
//把图片从临时文件夹已到正式文件夹并删除临时文件夹文件
MessageModel msgModelMove =moveTotherFolders(cert_id);
if (msgModelMove.constErrorCode.equals(msgModelMove.getErrorCode())) {
RedisUtil.setStringEx("face_v_"+cert_id, RedisUtil.timeOutSeconds, msgModelMove.getErrMsg());
}
else {
RedisUtil.setStringEx("face_v_"+cert_id, RedisUtil.timeOutSeconds, "ok");
}
//将人脸信息加入到人脸库中 2021-10-13 10:29
MessageModel resMsg = faceDetectBaiDu.faceGroupComponent.addUser(cert_id, msgModelMove.getMsg());
if (StringUtils.isNotBlank(resMsg.getErrorCode())) {
//人脸注册失败 -> 将face_group_id重置为空
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("certId", cert_id);
paramMap.put("faceGroupId", StringUtils.EMPTY);
paramMap.put("faceUid", StringUtils.EMPTY);
paramMap.put("face_add_time", new Date());
faceDetectBaiDu.faceGroupMapper.updatePhotoInfoFaceGroupId(paramMap);
return resMsg;
}
}
else{//验证失败并删除临时文件夹文件
RedisUtil.setStringEx("face_v_"+cert_id, RedisUtil.timeOutSeconds, messageModel.getErrMsg());
}
//从临时文件夹中删除图片
File tempFile = new File(path);
if (tempFile.exists()) {
FileUtils.forceDelete(tempFile);
}
System.out.println(res.toString(2));
} catch (Exception e) {
Log4jUtil.logError.error("人脸检测失败:"+e);
RedisUtil.setStringEx("face_v_"+cert_id, RedisUtil.timeOutSeconds, "人脸检测失败");
}
return messageModel;
}
消费线程:
private static class MQQueueValidateRunnable implements Runnable {
public void run() {
while (true) {
try {
Properties properties = ResourceUtil.getResourceProperties();
String qpsServerName = properties.getProperty("face.qpsServerName");
String threadCount = RedisUtil.getHashMap("qps_cert_num", qpsServerName);
Log4jUtil.logInfo.info("qps_cert_num:"+threadCount);
if (threadCount == null) {
threadCount="1";
}
if (threadPoolExecutor == null) {
threadPoolExecutor =new ThreadPoolExecutor(20, 20, 1, TimeUnit.DAYS, queue);
}
for(int i=0;i<Integer.valueOf(threadCount);i++)
{
if (threadPoolExecutor.getActiveCount()<Integer.valueOf(threadCount)) {
String certID = RedisUtil.blpopList(mq_cert_validate_list);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
//System.out.println(df.format(new Date())+" "+certID);
Log4jUtil.logInfo.info(df.format(new Date())+" qpsServerName: "+qpsServerName+" threadCount: "+threadCount+", cert_id "+certID);
if (RedisUtil.errFlag.equals(certID)) {//出现异常错误
continue;
}
if (certID != null) {
MQCertValidateRunnable poolRunnable = new MQCertValidateRunnable(certID.toLowerCase());
threadPoolExecutor.execute(poolRunnable);
}
}
}
Thread.sleep(2100);
} catch (Exception e) {
Log4jUtil.logError.error("实现Runnable接口的类 身份证照验证队列执行错误:" + e);
}
}
}