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}