|
@@ -19,6 +19,8 @@ public class BaiduApiHelper {
|
|
|
|
|
|
private final static Logger log = LoggerFactory.getLogger(BaiduApiHelper.class);
|
|
|
|
|
|
+ private static double expectFaceLivenessScore = 0.39d;
|
|
|
+
|
|
|
public static BaiduSession getAccessToken(String apiKey, String apiSecret) {
|
|
|
if (StringUtils.isBlank(apiKey)) {
|
|
|
throw new IllegalArgumentException("[BAIDU] apiKey must be not empty.");
|
|
@@ -62,7 +64,7 @@ public class BaiduApiHelper {
|
|
|
RequestBody formBody = FormBody.create(MediaType.parse(Constants.JSON_CONTENT_TYPE), jsonParams);
|
|
|
|
|
|
BaiduResponse response = callApi(requestUrl, formBody);
|
|
|
- return parseFaceDetectResult(response);
|
|
|
+ return parseFaceVerifyResult(response);
|
|
|
}
|
|
|
|
|
|
public static FaceResult faceVerifyUsePrivateApi(FaceVerifyProperties properties, String jsonParams) {
|
|
@@ -74,7 +76,7 @@ public class BaiduApiHelper {
|
|
|
RequestBody formBody = FormBody.create(MediaType.parse(Constants.JSON_CONTENT_TYPE), jsonParams);
|
|
|
|
|
|
BaiduResponse response = callApi(requestUrl, formBody);
|
|
|
- return parseFaceDetectResult(response);
|
|
|
+ return parseFaceVerifyResult(response);
|
|
|
}
|
|
|
|
|
|
public static FaceResult faceDetect(FaceVerifyProperties properties, String jsonParams) {
|
|
@@ -131,6 +133,58 @@ public class BaiduApiHelper {
|
|
|
return parseFaceCompareResult(response, expectFaceCompareScore);
|
|
|
}
|
|
|
|
|
|
+ private static FaceResult parseFaceVerifyResult(BaiduResponse response) {
|
|
|
+ FaceResult result = new FaceResult();
|
|
|
+ result.setFacePass(false);
|
|
|
+ result.setFaceScore(0d);
|
|
|
+ result.setFaceNum(0);
|
|
|
+ result.setJsonResult(new JsonHelper().style(Include.NON_NULL).toJson(response));
|
|
|
+
|
|
|
+ int errorCode = response.getError_code();
|
|
|
+ if (errorCode != 0) {
|
|
|
+ result.setApiNeedRetry(true);// 默认值
|
|
|
+ result.setError(errorCode + " - " + response.getError_msg());
|
|
|
+
|
|
|
+ if (errorCode == 222202 || errorCode == 222203 || errorCode == 222209 || errorCode == 222304) {
|
|
|
+ // 222202 图片中没有人脸
|
|
|
+ // 222203 无法解析人脸
|
|
|
+ // 222209 face token不存在
|
|
|
+ // 222304 图片尺寸太大
|
|
|
+
|
|
|
+ result.setApiNeedRetry(false);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 请求并发超限(约20QPS,可按需调整)
|
|
|
+ if (errorCode == 18) {
|
|
|
+ log.debug("baidu api qps limit...");
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaiduResult data = response.getResult();
|
|
|
+ if (data == null) {
|
|
|
+ result.setError(result.getJsonResult());
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ double faceLiveness = data.getFace_liveness() != null ? data.getFace_liveness() : 0d;
|
|
|
+ result.setFaceScore(faceLiveness);
|
|
|
+
|
|
|
+ // 注:该接口的faceNum值没多大参考意义!照片中包含多张人脸时,默认取人脸面积最大的人脸,返回face_list的元素数量总不会大于1。
|
|
|
+ int faceNum = data.getFace_list() != null ? data.getFace_list().size() : 0;
|
|
|
+ result.setFaceNum(faceNum);
|
|
|
+
|
|
|
+ // 活体分数值,推荐阈值0.393241
|
|
|
+ if (faceNum == 1 && faceLiveness >= expectFaceLivenessScore) {
|
|
|
+ result.setFacePass(true);
|
|
|
+ } else {
|
|
|
+ result.setError("人脸数量:" + faceNum + "; 真实性得分:" + faceLiveness + ",阈值:" + expectFaceLivenessScore);
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
private static FaceResult parseFaceDetectResult(BaiduResponse response) {
|
|
|
FaceResult result = new FaceResult();
|
|
|
result.setFacePass(false);
|
|
@@ -152,10 +206,10 @@ public class BaiduApiHelper {
|
|
|
result.setApiNeedRetry(false);
|
|
|
}
|
|
|
|
|
|
- // 请求并发超限(约10个/秒,可按需调整)
|
|
|
- /*if (errorCode == 18) {
|
|
|
- log.warn("facepp_api_limit...");
|
|
|
- }*/
|
|
|
+ // 请求并发超限(约20QPS,可按需调整)
|
|
|
+ if (errorCode == 18) {
|
|
|
+ log.debug("baidu api qps limit...");
|
|
|
+ }
|
|
|
|
|
|
return result;
|
|
|
}
|
|
@@ -168,29 +222,23 @@ public class BaiduApiHelper {
|
|
|
|
|
|
double faceLiveness = 0d;
|
|
|
List<BaiduFace> faces = data.getFace_list();
|
|
|
- if (data.getFace_liveness() != null) {
|
|
|
- faceLiveness = data.getFace_liveness();
|
|
|
- } else {
|
|
|
- if (faces != null && !faces.isEmpty()) {
|
|
|
- BaiduFace face = faces.get(0);
|
|
|
- if (face.getLiveness() != null && face.getLiveness().getLivemapscore() != null) {
|
|
|
- faceLiveness = face.getLiveness().getLivemapscore();
|
|
|
- }
|
|
|
+ if (faces != null && !faces.isEmpty()) {
|
|
|
+ BaiduFace face = faces.get(0);
|
|
|
+ if (face.getLiveness() != null && face.getLiveness().getLivemapscore() != null) {
|
|
|
+ faceLiveness = face.getLiveness().getLivemapscore();
|
|
|
}
|
|
|
}
|
|
|
result.setFaceScore(faceLiveness);
|
|
|
|
|
|
- if (data.getFace_num() != null) {
|
|
|
- result.setFaceNum(data.getFace_num());
|
|
|
- } else {
|
|
|
- result.setFaceNum(faces != null ? faces.size() : 0);
|
|
|
- }
|
|
|
+ // 注:照片中包含多张人脸时,优先取人脸面积最大的人脸,返回的face_list的最大数量由接口请求参数“max_face_num(默认值1)”的值限定。
|
|
|
+ int faceNum = faces != null ? faces.size() : 0;
|
|
|
+ result.setFaceNum(faceNum);
|
|
|
|
|
|
// 活体分数值,推荐阈值0.393241
|
|
|
- if (faceLiveness >= 0.39d) {
|
|
|
+ if (faceNum == 1 && faceLiveness >= expectFaceLivenessScore) {
|
|
|
result.setFacePass(true);
|
|
|
} else {
|
|
|
- result.setError("faceLiveness=" + faceLiveness + " but less than 0.39");
|
|
|
+ result.setError("人脸数量:" + faceNum + "; 人脸得分:" + faceLiveness + ",阈值:" + expectFaceLivenessScore);
|
|
|
}
|
|
|
|
|
|
return result;
|
|
@@ -221,10 +269,10 @@ public class BaiduApiHelper {
|
|
|
result.setApiNeedRetry(false);
|
|
|
}
|
|
|
|
|
|
- // 请求并发超限(约10个/秒,可按需调整)
|
|
|
- /*if (errorCode == 18) {
|
|
|
- log.warn("facepp_api_limit...");
|
|
|
- }*/
|
|
|
+ // 请求并发超限(约20QPS,可按需调整)
|
|
|
+ if (errorCode == 18) {
|
|
|
+ log.debug("baidu api qps limit...");
|
|
|
+ }
|
|
|
|
|
|
return result;
|
|
|
}
|
|
@@ -238,10 +286,11 @@ public class BaiduApiHelper {
|
|
|
double score = data.getScore() != null ? data.getScore() : 0d;
|
|
|
result.setFaceScore(score);
|
|
|
|
|
|
+ // 人脸相似度得分,推荐阈值80
|
|
|
if (score >= expectFaceCompareScore) {
|
|
|
result.setFacePass(true);
|
|
|
} else {
|
|
|
- result.setError("faceScore=" + score + " but less than " + expectFaceCompareScore);
|
|
|
+ result.setError("人脸相似度得分:" + score + ",阈值:" + expectFaceCompareScore);
|
|
|
}
|
|
|
|
|
|
return result;
|