All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.gdface.cassdk.JniBridge Maven / Gradle / Ivy

There is a newer version: 2.1.1
Show newest version
package net.gdface.cassdk;

import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.LinkedHashMap;

import com.sun.jna.NativeLibrary;

import net.gdface.cassdk.jna.EF_Param;
import net.gdface.cassdk.jna.THFI_FacePos;
import net.gdface.cassdk.jna.THFI_Param;
import net.gdface.cassdk.jna.THFI_Param_Ex;
import net.gdface.cassdk.jna.THFaceImageLibrary;
import net.gdface.cassdk.jna.THFeatureLibrary;
import net.gdface.utils.ResourcePool.IntResourcePool;

/**
 * CASSDK 算法(线程安全)的调用实现
* 参见CASSDK的"THFaceImage_i.h","THFeature_i.h" * @author guyadong * */ public class JniBridge extends BaseJniBridge{ private static final THFaceImageLibrary faceImageLibrary; protected static THFeatureLibrary featureLibrary; static { String cassdkBin = CASSDK_HOME + "/bin"; NativeLibrary.addSearchPath("THFaceImage", cassdkBin); NativeLibrary.addSearchPath("THFeature", cassdkBin); faceImageLibrary = THFaceImageLibrary.INSTANCE; featureLibrary = THFeatureLibrary.INSTANCE; FEATURE_SIZE = featureLibrary.EF_Size(); logger.info(String.format("FEATURE_SIZE=%d bytes", FEATURE_SIZE)); // 从配置文件读取初始化通道数 init(); // add hook for release JNI resource on JVM shutdown Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { logger.info("release cassdk JNI resoure..."); release(); // 如果用 logger 输出不能显示,why? System.out.println("release cassdk JNI resoure finished"); } }); } /** * 从参数配置对象中读取参数创建{@link THFIParam} * @return THFIParam */ private static THFI_Param createTHFIParam(){ THFI_Param param= new THFI_Param(); param.nMinFaceSize = CasConfig.getMinFaceSize(); param.nRollAngle = CasConfig.getRollAngle(); return param; } /** * 从参数配置对象中读取参数创建{@link THFI_Param_Ex} * @return THFI_Param_Ex */ private static THFI_Param_Ex createTHFIParamEx(){ THFI_Param_Ex param= new THFI_Param_Ex(createTHFIParam(),CasConfig.getDeviceID()); return param; } private static EF_Param createEFParam(){ EF_Param param = new EF_Param(CasConfig.getDeviceID()); return param; } /** * 人脸识别模块(THFaceImage和THFeature)初始化, 只需在应用程序初始化时调用一次 * * @throws ExceptionInInitializerError * @see #initTHFaceImage(int, int, THFIParam) * @see #initTHFeature(int) * @return 初始化失败则抛出异常{@link ExceptionInInitializerError} */ private static void init() throws ExceptionInInitializerError { logger.info(String.format("CASSDK %s initializing(SDK正在初始化)",CasConfig.getVersion().version)); logger.info(String.format("model initializing(模型数据初始化) MODE:%s", CasConfig.isGpuMode()?"GPU ID:"+CasConfig.getDeviceID():"CPU")); int featureChannelNum = CasConfig.getFeatureChannelNum(); int detectChannelNum = CasConfig.getFeatureChannelNum(); try{ copyModelToUserDir(); { logger.info(String.format("人脸检测通道: %d",detectChannelNum)); logger.info(String.format("特征提取通道: %d",featureChannelNum)); detectChannelPool = new IntResourcePool(detectChannelNum); featureChannelPool = new IntResourcePool(featureChannelNum); logger.info("detect module initializing(人脸检测模块初始化)"); int result = CasConfig.isGpuMode() ? faceImageLibrary.THFI_Create_Ex((short)detectChannelNum, createTHFIParamEx()) : faceImageLibrary.THFI_Create((short)detectChannelNum, createTHFIParam()); if(result <=0){ StringBuffer buffer = new StringBuffer("fail to initTHFaceImage,error code:"); buffer.append(result); switch(result){ case -99:{ buffer.append("msg:").append(INVALID_LICENSE); break; } default: } throw new JniException(buffer.toString()); } } { logger.info("feature module initializing(特征提取模块初始化)"); short result = CasConfig.isGpuMode() ? featureLibrary.EF_Init_Ex(featureChannelNum,createEFParam()) : featureLibrary.EF_Init(featureChannelNum); if(result <=0 ){ StringBuffer buffer = new StringBuffer("fail to initTHFeature,error code:"); buffer.append(result); switch(result){ case -99:{ buffer.append("msg:").append(INVALID_LICENSE); break; } case -1:{ buffer.append("msg:").append("open file \"feadb.db*\" error"); break; } case -2:{ buffer.append("msg:").append("check file \"feadb.db*\" error"); break; } case -3:{ buffer.append("msg:").append("read file \"feadb.db*\" error"); break; } default: break; } throw new JniException(buffer.toString()); } } }catch(Exception e){ logger.info(String.format("%s:%s",e.getClass().getSimpleName(),e.getMessage())); throw new ExceptionInInitializerError(e); } logger.info("CASSDK initialized(SDK初始化结束)"); } /** * 释放所有资源(THFeature SDK和THFaceImage SDK)
* JVM结束时会自动调用此方法
*/ private static void release(){ featureLibrary.EF_Release(); faceImageLibrary.THFI_Release(); } /** * 对图像进行人脸检测 * @param imgData * 图像数据,长度必须为 (width*height*3),否则抛出异常 {@link IllegalArgumentException} * @param bpp * 图像像素位数(8或24),否则抛出异常 {@link IllegalArgumentException} * @param width * 图像宽度 * @param height * 图像高度 * @return 返回人脸人眼等位置信息数组(没有检测到人脸则返回长度为0的空数组) */ public static THFI_FacePos[] detectFace(byte[] imgData, int bpp, int width, int height){ if(null == imgData){ throw new NullPointerException("imgData must not be null"); } if(bpp != 24){ throw new IllegalArgumentException("must RGB24"); } if(imgData.length != width*height*3){ throw new NullPointerException("INVALID imageData"); } short nChannelID = detectChannelPool.apply().shortValue(); // logger.info(String.format("detectChannelD=%d", nChannelID)); THFI_FacePos[] pfps=new THFI_FacePos[maxDetectFaceNum]; try{ int result = faceImageLibrary.THFI_DetectFace(nChannelID, ByteBuffer.wrap(imgData), bpp, width, height, pfps, pfps.length, sampleSize); if(result<0){ StringBuffer buffer = new StringBuffer("fail to THFI_DetectFace,error code:"); buffer.append(result); switch(result){ case -99:{ buffer.append("msg:").append(INVALID_LICENSE); break; } case -1:{ buffer.append("msg:").append(INVALID_CHANNEL); break; } case -2:{ buffer.append("msg:").append(INVALID_IMAGE); break; } case -3:{ buffer.append("msg:").append(INVALID_FPS); break; } default: } throw new JniException(buffer.toString()); } return Arrays.copyOf(pfps, result); }finally{ detectChannelPool.free(); } } /** * 对人脸图像(RGB24)指定的位置进行特征提取 * @param imgData * 图像数据,RGB24格式(注意不需要位图四字节对齐),在内存中人脸是正的,
* 长度必须为 (width*height*3),否则抛出异常 {@link IllegalArgumentException} * @param width * 图像宽度 * @param height * 图像高度 * @param facePos * 人脸位置信息,为{@code null}时抛出异常 {@link IllegalArgumentException} * * @return 人脸特征数组(提取失败返回null) */ public static byte[] getFaceFeature(byte[] imgData, int width, int height, THFI_FacePos facePos){ if(null == imgData){ throw new NullPointerException("imgData must not be null"); } if(imgData.length != width*height*3){ throw new NullPointerException("INVALID imageData"); } short nChannelID = featureChannelPool.apply().shortValue(); // logger.info(String.format("featureChannelD=%d", nChannelID)); ByteBuffer featureBuffer = ByteBuffer.allocate(FEATURE_SIZE); try{ int result = featureLibrary.EF_Extract(nChannelID , ByteBuffer.wrap(imgData), width, height, 3, facePos, featureBuffer); if(result<0){ StringBuffer buffer = new StringBuffer("fail to EF_Extract,error code:"); buffer.append(result); switch(result){ case -99:{ buffer.append("msg:").append(INVALID_LICENSE); break; } case -1:{ buffer.append("msg:").append(INVALID_PBUF); break; } case -2:{ buffer.append("msg:").append(INVALID_CHANNEL); break; } default: } throw new JniException(buffer.toString()); } return featureBuffer.array(); }finally{ featureChannelPool.free(); } } /** * 对图像(RGB24)中的一组人脸位置提取特征码
* @param imgData * @param width * @param height * @param facePosArray * 要提取特征的人脸位置对象数组,为{@code null}时抛出异常 {@link IllegalArgumentException} * * @see #getFaceFeature(byte[], int, int, FacePos) * @return 返回facePosArray,对于提取到特征码的元素,{@link FacePos#feature}包含特征码数据,
* 特征提取失败则对应的 {@link FacePos#feature}为null */ public static byte[][] getFaceFeatures(byte[] imgData, int width, int height, THFI_FacePos[] facePosArray){ if(null == imgData ){ throw new NullPointerException("imgData must not be null"); } if(null == facePosArray){ throw new NullPointerException("facePosArray must not be null"); } if(imgData.length != width*height*3){ throw new NullPointerException("INVALID imageData"); } short nChannelID = featureChannelPool.apply().shortValue(); // logger.info(String.format("featureChannelD=%d", nChannelID)); ByteBuffer featuresBuffer = ByteBuffer.allocate(FEATURE_SIZE*facePosArray.length); try{ int result = featureLibrary.EF_Extract_M(nChannelID , ByteBuffer.wrap(imgData), width, height, 3, facePosArray, featuresBuffer, facePosArray.length); if(result<0){ StringBuffer buffer = new StringBuffer("fail to EF_Extract,error code:"); buffer.append(result); switch(result){ case -99:{ buffer.append("msg:").append(INVALID_LICENSE); break; } case -1:{ buffer.append("msg:").append(INVALID_PBUF); break; } case -2:{ buffer.append("msg:").append(INVALID_CHANNEL); break; } default: } throw new JniException(buffer.toString()); } byte[][] features = new byte[facePosArray.length][FEATURE_SIZE]; for(int i = 0 ;i< facePosArray.length; ++i){ features[i] = Arrays.copyOfRange(featuresBuffer.array(),i*FEATURE_SIZE,(i + 1)*FEATURE_SIZE); } return features; }finally{ featureChannelPool.free(); } } /** * 对图像(RGB24)进行人脸检测并提取每个检测到的人脸特征码 * @param imgData * @param width * @param height * @return 返回包含特征码数据的 {@link FacePos}对象数组(只包含成功提取特征码的位置对象) * @see #detectFace(byte[], int, int, int, int) * @see #getFaceFeatures(byte[], int, int, THFI_FacePos[]) */ public static LinkedHashMap detectAndGetFeatures(byte[] imgData, int width, int height){ LinkedHashMap map = new LinkedHashMap(16); THFI_FacePos[] facepos = detectFace(imgData,24,width,height); byte[][] features = getFaceFeatures(imgData, width, height, facepos); for(int i = 0 ;i< facepos.length ; ++i){ map.put(facepos[i], features[i]); } return map; } /** * 人脸特征相似度比对
* 特征码为{@code null}或长度不等于 {@link #FEATURE_SIZE}则抛出{@link IllegalArgumentException}异常 * @param feature1 * 待比对的人脸特征 * @param feature2 * 待比对的人脸特征 * @return 两个人脸的相似度,范围在0-1之间,相似度值越高,表示比对的两个人脸越可能为同一个人 */ public static float compareFeature(byte[] feature1, byte[] feature2){ if(null == feature1 || null == feature2){ throw new NullPointerException("feature1,feature2 must not be null"); } if(feature1.length != FEATURE_SIZE || feature2.length != FEATURE_SIZE){ throw new IllegalArgumentException("INVALID length of feature1 or feature2"); } return featureLibrary.EF_Compare(ByteBuffer.wrap(feature1), ByteBuffer.wrap(feature2)); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy