001package net.facelib.mtfsdk; 002 003import net.facelib.jni.BaseJniBridge; 004import net.facelib.jni.FacelibRuntimeParam; 005import net.facelib.jni.SdkInitException; 006import net.facelib.jni.SdkRuntimeException; 007import net.gdface.image.MatType; 008import net.gdface.utils.SimpleLog; 009 010import static net.facelib.mtfsdk.MtfsdkConstant.*; 011 012import java.util.Arrays; 013 014import static net.facelib.jni.BridgeLog.BRIDEG_LOGGER; 015 016import net.facelib.akcore.LicenseManager; 017import net.facelib.jni.SdkStatus; 018import net.facelib.sdk.ImageSupport; 019 020/** 021 * MTFSDK for android/arm JNI 接口<br> 022 * 此类为非线程安全的,不可多线程共享调用,需要在外部进一步封装实现线程安全 023 * 024 * @author guyadong 025 * 026 */ 027public class V2AndroidBridge extends BaseJniBridge { 028 public static final String SDK_VERSION = "MTFSDK512V2"; 029 static final String V2_PRODUCT_ID = "MTFSDK512V2_android"; 030 031 private final long[] featureHandle = new long[]{-1}; 032 /** 033 * 初始化状态 034 */ 035 private volatile SdkStatus status = SdkStatus.SDK_UNINITIALIZED; 036 public static V2LicenseManager V2_LICENSE_MANAGER = new V2LicenseManager(); 037 static { 038 try { 039 BRIDEG_LOGGER.log("loadLibrary FS_AndroidFeaV2SDK"); 040 // 加载算法动态库 041 System.loadLibrary("FS_AndroidFeaV2SDK"); 042 } catch (Exception e) { 043 BRIDEG_LOGGER.log(e.getMessage()); 044 throw new ExceptionInInitializerError(e); 045 } 046 047 } 048 049 public V2AndroidBridge() { 050 } 051 052 @Override 053 public SdkStatus getStatus() { 054 return status; 055 } 056 057 @Override 058 protected void sdkInit(String licenseFile, String licenseKey, String licenseCode) throws SdkInitException { 059 if (SdkStatus.SDK_INIT_OK == status) { 060 return; 061 } 062 try { 063 int ffFlag = FFInitV2( 064 licenseCode.getBytes(), 065 licenseKey.getBytes(), 066 licenseFile.getBytes(), 067 "\0", 068 featureHandle); 069 BRIDEG_LOGGER.log("FFInitV2 featureHandle: [{}] ffFlag={}",featureHandle[0],ffFlag); 070 status = SdkStatus.jniCode(ffFlag); 071 BRIDEG_LOGGER.log("feature module: {}", this); 072 if (status != SdkStatus.SDK_INIT_OK) { 073 throw new SdkInitException(status); 074 } 075 } finally { 076 // 如果没有初始化成功,则destroy已经初始化模块 077 if (status != SdkStatus.SDK_INIT_OK) { 078 BRIDEG_LOGGER.log("FFDestroyV2 caused by init fail {}",this); 079 FFDestroyV2(featureHandle[0]); 080 } 081 } 082 } 083 084 @Override 085 protected void sdkUninit() { 086 if (featureHandle[0] >= 0) { 087 BRIDEG_LOGGER.log("FFDestroyV2 {}",this); 088 status = SdkStatus.SDK_UNINITIALIZED; 089 FFDestroyV2(featureHandle[0]); 090 featureHandle[0] = -1; 091 } 092 } 093 094 @Override 095 protected LicenseManager licenseManager() { 096 return BaseJniBridge.getLicenseManager(V2_PRODUCT_ID, V2AndroidBridge.V2_LICENSE_MANAGER); 097 } 098 099 public byte[] feaExtractByte(MatType matType, byte[] matData, int width, int height, double[] rect) { 100 byte[] buffer = new byte[FEATURE_BYTES]; 101 //BRIDEG_LOGGER.log("before FFFeaExtractByteV2 {} width={},height={}",this,width, height); 102 byte[] bgr = ImageSupport.toBGR(matType, matData, width, height); 103 int ret = FFFeaExtractByteV2(featureHandle[0], bgr, width, height, buffer, rect); 104 if (ret < 0) { 105 SdkStatus code = SdkStatus.jniCode(ret); 106 BRIDEG_LOGGER.log("FFFeaExtractByteV2 code={} {}",code,this); 107 throw new SdkRuntimeException(code); 108 } 109 return buffer; 110 } 111 112 @Override 113 public V2AndroidBridge setRuntimeParam(String name, Object value) throws SdkRuntimeException { 114 FacelibRuntimeParam r = FacelibRuntimeParam.valueOf(name); 115 switch (r) { 116 case featureThreadNumber: 117 int featureThreadNumber = value != null ? (Integer) value 118 : MtfAndroidConfigProvider.DEFAULT_FEATURE_THREAD_NUMBER; 119 if (featureThreadNumber > 0) { 120 int ret = FFSetThreadsNumberV2(featureHandle[0], featureThreadNumber); 121 if (ret != 0) { 122 SdkStatus code = SdkStatus.jniCode(ret); 123 BRIDEG_LOGGER.log("FFSetThreadsNumberV2 code={}",code,this); 124 throw new SdkRuntimeException(code); 125 } 126 } 127 break; 128 default: 129 throw new IllegalArgumentException(SimpleLog.logString("INVALID parameter name: {}", name)); 130 } 131 return this; 132 } 133 134 //////////////////////////////////////// 特征提取系列/////////////////////////////////////////// 135 /** 136 * 人脸识别初始化函数 137 * 138 * @param licenseCode 139 * 授权码 140 * @param licenseKey 141 * 授权关键字 142 * @param path 143 * 授权码文件本地路径 144 * @param faceDetectionModelPath 145 * 模型路径 146 * @param handle 147 * [out]句柄 148 * @return 成功(0)或错误代码(< 0),see also {@link SdkStatus} 149 */ 150 private static native int FFInitV2(byte[] licenseCode, byte[] licenseKey, byte[] path, 151 String faceDetectionModelPath, long[] handle); 152 153 /** 154 * 人脸识别模块资源释放函数 155 * 156 * @param handle 157 * 句柄 158 */ 159 static native void FFDestroyV2(long handle); 160 161 /** 162 * 对输入图像中检测到的人脸提取特征 163 * 164 * @param handle 165 * 操作句柄 166 * @param BGR 167 * 待检测图像BGR格式 168 * @param width 169 * 图像宽度 170 * @param height 171 * 图像高度 172 * @param fea 173 * [out] 人脸特征 空间在外部申请,长度4096 174 * @param rect 175 * 人脸位置及关键点信息 由人脸检测SDK 产生,参见 176 * {@link #FDDetect(long, byte[], int, int, int, double[])} 177 * @return 成功(0)或错误代码(< 0),see also {@link SdkStatus} 178 */ 179 private static native int FFFeaExtractByteV2(long handle, byte[] BGR, int width, int height, byte[] fea, 180 double[] rect); 181 182 /** 183 * 人脸相似度比对函数<br> 184 * 对人脸特征feaA和feaB进行相似度比对,返回相似度结果 185 * 186 * @param feaA 187 * 1024 bytes 188 * @param feaB 189 * 1024 bytes 190 * @return 相似度(0.0~1.0) 191 */ 192 public static native double FFSimilarityByteV2(byte[] feaA, byte[] feaB); 193 194 /** 195 * @return 人脸识别模块版本 196 */ 197 public static native String FFgetVersionV2(); 198 199 private static native int FFSetThreadsNumberV2(long handle, int threadsNumbers); 200 201 @Override 202 public String toString() { 203 StringBuilder builder = new StringBuilder(); 204 builder.append("V2AndroidBridge [featureHandle="); 205 builder.append(Arrays.toString(featureHandle)); 206 builder.append(", status="); 207 builder.append(status); 208 builder.append("]"); 209 return builder.toString(); 210 } 211 212}