mirror of
https://github.com/geekwenjie/SmartJavaAI.git
synced 2026-09-14 05:38:50 +00:00
1、新增图片与视频活体检测
2、新增人脸属性识别(性别、年龄、口罩、姿态、眼睛状态) 3、优化检测返回与包结构 4、新增 dependencyManagement 统一依赖版本管理
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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; // 默认返回未知
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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; // 默认返回未知
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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; // 默认返回未知
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user