1、新增图片与视频活体检测

2、新增人脸属性识别(性别、年龄、口罩、姿态、眼睛状态)
3、优化检测返回与包结构
4、新增 dependencyManagement 统一依赖版本管理
This commit is contained in:
dengwenjie
2025-05-09 20:10:04 +08:00
parent 42d2943a94
commit bef574cb91
63 changed files with 3266 additions and 382 deletions

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>cn.smartjavaai</groupId>
<artifactId>smartjavaai-parent</artifactId>
<version>1.0.11</version>
<version>1.0.12</version>
</parent>
<artifactId>smartjavaai-common</artifactId>

View File

@@ -0,0 +1,53 @@
package cn.smartjavaai.common.entity;
import lombok.Data;
/**
* 检测结果信息
* @author dwj
* @date 2025/5/7
*/
@Data
public class DetectionInfo {
/**
* 检测位置信息
*/
private DetectionRectangle detectionRectangle;
/**
* 检测得分
*/
private float score;
/**
* 人脸信息
*/
private FaceInfo faceInfo;
/**
* 目标检测信息
*/
private ObjectDetInfo objectDetInfo;
public DetectionInfo() {
}
public DetectionInfo(DetectionRectangle detectionRectangle) {
this.detectionRectangle = detectionRectangle;
}
public DetectionInfo(DetectionRectangle detectionRectangle, float score) {
this.detectionRectangle = detectionRectangle;
this.score = score;
}
public DetectionInfo(DetectionRectangle detectionRectangle, float score, FaceInfo faceInfo) {
this.detectionRectangle = detectionRectangle;
this.score = score;
this.faceInfo = faceInfo;
}
}

View File

@@ -1,98 +1,30 @@
package cn.smartjavaai.common.entity;
import cn.smartjavaai.common.enums.GenderType;
import cn.smartjavaai.common.enums.LivenessStatus;
import lombok.Data;
import java.util.List;
/**
* 检测结果-矩形区域
* @author dwj
*/
@Data
public class DetectionRectangle {
public int x;
public int y;
public int width;
public int height;
public float score;
public String className;
/**
* 人脸关键点
*/
private List<Point> keyPoints;
public DetectionRectangle() {
}
public DetectionRectangle(int x, int y, int width, int height, float score) {
public DetectionRectangle(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.score = score;
}
public DetectionRectangle(int x, int y, int width, int height, float score, String className) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.score = score;
this.className = className;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public float getScore() {
return score;
}
public void setScore(float score) {
this.score = score;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public List<Point> getKeyPoints() {
return keyPoints;
}
public void setKeyPoints(List<Point> keyPoints) {
this.keyPoints = keyPoints;
}
}

View File

@@ -1,5 +1,7 @@
package cn.smartjavaai.common.entity;
import lombok.Data;
import java.util.List;
/**
@@ -7,15 +9,15 @@ import java.util.List;
* @author dwj
* @date 2025/4/12
*/
@Data
public class DetectionResponse {
private List<DetectionRectangle> rectangleList;
private List<DetectionInfo> detectionInfoList;
public List<DetectionRectangle> getRectangleList() {
return rectangleList;
public DetectionResponse() {
}
public void setRectangleList(List<DetectionRectangle> rectangleList) {
this.rectangleList = rectangleList;
public DetectionResponse(List<DetectionInfo> detectionInfoList) {
this.detectionInfoList = detectionInfoList;
}
}

View File

@@ -0,0 +1,50 @@
package cn.smartjavaai.common.entity;
import cn.smartjavaai.common.enums.EyeStatus;
import cn.smartjavaai.common.enums.GenderType;
import lombok.Data;
/**
* 人脸属性
* @author dwj
* @date 2025/5/7
*/
@Data
public class FaceAttribute {
/**
* 性别
*/
private GenderType genderType;
/**
* 年龄
*/
private Integer age;
/**
* 左眼状态
*/
private EyeStatus leftEyeStatus;
/**
* 右眼状态
*/
private EyeStatus rightEyeStatus;
/**
* 是否带口罩
*/
private Boolean wearingMask;
/**
* 姿态
*/
private HeadPose headPose;
public FaceAttribute() {
}
}

View File

@@ -0,0 +1,48 @@
package cn.smartjavaai.common.entity;
import cn.smartjavaai.common.enums.LivenessStatus;
import lombok.Data;
import java.util.List;
/**
* 人脸信息
* @author dwj
* @date 2025/5/7
*/
@Data
public class FaceInfo {
/**
* 人脸关键点
*/
private List<Point> keyPoints;
/**
* 人脸属性
*/
private FaceAttribute faceAttribute;
/**
* 活体检测结果
*/
private LivenessStatus livenessStatus;
public FaceInfo() {
}
public FaceInfo(List<Point> keyPoints) {
this.keyPoints = keyPoints;
}
public FaceInfo(List<Point> keyPoints, FaceAttribute faceAttribute, LivenessStatus livenessStatus) {
this.keyPoints = keyPoints;
this.faceAttribute = faceAttribute;
this.livenessStatus = livenessStatus;
}
public FaceInfo(FaceAttribute faceAttribute, LivenessStatus livenessStatus) {
this.faceAttribute = faceAttribute;
this.livenessStatus = livenessStatus;
}
}

View File

@@ -0,0 +1,32 @@
package cn.smartjavaai.common.entity;
import lombok.Data;
/**
* 姿态检测结果(单位:度)
* pitch上下俯仰角正值抬头负值低头
* yaw左右偏航角正值右偏负值左偏
* roll倾斜翻滚角正值右倾负值左倾
*/
@Data
public class HeadPose {
/** 俯仰角:头上下抬(-90°~+90° */
private Float pitch;
/** 偏航角:头左右转(-90°~+90° */
private Float yaw;
/** 翻滚角:头部倾斜(-90°~+90° */
private Float roll;
public HeadPose() {
}
public HeadPose(Float pitch, Float yaw, Float roll) {
this.pitch = pitch;
this.yaw = yaw;
this.roll = roll;
}
}

View File

@@ -0,0 +1,22 @@
package cn.smartjavaai.common.entity;
import cn.smartjavaai.common.enums.LivenessStatus;
import lombok.Data;
/**
* 目标检测信息
* @author dwj
* @date 2025/5/7
*/
@Data
public class ObjectDetInfo {
private String className;
public ObjectDetInfo() {
}
public ObjectDetInfo(String className) {
this.className = className;
}
}

View File

@@ -0,0 +1,42 @@
package cn.smartjavaai.common.enums;
/**
* 眼睛状态
* @author dwj
* @date 2025/5/7
*/
public enum EyeStatus {
OPEN(0, "睁眼"),
CLOSED(1, "闭眼"),
NON_EYE_REGION(2, "非眼部区域"),
UNKNOWN(3, "未知状态");
private final int code;
private final String description;
EyeStatus(int code, String description) {
this.code = code;
this.description = description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
public static EyeStatus fromCode(int code) {
for (EyeStatus status : EyeStatus.values()) {
if (status.getCode() == code) {
return status;
}
}
return UNKNOWN; // 默认返回未知
}
}

View File

@@ -0,0 +1,40 @@
package cn.smartjavaai.common.enums;
/**
* 性别枚举
* @author dwj
* @date 2025/5/6
*/
public enum GenderType {
MALE(0, ""),
FEMALE(1, ""),
UNKNOWN(2, "未知");
private final int code;
private final String description;
GenderType(int code, String description) {
this.code = code;
this.description = description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
public static GenderType fromCode(int code) {
for (GenderType status : GenderType.values()) {
if (status.getCode() == code) {
return status;
}
}
return UNKNOWN; // 默认返回未知
}
}

View File

@@ -0,0 +1,40 @@
package cn.smartjavaai.common.enums;
/**
* 活体检测结果
* @author dwj
* @date 2025/4/29
*/
public enum LivenessStatus {
LIVE(0, "活体"),
NON_LIVE(1, "非活体"),
UNKNOWN(2, "未知"),
DETECTING(3, "正在检测");
private final int code;
private final String description;
LivenessStatus(int code, String description) {
this.code = code;
this.description = description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
public static LivenessStatus fromCode(int code) {
for (LivenessStatus status : LivenessStatus.values()) {
if (status.getCode() == code) {
return status;
}
}
return UNKNOWN; // 默认返回未知
}
}

View File

@@ -145,41 +145,6 @@ public class ImageUtils {
}
}
/**
* 画检测框
*
* @param image
* @param x
* @param y
* @param width
* @param height
*/
public static void drawImageRect(Image image, DetectionResponse detectionResponse) {
if(Objects.nonNull(detectionResponse) && Objects.nonNull(detectionResponse.getRectangleList()) && !detectionResponse.getRectangleList().isEmpty()){
// 将绘制图像转换为Graphics2D'
BufferedImage bufferedImage = (BufferedImage)image.getWrappedImage();
Graphics2D g = (Graphics2D) bufferedImage.getGraphics();
try {
g.setColor(new Color(0, 255, 0));
// 声明画笔属性 :粗 细(单位像素)末端无修饰 折线处呈尖角
BasicStroke bStroke = new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
g.setStroke(bStroke);
for(DetectionRectangle detectionRectangle : detectionResponse.getRectangleList()){
g.drawRect(detectionRectangle.getX(), detectionRectangle.getY(), detectionRectangle.getWidth(), detectionRectangle.getHeight());
}
} finally {
g.dispose();
}
}
}
}

View File

@@ -0,0 +1,25 @@
package cn.smartjavaai.common.utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.ObjectPool;
/**
* @author dwj
* @date 2025/5/7
*/
@Slf4j
public class PoolUtils {
// 泛型方法,支持任意类型的 Predictor 和对象池
public static <T> void returnToPool(ObjectPool<T> pool, T predictor) {
if (pool == null || predictor == null) {
return;
}
try {
pool.returnObject(predictor);
} catch (Exception e) {
log.warn("归还Predictor到池失败", e);
}
}
}