├── .idea
├── compiler.xml
├── encodings.xml
├── misc.xml
└── vcs.xml
├── README.md
├── pom.xml
├── spd.iml
└── src
├── main
└── java
│ ├── algorithm
│ └── AlgorithmUtil.java
│ ├── detector
│ ├── Detector.java
│ └── impl
│ │ ├── HeadDetector.java
│ │ └── UpperBodyDetector.java
│ ├── model
│ ├── Angle.java
│ ├── HeadInfo.java
│ ├── Location.java
│ ├── Point.java
│ ├── SittingPosition.java
│ ├── SittingPositionParam.java
│ ├── SpdImage.java
│ └── UpperBodyInfo.java
│ ├── service
│ ├── SittingPositionDetection.java
│ └── impl
│ │ ├── DeepLearningSittingPosition.java
│ │ └── SimpleSittingPositionDetection.java
│ └── spd
│ └── Spd.java
└── test
└── java
└── detector
└── impl
└── HeadDetectorTest.java
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # spd
2 | spd是sitting position detection的缩写
3 | spd是一套基于Baidu AI成熟的人脸检测和人体分析接口实现的一套坐姿识别工具
4 |
5 | # 算法思路
6 | 本项目参考了知网中的一篇论文并针对具体应用调整了部分参数。
7 | 该项目的最初目的是为了实验室的项目服务。
8 |
9 | # 开始使用
10 | 你可以参考下面的测试类,了解如何使用,我们对细节进行了高度的封装,只暴露了一个接口。
11 |
12 | ```
13 | public class Test{
14 |
15 |
16 | public static void main(String[] args) throws FileNotFoundException {
17 | HashMap config1=new HashMap();
18 | config1.put("appId","xxxxxx");
19 | config1.put("apiKey","xxxxxxxx");
20 | config1.put("secretKey","xxxxxxxx");
21 |
22 | HashMap config2=new HashMap();
23 | config2.put("appId","xxxxxx");
24 | config2.put("apiKey","xxxxxxx");
25 | config2.put("secretKey","xxxxxxxxx");
26 |
27 | Spd spd=Spd.getInstance(config1,config2);
28 | String base=getImageStr("/home/zeng/IdeaProjects/spd/src/main/resources/test7.jpg");
29 |
30 | //获取图片base64编码信息
31 | //。。。
32 | long s1=System.currentTimeMillis();
33 | SittingPosition sittingPosition=spd.getSittingPosition(1,base);
34 | long s2=System.currentTimeMillis();
35 | System.out.println((s2-s1)+"ms");
36 | System.out.println(sittingPosition);
37 | }
38 |
39 | public static String getImageStr(String imgFile)
40 | {//将图片文件转化为字节数组字符串,并对其进行Base64编码处理
41 | InputStream in = null;
42 | byte[] data = null;
43 | //读取图片字节数组
44 | try
45 | {
46 | in = new FileInputStream(imgFile);
47 | data = new byte[in.available()];
48 | in.read(data);
49 | in.close();
50 | }
51 | catch (IOException e)
52 | {
53 | e.printStackTrace();
54 | }
55 | //对字节数组Base64编码
56 | BASE64Encoder encoder = new BASE64Encoder();
57 | return encoder.encode(data);//返回Base64编码过的字节数组字符串
58 | }
59 | }
60 | ```
61 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | cn.finalabproject
8 | spd
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 | com.baidu.aip
14 | java-sdk
15 | 4.3.2
16 |
17 |
18 |
19 | com.baidu.aip
20 | java-sdk
21 | 4.8.0
22 |
23 |
24 |
25 | org.projectlombok
26 | lombok
27 | 1.16.20
28 | provided
29 |
30 |
31 |
32 | junit
33 | junit
34 | 4.12
35 | test
36 |
37 |
38 |
39 |
40 | com.google.code.gson
41 | gson
42 | 2.8.5
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/spd.iml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/main/java/algorithm/AlgorithmUtil.java:
--------------------------------------------------------------------------------
1 | package algorithm;
2 |
3 | public class AlgorithmUtil {
4 | // public static Double
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/detector/Detector.java:
--------------------------------------------------------------------------------
1 | package detector;
2 |
3 | import model.SpdImage;
4 |
5 | public interface Detector {
6 | public boolean init(String appId,String apiKey,String secretKey);
7 |
8 | public Object detection(SpdImage spdImage) throws Exception;
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/detector/impl/HeadDetector.java:
--------------------------------------------------------------------------------
1 | package detector.impl;
2 |
3 | import com.baidu.aip.face.AipFace;
4 | import com.google.gson.Gson;
5 | import detector.Detector;
6 | import model.Angle;
7 | import model.HeadInfo;
8 | import model.Location;
9 | import model.SpdImage;
10 | import org.json.JSONArray;
11 | import org.json.JSONObject;
12 |
13 | import java.util.HashMap;
14 |
15 | /**
16 | * 头部检测器
17 | * @author zeng
18 | */
19 | public class HeadDetector implements Detector {
20 | private AipFace client=null;
21 | private boolean state=false;
22 | private static HeadDetector headDetector=new HeadDetector();
23 |
24 | private HeadDetector(){
25 |
26 | }
27 |
28 | public static HeadDetector getHeadDetecto(){
29 | return headDetector;
30 | }
31 |
32 | public boolean init(String appId, String apiKey, String secretKey) {
33 | client=new AipFace(appId,apiKey,secretKey);
34 | if (client!=null){
35 | state=true;
36 | }
37 | return state;
38 | }
39 |
40 | public HeadInfo detection(SpdImage spdImage) throws Exception {
41 | HeadInfo headInfo=new HeadInfo();
42 | if (!state){
43 | throw new Exception("检测器初始化失败!");
44 | }
45 | try {
46 | JSONObject ret=client.detect(spdImage.getImage(),spdImage.getType(),new HashMap());
47 |
48 | JSONObject result= (JSONObject) ret.get("result");
49 |
50 | JSONArray faceList= (JSONArray) result.get("face_list");
51 |
52 | if (faceList.length()<=0){
53 | return null;
54 | }
55 | //获取人脸信息
56 | JSONObject faceInfo=faceList.getJSONObject(0);
57 |
58 | //获取3d旋转角度
59 | JSONObject angle= (JSONObject) faceInfo.get("angle");
60 | JSONObject location=(JSONObject)faceInfo.get("location");
61 | Gson gson=new Gson();
62 |
63 | if (angle!=null){
64 | Angle angle1=gson.fromJson(angle.toString(), Angle.class);
65 | headInfo.setAngel(angle1);
66 | }else {
67 | return null;
68 | }
69 | if (location!=null){
70 | System.out.println(location);
71 | Location location1=gson.fromJson(location.toString(),Location.class);
72 | headInfo.setLocation(location1);
73 | }else {
74 | return null;
75 | }
76 | }catch (Exception e){
77 | return null;
78 | }
79 | return headInfo;
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/detector/impl/UpperBodyDetector.java:
--------------------------------------------------------------------------------
1 | package detector.impl;
2 |
3 |
4 | import com.baidu.aip.bodyanalysis.AipBodyAnalysis;
5 | import com.baidu.aip.util.Base64Util;
6 | import com.google.gson.Gson;
7 | import detector.Detector;
8 | import model.Point;
9 | import model.SpdImage;
10 | import model.UpperBodyInfo;
11 | import org.json.JSONArray;
12 | import org.json.JSONObject;
13 |
14 | import javax.imageio.stream.FileImageInputStream;
15 | import java.io.ByteArrayOutputStream;
16 | import java.io.File;
17 | import java.io.FileNotFoundException;
18 | import java.io.IOException;
19 | import java.util.HashMap;
20 |
21 | /**
22 | * 上身检测器
23 | * @author zeng
24 | */
25 | public class UpperBodyDetector implements Detector {
26 | AipBodyAnalysis client=null;
27 | private boolean state=false;
28 | Gson gson=new Gson();
29 | JSONObject bodyParts=null;
30 | JSONObject location=null;
31 | private static UpperBodyDetector upperBodyDetector=new UpperBodyDetector();
32 |
33 | private UpperBodyDetector(){
34 |
35 | }
36 |
37 | public static UpperBodyDetector getUpperBodyDetector(){
38 | return upperBodyDetector;
39 | }
40 | public boolean init(String appId, String apiKey, String secretKey) {
41 | client=new AipBodyAnalysis(appId,apiKey,secretKey);
42 | if (client==null){
43 | return false;
44 | }
45 | state=true;
46 | return true;
47 | }
48 |
49 | public UpperBodyInfo detection(SpdImage spdImage) throws Exception {
50 | if (!state){
51 | return null;
52 | }
53 | UpperBodyInfo upperBodyInfo=new UpperBodyInfo();
54 | upperBodyInfo.setWidth(spdImage.getWidth());
55 | upperBodyInfo.setHeight(spdImage.getHeight());
56 |
57 | byte[] bytes=spdImage.getImageArr();
58 | JSONObject ret=client.bodyAnalysis(bytes,new HashMap());
59 | System.out.println(ret);
60 | if (ret==null||ret.get("person_info")==null){
61 | return null;
62 | }
63 | JSONArray jsonArray= (JSONArray) ret.get("person_info");
64 | if (jsonArray.length()<=0){
65 | return null;
66 | }
67 | JSONObject personInfo=jsonArray.getJSONObject(0);
68 |
69 | bodyParts= (JSONObject) personInfo.get("body_parts");
70 | location=(JSONObject)personInfo.get("location");
71 |
72 | double height=(Double)location.get("height");
73 | double width=(Double) location.get("width");
74 |
75 | upperBodyInfo.setBodyHeight(height);
76 | upperBodyInfo.setBodyWidth(width);
77 | Point nose=getKeyPoint("nose");
78 | Point neck=getKeyPoint("neck");
79 |
80 | Point leftShoulder=getKeyPoint("left_shoulder");
81 | Point rightShoulder=getKeyPoint("right_shoulder");
82 |
83 | Point leftElbow=getKeyPoint("left_elbow");
84 | Point rightElbow=getKeyPoint("right_elbow");
85 |
86 | Point leftWrist=getKeyPoint("left_wrist");
87 | Point rightWrist=getKeyPoint("right_wrist");
88 |
89 | upperBodyInfo.setNose(nose);
90 | upperBodyInfo.setNeck(neck);
91 |
92 | upperBodyInfo.setLeftShoulder(leftShoulder);
93 | upperBodyInfo.setRightShoulder(rightShoulder);
94 |
95 | upperBodyInfo.setLeftElbow(leftElbow);
96 | upperBodyInfo.setRightElbow(rightElbow);
97 |
98 | upperBodyInfo.setLeftWrist(leftWrist);
99 | upperBodyInfo.setRightWrist(rightWrist);
100 |
101 | return upperBodyInfo;
102 | }
103 |
104 | public Point getKeyPoint(String key){
105 | Point point=null;
106 | String jsonNose=bodyParts.get(key).toString();
107 | point=gson.fromJson(jsonNose, Point.class);
108 | return point;
109 | }
110 |
111 | //图片到byte数组
112 | public byte[] image2byte(String path){
113 | byte[] data = null;
114 | FileImageInputStream input = null;
115 | try {
116 | input = new FileImageInputStream(new File(path));
117 | ByteArrayOutputStream output = new ByteArrayOutputStream();
118 | byte[] buf = new byte[1024];
119 | int numBytesRead = 0;
120 | while ((numBytesRead = input.read(buf)) != -1) {
121 | output.write(buf, 0, numBytesRead);
122 | }
123 | data = output.toByteArray();
124 | output.close();
125 | input.close();
126 | }
127 | catch (FileNotFoundException ex1) {
128 | ex1.printStackTrace();
129 | }
130 | catch (IOException ex1) {
131 | ex1.printStackTrace();
132 | }
133 | return data;
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/main/java/model/Angle.java:
--------------------------------------------------------------------------------
1 | package model;
2 |
3 | import lombok.Getter;
4 | import lombok.Setter;
5 |
6 | @Getter
7 | @Setter
8 | public class Angle {
9 | private Double roll;
10 | private Double pitch;
11 | private Double yaw;
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/model/HeadInfo.java:
--------------------------------------------------------------------------------
1 | package model;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.NoArgsConstructor;
6 | import lombok.Setter;
7 |
8 |
9 | /**
10 | * 描述头部信息
11 | * @author zeng
12 | */
13 | @Getter
14 | @Setter
15 | @AllArgsConstructor
16 | @NoArgsConstructor
17 | public class HeadInfo {
18 | //参考宽度
19 | private Integer width;
20 | //参考高度
21 | private Integer height;
22 | //人脸位置
23 | private Location location;
24 | //人脸旋转角度参数
25 | private Angle angel;
26 | //人脸可信度
27 | private Double probability;
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/model/Location.java:
--------------------------------------------------------------------------------
1 | package model;
2 |
3 | import lombok.Getter;
4 | import lombok.Setter;
5 |
6 | @Setter
7 | @Getter
8 | public class Location {
9 | private Double top;
10 | private Double left;
11 | private Double rotation;
12 | private Double width;
13 | private Double height;
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/model/Point.java:
--------------------------------------------------------------------------------
1 | package model;
2 |
3 | import lombok.Getter;
4 | import lombok.Setter;
5 |
6 | @Setter
7 | @Getter
8 | public class Point {
9 | private Double x;
10 | private Double y;
11 | @Override
12 | public String toString() {
13 | return "("+this.x+","+this.y+")";
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/model/SittingPosition.java:
--------------------------------------------------------------------------------
1 | package model;
2 | /**
3 | * 坐姿数据
4 | * @author zeng
5 | */
6 | public class SittingPosition {
7 | private int id;
8 | private int uid;
9 | /**
10 | * 0 正常
11 | * 1 头左偏
12 | * 2 头右偏
13 | * 3 左手错误放置
14 | * 4 右手错误放置
15 | * 5 身体倾斜
16 | * 6 趴桌
17 | */
18 | private int status;
19 | private double degree;
20 |
21 | public int getId() {
22 | return id;
23 | }
24 |
25 | public void setId(int id) {
26 | this.id = id;
27 | }
28 |
29 | public int getUid() {
30 | return uid;
31 | }
32 |
33 | public void setUid(int uid) {
34 | this.uid = uid;
35 | }
36 |
37 | public int getStatus() {
38 | return status;
39 | }
40 |
41 | public void setStatus(int status) {
42 | this.status = status;
43 | }
44 |
45 | public double getDegree() {
46 | return degree;
47 | }
48 |
49 | public void setDegree(double degree) {
50 | this.degree = degree;
51 | }
52 |
53 | @Override
54 | public String toString() {
55 | return "SittingPosition{" +
56 | "id=" + id +
57 | ", uid=" + uid +
58 | ", status=" + status +
59 | ", degree=" + degree +
60 | '}';
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/model/SittingPositionParam.java:
--------------------------------------------------------------------------------
1 | package model;
2 |
3 | /**
4 | * 描述坐姿信息的参照值
5 | */
6 | public class SittingPositionParam {
7 | //边界1:左偏30度
8 | public static final Integer HEAD_LEFT_ROTATION=12;
9 | //边界2:右偏30度
10 | public static final Integer HEAD_RIGHT_ROTATION=-12;
11 | //
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/model/SpdImage.java:
--------------------------------------------------------------------------------
1 | package model;
2 |
3 |
4 | import com.baidu.aip.util.Base64Util;
5 | import sun.misc.BASE64Decoder;
6 |
7 | /**
8 | * 统一图片形式
9 | */
10 | public class SpdImage {
11 | public final static String URL="URL";
12 | public final static String BASE64="BASE64";
13 |
14 |
15 | private Integer width;
16 | private Integer height;
17 |
18 | private String image=null;
19 | private String type=SpdImage.BASE64;
20 |
21 | public SpdImage(){
22 |
23 | }
24 |
25 | public SpdImage(String image){
26 | this.image=image;
27 | }
28 |
29 | public String getImage(){
30 | return image;
31 | }
32 |
33 | public String getType(){
34 | return type;
35 | }
36 |
37 | public byte[] getImageArr() {
38 | BASE64Decoder base64Decoder=new BASE64Decoder();
39 | byte[] bytes=null;
40 | try {
41 | bytes=base64Decoder.decodeBuffer(image);
42 | }catch (Exception e){
43 | e.printStackTrace();
44 | }
45 |
46 | return bytes;
47 | }
48 |
49 | public Integer getWidth() {
50 | return width;
51 | }
52 |
53 | public Integer getHeight() {
54 | return height;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/model/UpperBodyInfo.java:
--------------------------------------------------------------------------------
1 | package model;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.NoArgsConstructor;
6 | import lombok.Setter;
7 |
8 | /**
9 | * 描述上半身信息
10 | * @author zeng
11 | */
12 | @Getter
13 | @Setter
14 | @AllArgsConstructor
15 | @NoArgsConstructor
16 | public class UpperBodyInfo {
17 | //参考宽度
18 | private Integer width;
19 |
20 | //参考高度
21 | private Integer height;
22 |
23 | //关键点1 鼻子
24 | private Point nose;
25 |
26 | //关键点2 颈部
27 | private Point neck;
28 |
29 | //关键点3 左肩
30 | private Point leftShoulder;
31 |
32 | //关键点4 右肩
33 | private Point rightShoulder;
34 |
35 | //关键点5 左手肘
36 | private Point leftElbow;
37 |
38 | //关键点6 右手肘
39 | private Point rightElbow;
40 |
41 | //关键点7 左手腕
42 | private Point leftWrist;
43 |
44 | //关键点8 右手腕
45 | private Point rightWrist;
46 |
47 | private double bodyWidth;
48 |
49 | private double bodyHeight;
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/service/SittingPositionDetection.java:
--------------------------------------------------------------------------------
1 | package service;
2 |
3 | import model.HeadInfo;
4 | import model.SittingPosition;
5 | import model.UpperBodyInfo;
6 |
7 | /**
8 | * 坐姿检测
9 | */
10 | public interface SittingPositionDetection {
11 | public SittingPosition getSittingPosition(HeadInfo headInfo, UpperBodyInfo upperBodyInfo);
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/service/impl/DeepLearningSittingPosition.java:
--------------------------------------------------------------------------------
1 | package service.impl;
2 |
3 | import model.HeadInfo;
4 | import model.SittingPosition;
5 | import model.UpperBodyInfo;
6 | import service.SittingPositionDetection;
7 |
8 | /**
9 | * 具有深度学习能力的坐姿检测服务
10 | */
11 | public class DeepLearningSittingPosition implements SittingPositionDetection {
12 | public SittingPosition getSittingPosition(HeadInfo headInfo, UpperBodyInfo upperBodyInfo) {
13 | return null;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/service/impl/SimpleSittingPositionDetection.java:
--------------------------------------------------------------------------------
1 | package service.impl;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.NoArgsConstructor;
6 | import lombok.Setter;
7 | import model.*;
8 | import service.SittingPositionDetection;
9 |
10 | /**
11 | * 该坐姿检测程序的理论来源于知网的一篇论文的数据,准确性达到百分之90左右
12 | */
13 | public class SimpleSittingPositionDetection implements SittingPositionDetection {
14 |
15 | /**
16 | * 基于头部信息和人体关键点获取坐姿信息
17 | * @param headInfo
18 | * @param upperBodyInfo
19 | * @return
20 | */
21 | public SittingPosition getSittingPosition(HeadInfo headInfo, UpperBodyInfo upperBodyInfo) {
22 | SittingPosition sittingPosition=new SittingPosition();
23 | //数据修复,保证数据残缺时可以得到有效数据
24 |
25 | UnderarmData underarmData=new UnderarmData();
26 | BodySlant bodySlant=new BodySlant();
27 | HandPosition handPosition=new HandPosition();
28 | HeadSlant headSlant=new HeadSlant();
29 |
30 | if (upperBodyInfo!=null){
31 | //1. 获取是否趴桌
32 | underarmData=analysisUnderarm(upperBodyInfo);
33 | //2. 身体是否倾斜
34 | bodySlant=analysisBodySlant(upperBodyInfo);
35 | //4. 获取手部位置
36 | handPosition=analysisHandPosition(upperBodyInfo);
37 | }
38 | if (headInfo!=null){
39 | //3. 获取头部偏离
40 | headSlant=analysisHeadSlantData(headInfo);
41 | }
42 |
43 |
44 |
45 |
46 | //获取标志性错误(错误最大最明显)
47 | if (underarmData.isUnderarm){
48 | sittingPosition.setStatus(6);
49 | sittingPosition.setDegree(underarmData.getDegree());
50 | return sittingPosition;
51 | }else if (bodySlant.isBodySlant){
52 | sittingPosition.setStatus(5);
53 | sittingPosition.setDegree(bodySlant.getDegree());
54 | return sittingPosition;
55 | }else if (headSlant.isSlant){
56 | if (headSlant.getDirection()==Direction.LEFT){
57 | sittingPosition.setStatus(1);
58 | sittingPosition.setDegree(1);
59 | return sittingPosition;
60 | }else {
61 | sittingPosition.setStatus(2);
62 | sittingPosition.setDegree(1);
63 | return sittingPosition;
64 | }
65 | }else {
66 | sittingPosition.setStatus(0);
67 | sittingPosition.setDegree(0);
68 | return sittingPosition;
69 | }
70 | }
71 |
72 | /**
73 | * 百度返回的数据中包含了人脸3d角度的偏移,可以直接通过参数判断头部是否偏了
74 | * 判断头部偏离系数,范围为[0,1],当返回值为0时,表示头部未发生偏离,
75 | * @param headInfo
76 | * @return 偏离系数
77 | */
78 | private static HeadSlant analysisHeadSlantData(HeadInfo headInfo){
79 | Double rotation=headInfo.getLocation().getRotation();
80 | int flag=rotation>0?1:-1;
81 | rotation=Math.abs(rotation);
82 |
83 | //判断是否在合理的范围内
84 | if(rotation<=SittingPositionParam.HEAD_LEFT_ROTATION){
85 | return new HeadSlant(false,Direction.NO,0);//没有偏离
86 | }
87 |
88 | HeadSlant slantData=new HeadSlant();
89 | slantData.setDegree(rotation*(1.0/78)-(12.0/78));
90 | slantData.setSlant(true);
91 | if (flag==1){
92 | slantData.setDirection(Direction.LEFT);
93 | }else {
94 | slantData.setDirection(Direction.RIGHT);
95 | }
96 | return slantData;
97 | }
98 |
99 |
100 | /**
101 | * 判断是否趴下
102 | * 人体区域高度和人体区域宽度的比值小于常数k
103 | * @param upperBodyInfo
104 | * @return
105 | */
106 | private static UnderarmData analysisUnderarm(UpperBodyInfo upperBodyInfo){
107 | double bodyWidth=upperBodyInfo.getBodyWidth();
108 | double bodyHeight=upperBodyInfo.getBodyHeight();
109 |
110 | //利用宽度和高度比
111 | if (bodyWidth==0){
112 | return new UnderarmData(false,0);
113 | }
114 | double ratio=bodyHeight/bodyWidth;
115 | if (ratio<0.5){
116 | if (ratio<0.1){
117 | return new UnderarmData(false,0);
118 | }
119 | double degree=-1/0.4*ratio+1/4;
120 | return new UnderarmData(true,degree);
121 | }else {
122 | return new UnderarmData(false,0);
123 | }
124 | }
125 |
126 | /**
127 | * 判断身体是否倾斜
128 | * 根据论文中训练的模型表示,下面这种情况可以视为身体倾斜
129 | * 左偏 L2<80度
130 | * 右偏 L2>100度
131 | *
132 | */
133 |
134 | private static BodySlant analysisBodySlant(UpperBodyInfo upperBodyInfo){
135 | Point p1=upperBodyInfo.getRightShoulder();//左肩位置
136 | Point p2=upperBodyInfo.getNeck();//脖子位置
137 |
138 | double tan2=(p1.getY()-p2.getY())/(p1.getX()-p2.getX());
139 | tan2=Math.abs(tan2);
140 | double l2=0;
141 | if (p1.getY()=10){
149 | double degree=1.0/35.0*cha-2.0/7.0;
150 | return new BodySlant(true,degree);
151 | }else {
152 | return new BodySlant(false,0);
153 | }
154 | }
155 |
156 | /**
157 | * 判断手部位置
158 | * @param upperBodyInfo
159 | * @return = 0 正常
160 | * = 1
161 | * = -1
162 | */
163 | private static HandPosition analysisHandPosition(UpperBodyInfo upperBodyInfo){
164 | Point point1=upperBodyInfo.getNose();//鼻子
165 | Point point2=upperBodyInfo.getNeck();//脖子
166 | Point point3=upperBodyInfo.getLeftElbow();//左手腕
167 | Point point4=upperBodyInfo.getRightElbow();//右手腕
168 |
169 | if (point1!=null&&point2!=null&&point3!=null&&point4!=null){
170 | if ((point3.getY()-point1.getY())*(point3.getY()-point2.getY())<0){
171 | return new HandPosition(true,Direction.LEFT);
172 | }
173 | if (((point4.getY()-point1.getY())*(point4.getY()-point2.getY()))<0){
174 | return new HandPosition(true,Direction.RIGHT);
175 | }
176 | }
177 | return new HandPosition(false,Direction.NO);
178 | }
179 |
180 | //--------------------对检测结果的封装-------------------------------------------
181 |
182 | //方向
183 | enum Direction{
184 | LEFT,RIGHT,NO;
185 | }
186 |
187 | //1.头偏离
188 | @Getter
189 | @Setter
190 | @AllArgsConstructor
191 | @NoArgsConstructor
192 | private static class HeadSlant{
193 | private boolean isSlant;//是否偏离
194 | private Direction direction;//偏离方向
195 | private double degree;//偏离程度
196 |
197 | }
198 |
199 | //2.趴下
200 | @Setter
201 | @Getter
202 | @AllArgsConstructor
203 | @NoArgsConstructor
204 | private static class UnderarmData{
205 | private boolean isUnderarm;
206 | private double degree;
207 | }
208 |
209 | //3.身体倾斜
210 | @Setter
211 | @Getter
212 | @AllArgsConstructor
213 | @NoArgsConstructor
214 | private static class BodySlant{
215 | private boolean isBodySlant;
216 | private double degree;
217 | }
218 |
219 | //4.手部位置
220 | @Setter
221 | @Getter
222 | @AllArgsConstructor
223 | @NoArgsConstructor
224 | private static class HandPosition{
225 | private boolean isError;
226 | private Direction direction;
227 | }
228 | }
229 |
--------------------------------------------------------------------------------
/src/main/java/spd/Spd.java:
--------------------------------------------------------------------------------
1 | package spd;
2 |
3 | import detector.impl.HeadDetector;
4 | import detector.impl.UpperBodyDetector;
5 | import model.HeadInfo;
6 | import model.SittingPosition;
7 | import model.SpdImage;
8 | import model.UpperBodyInfo;
9 | import service.SittingPositionDetection;
10 | import service.impl.SimpleSittingPositionDetection;
11 |
12 | import java.util.HashMap;
13 |
14 | /**
15 | * spd是该包的入口
16 | */
17 | public class Spd {
18 | private static Spd spd=new Spd();
19 | private static HeadDetector headDetector=null;
20 | private static UpperBodyDetector upperBodyDetector=null;
21 |
22 | private Spd(){
23 | }
24 | //单例模式,谁让baidu Api免费用户不支持并发呢
25 | public static Spd getInstance(HashMap headDetectorConfig,HashMap upperBodyDetectorConfig){
26 | //获取单例
27 | headDetector=HeadDetector.getHeadDetecto();
28 | upperBodyDetector=UpperBodyDetector.getUpperBodyDetector();
29 |
30 | boolean b1=headDetector.init(headDetectorConfig.get("appId"),headDetectorConfig.get("apiKey"),headDetectorConfig.get("secretKey"));
31 | boolean b2=upperBodyDetector.init(upperBodyDetectorConfig.get("appId"),upperBodyDetectorConfig.get("apiKey"),upperBodyDetectorConfig.get("secretKey"));
32 | if (!(b1&&b2)){
33 | return null;
34 | }
35 | return spd;
36 | }
37 |
38 | /**
39 | * 获取坐姿信息
40 | * @param uid 用户id
41 | * @param base 图片的base64码,大小不超过2MB
42 | * @return 坐姿信息类
43 | */
44 | public SittingPosition getSittingPosition(Integer uid,String base){
45 | HeadInfo headInfo=null;
46 | UpperBodyInfo upperBodyInfo=null;
47 |
48 | SpdImage spdImage=new SpdImage(base);
49 | //获取基础信息:头部信息,关键点信息
50 | try {
51 | headInfo=headDetector.detection(spdImage);
52 | upperBodyInfo=upperBodyDetector.detection(spdImage);
53 |
54 | if (headInfo==null&&upperBodyInfo==null){
55 | return null;
56 | }
57 | }catch (Exception e){
58 | e.printStackTrace();
59 | }
60 |
61 | SittingPosition sittingPosition=null;
62 |
63 | SittingPositionDetection sittingPositionDetection=new SimpleSittingPositionDetection();
64 | sittingPosition=sittingPositionDetection.getSittingPosition(headInfo,upperBodyInfo);
65 | sittingPosition.setUid(uid);
66 | return sittingPosition;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/test/java/detector/impl/HeadDetectorTest.java:
--------------------------------------------------------------------------------
1 | package detector.impl;
2 |
3 | public class HeadDetectorTest {
4 |
5 | }
6 |
--------------------------------------------------------------------------------