001package net.gdface.mtfsdk;
002
003import static net.gdface.mtfsdk.MtfAndroidConfigProvider.*;
004import static net.gdface.utils.BufferUtils.*;
005
006import net.gdface.sdk.CodeInfo;
007import net.gdface.sdk.EyeInfo;
008import net.gdface.sdk.FAngle;
009import net.gdface.sdk.FInt2;
010import net.gdface.sdk.FRect;
011import net.gdface.utils.Assert;
012
013/**
014 * 人脸检测信息描述对象<br>
015 * 实现原始人脸检测数据(double[])的解析,以及与{@link CodeInfo}实例的相互转换
016 * @author guyadong
017 *
018 */
019public class NativeFaceInfo extends CodeInfo {
020        /**
021         * 人脸检测数据(double数组)的字段名索引
022         * @author guyadong
023         *
024         */
025        enum FieldIndex{
026                /* 人脸位置矩形左上角 x */FRECT_LEFT,
027                /* 人脸位置矩形左上角 y */FRECT_TOP,
028                /* 人脸位置矩形宽度 */FRECT_WIDTH,
029                /* 人脸位置矩形高度 */FRECT_HEIGHT,
030                /* 人脸关键点 0 x坐标:左眼 */FD_LEFT_EYE_X,
031                /* 人脸关键点 0 y坐标:左眼 */FD_LEFT_EYE_Y,
032                /* 人脸关键点 1 x坐标:右眼 */FD_RIGHT_EYE_X,
033                /* 人脸关键点 1 y坐标:右眼 */FD_RIGHT_EYE_Y,
034                /* 人脸关键点 2 x坐标:鼻子 */FD_NOSE_X,
035                /* 人脸关键点 2 y坐标:鼻子 */FD_NOSE_Y,
036                /* 人脸关键点 3 x坐标:左嘴角*/FD_MOUTH_LEFT_X,
037                /* 人脸关键点 3 y坐标:左嘴角 */FD_MOUTH_LEFT_Y,
038                /* 人脸关键点 4 x坐标:右嘴角*/FD_MOUTH_RIGHT_X,
039                /* 人脸关键点 4 y坐标:右嘴角 */FD_MOUTH_RIGHT_Y,
040                /* 置信度 */FD_CONFIDENCE,
041                /* 人脸框预测x步进值,只有在使用位置关联函数才有赋值 */FD_FACE_OFFSET_Y,
042                /* 人脸框预测y步进值,只有在使用位置关联函数才有赋值 */FD_FACE_OFFSET_X,
043                /* 人脸姿态角度:旋转角roll   */FD_ANGLE_ROLL,
044                /* 人脸姿态角度:偏转角yaw  */FD_ANGLE_YAW,
045                /* 人脸姿态角度:倾斜角pitch */FD_ANGLE_PITCH,
046                /* 识别标记(是否已经识别) */FD_DETECTED_FLAG,
047        }
048        private static final long serialVersionUID = 1L;
049        /**
050         * 人脸检测框置信度(与{@link FAngle#getConfidence()}相同)
051         */
052        double confidence;
053        /**
054         * 从JNI动态库返回的原始人脸检测数据 double[61]
055         */
056        double nativeData[];
057        public NativeFaceInfo(double[] nativeData) {
058                this(nativeData,0);
059        }
060        /**
061         * 从原始人脸信息数组构造实例
062         * @param nativeData 原始数据
063         * @param start 数据起始索引
064         */
065        public NativeFaceInfo(double[] nativeData,int start) {
066                super();
067                init(nativeData, start);
068        }
069        public NativeFaceInfo(CodeInfo codeInfo) {
070                super();
071                Assert.notNull(codeInfo, "codeinfo");
072                byte[] facialData = codeInfo.getFacialData();
073                Assert.notNull(facialData, "facialData");
074                init(asDoubleArray(facialData), 0);
075        }
076        /**
077         * 从原始人脸检测数据(61个double)解析为当前对象对应字段
078         * @param nativeData
079         * @param start
080         */
081        private void init(double[] nativeData, int start){
082                Assert.isTrue(start>=0,"start>=0", "invalid start");
083                Assert.isTrue(nativeData!=null && nativeData.length-start>=FDDATA_LEN, 
084                                "nativeData!=null && nativeData.length-start>=CaffeMobile.FDDATA_LEN","invalid nativeData");
085                this.nativeData = new double[FDDATA_LEN];
086                System.arraycopy(nativeData, start, this.nativeData, 0, this.nativeData.length);
087                ////////////////////
088                FRect pos = getPos();
089                if(pos == null){
090                        pos = new FRect();
091                }
092                pos.setLeft((int) this.nativeData[FieldIndex.FRECT_LEFT.ordinal()]);
093                pos.setTop((int) this.nativeData[FieldIndex.FRECT_TOP.ordinal()]);
094                pos.setWidth((int) this.nativeData[FieldIndex.FRECT_WIDTH.ordinal()]);
095                pos.setHeight((int) this.nativeData[FieldIndex.FRECT_HEIGHT.ordinal()]);
096                setPos(pos);
097                /////////////////////////
098                FAngle angle = getAngle();
099                if(angle == null){
100                        angle = new FAngle();
101                }
102                angle.setRoll((int) this.nativeData[FieldIndex.FD_ANGLE_ROLL.ordinal()]);
103                angle.setYaw((int) this.nativeData[FieldIndex.FD_ANGLE_YAW.ordinal()]);
104                angle.setPitch((int) this.nativeData[FieldIndex.FD_ANGLE_PITCH.ordinal()]);
105                angle.setConfidence((int)(this.nativeData[FieldIndex.FD_CONFIDENCE.ordinal()]*100));
106                setAngle(angle);
107                //////////////////////////
108                EyeInfo ei = getEi();
109                if(ei == null){
110                        ei = new EyeInfo();
111                }
112                ei.setLeftx((int)this.nativeData[FieldIndex.FD_LEFT_EYE_X.ordinal()]);
113                ei.setLefty((int)this.nativeData[FieldIndex.FD_LEFT_EYE_Y.ordinal()]);
114                ei.setRightx((int)this.nativeData[FieldIndex.FD_RIGHT_EYE_X.ordinal()]);
115                ei.setRighty((int)this.nativeData[FieldIndex.FD_RIGHT_EYE_Y.ordinal()]);
116                setEi(ei);
117                //////////////////////////
118                FInt2 mouth = getMouth();
119                if(mouth == null){
120                        mouth = new FInt2();
121                }
122                {
123                        // 计算左右眼中间点位置 
124                        double x = (this.nativeData[FieldIndex.FD_MOUTH_LEFT_X.ordinal()] 
125                                                                + this.nativeData[FieldIndex.FD_MOUTH_RIGHT_X.ordinal()])/2;
126                        double y = (this.nativeData[FieldIndex.FD_MOUTH_LEFT_Y.ordinal()] 
127                                                                + this.nativeData[FieldIndex.FD_MOUTH_RIGHT_Y.ordinal()])/2;
128                        mouth.setX((int)x);
129                        mouth.setY((int)y);
130                        setMouth(mouth);
131                }
132
133                ////////////////////////
134                FInt2 nose = getNose();
135                if(nose == null){
136                        nose = new FInt2();
137                }
138                nose.setX((int)this.nativeData[FieldIndex.FD_NOSE_X.ordinal()]);
139                nose.setY((int)this.nativeData[FieldIndex.FD_NOSE_Y.ordinal()]);
140                setNose(nose);
141                //////////////////////
142                confidence = this.nativeData[FieldIndex.FD_CONFIDENCE.ordinal()];
143                setFacialData(asByteArray(this.nativeData));
144        }
145        /**
146         * {@link CodeInfo} 转换为{@link NativeFaceInfo}
147         * @param code
148         * @return
149         */
150        public static NativeFaceInfo toNative(CodeInfo code){
151                if(code == null){
152                        return null;
153                }                       
154                if(code instanceof NativeFaceInfo){
155                        return (NativeFaceInfo)code;
156                }
157                return new NativeFaceInfo(code);
158        }
159        public static long getSerialversionuid() {
160                return serialVersionUID;
161        }
162        public double getConfidence() {
163                return confidence;
164        }
165        /**
166         * @return原始人脸检测数据 double[61]
167         */
168        public double[] getNativeData() {
169                return nativeData;
170        }
171}