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

net.facelib.faceapi.client.FaceApiMtfClient Maven / Gradle / Ivy

The newest version!
package net.facelib.faceapi.client;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.gitee.l0km.com4j.base.ResourcePool.IntResourcePool;
import com.gitee.l0km.com4j.base.SimpleLog;
import com.gitee.l0km.com4j.base.BaseVolatile;
import com.gitee.l0km.com4j.base.ILazyInitVariable;
import com.gitee.l0km.ximage.BaseLazyImage;
import com.gitee.l0km.ximage.ImageErrorException;
import com.gitee.l0km.ximage.MatType;
import com.gitee.l0km.ximage.NotFoundLazyImageFactoryException;
import com.gitee.l0km.ximage.UnsupportedFormatException;
import com.gitee.l0km.xthrift.thrift.ClientFactory;

import net.facelib.mtfsdk.jna.ZymtffacedetectsdkLibrary;
import net.facelib.sdk.ImageSupport;
import net.gdface.sdk.BaseFaceApi;
import net.gdface.sdk.CapacityFieldConstant;
import net.gdface.sdk.CodeInfo;
import net.gdface.sdk.ContextLoader;
import net.gdface.sdk.ContextLoader.GlobalContextField;
import net.gdface.sdk.FseResult;
import net.gdface.sdk.NotFaceDetectedException;
import net.gdface.sdk.thrift.FaceApiThriftClient;

import static com.gitee.l0km.com4j.base.ConditionChecks.checkNotNull;
/**
 * {@link net.gdface.sdk.FaceApi} rpc client实现类(线程安全)
* 人脸检测基于MTFSDK本地实现,特征提取和比对以及特征搜索调用RPC实现 * @author guyadong * */ public class FaceApiMtfClient extends BaseFaceApi implements MtfsdkConstant,CapacityFieldConstant { /** * RPC client 实例 */ private FaceApiThriftClient client; /** * 用于人脸检测的数据缓冲区 */ private static final ThreadLocal faceBuffer = new ThreadLocal(){ @Override protected float[] initialValue() { return new float[FDDATA_LEN*MAX_FACE_COUNT]; } }; private static final ZymtffacedetectsdkLibrary JNA = ZymtffacedetectsdkLibrary.INSTANCE; /** 管理通道的资源池对象 */ private static final IntResourcePool channelPool ; /** * 初始化状态 */ private static volatile SdkStatus status =SdkStatus.SDK_UNINITIALIZED; /** * 返回并发参数
* 先尝试从全局上下文({@link ContextLoader})获取, * 如果找不到则返回1作为默认值 */ private static final ILazyInitVariable concurrency = new BaseVolatile(){ @Override protected Integer doGet() { Integer concurrency = ContextLoader.getGlobalContext(GlobalContextField.CONCURRENCY); return null == concurrency ? 1 : concurrency; }}; /** * 返回人脸检测倾向
* 先尝试从全局上下文({@link ContextLoader})获取, * 如果找不到则返回true为默认值 */ private static final ILazyInitVariable mulitFaceDetectDrend = new BaseVolatile(){ @Override protected Integer doGet() { Boolean mfd = ContextLoader.getGlobalContext(GlobalContextField.MULIT_FACE_DETECT_TREND); if(null == mfd){ return 0; } return mfd ? 0 : 1; }}; /** * 构造方法
* 通过该方法可以更精确控制创建 FaceApi 服务客户端的参数 * @param factory 客户端工厂类实例 */ public FaceApiMtfClient(ClientFactory factory) { init(factory); } /** * 构造方法
* 使用指定的主机名和端口号构造客户端实例 * @param host FaceApi 服务主机名 * @param port FaceApi 服务端口号 */ public FaceApiMtfClient(String host, int port) { init(host, port); } /** * 默认构造方法
* NOTE:使用该方法构造的实例时,FaceApi 服务客户端没有初始化,调用远端服务会抛出{@link IllegalStateException}异常,
* 可以使用 {@link #init(String, int)}或 {@link #init(ClientFactory)}方法初始化FaceApi 服务客户端. */ public FaceApiMtfClient() { this.client = null; } /** * 使用指定的主机名和端口号初始化 FaceApi 服务客户端实例 * @param factory * @return 当前对象 */ public FaceApiMtfClient init(ClientFactory factory) { this.client = new FaceApiThriftClient(factory); return this; } /** * 使用指定的主机名和端口号初始化 FaceApi 服务客户端实例 * @param host FaceApi 服务主机名 * @param port FaceApi 服务端口号 * @return 当前对象 */ public FaceApiMtfClient init(String host, int port){ this.client = new FaceApiThriftClient(host, port); return this; } private FaceApiThriftClient getClient() { if(null == client){ throw new IllegalStateException("client is uninitialized"); } return client; } /** * 测试 FaceApi 服务端是否可连接
* FaceApi 服务客户端未初始化时返回{@code false} * @return FaceApi 服务可连接则返回{@code true},否则返回{@code false} */ public boolean testConnect() { return null == client ? false : client.testConnect(); } /** * 以 ${host}:${port} 格式返回FaceApi 服务主机名和端口号 * @return ${host}:${port} 格式字符串 */ public String getServiceLocation(){ return getClient().getFactory().getHostAndPort().toString(); } /** * 对输入图像进行人脸检测,检测结果由rect返回, * 检测到人脸返回大于0的人脸个数, * 返回的是21个元素的脸部信息 * @param matType 图像矩阵类型 * @param imgMatrix 待检测图像BGR格式 * @param width 图像宽度 * @param height 图像高度 * @param detectMod 0:用于普通多人脸检测,1:用于帧相关单人脸检测 */ protected void nativeDetectFace(MatType matType, byte[] imgMatrix, int width, int height,List faceInfo, int detectMod) { float[] buffer = faceBuffer.get(); try { byte[] bgr = ImageSupport.toBGR(matType, imgMatrix, width, height); int ret = JNA.FDDetect(channelPool.apply(),ByteBuffer.wrap(bgr), width, height, 3, detectMod, FloatBuffer.wrap(buffer)); if(ret<0){ throw new SdkRuntimeException(SdkStatus.jniCode(ret)); } for(int i=0; i < ret; ++i){ faceInfo.add(new NativeFaceInfo(buffer, i*FDDATA_LEN)); } } finally { channelPool.free(); } } /** * SDK初始化
* @throws SdkInitException */ private static void init() throws SdkInitException{ // double check if(SdkStatus.SDK_INIT_OK != status){ synchronized (FaceApiMtfClient.class) { if(SdkStatus.SDK_INIT_OK != status){ SimpleLog.log("MTFSDK native library initlalizing,wait a moment please."); int channelNum = concurrency.get(); int channelId=0; try { for(; channelId < channelNum; ++channelId){ System.out.print('.'); int ret = JNA.FSSDKInit(channelId); if(ret != 0){ throw new SdkRuntimeException(SdkStatus.jniCode(ret)); } } // 初始化成功则置状态为成功 status = SdkStatus.SDK_INIT_OK ; } finally { System.out.println(); // 如果没有完成循环代表初始化不完全成功,则执行release if( channelId < channelNum){ for(int i=0;i * * @param lazyImg * 图像对象,为{@code null}时抛出{@link IllegalArgumentException} * @return 没有检测到人脸则返回空表 * @throws UnsupportedFormatException */ public List detectFace(BaseLazyImage lazyImg) throws UnsupportedFormatException { checkNotNull(lazyImg, "lazyImg is null"); List faceInfo = new ArrayList(); if (lazyImg.getWidth() > 0 && lazyImg.getHeight() > 0) { byte[] imgMatrix = lazyImg.getMatrixData(getNativeMatrixType()); nativeDetectFace(getNativeMatrixType(),imgMatrix, lazyImg.getWidth(),lazyImg.getHeight(),faceInfo, mulitFaceDetectDrend.get()); } return faceInfo; } /** * 对平台支持的图像对象进行人脸检测
* @param 在标准java平台下,为 {@code java.awt.image.BufferedImage}
* 在android平台下为{@code android.graphics.Bitmap}
* @param imgObj 图像对象 * @return 没有检测到人脸则返回空表 * @throws IllegalArgumentException imgObj不是平台支持的类型 */ public List detectFaceByImage(T imgObj) { try { BaseLazyImage lazyImg = BaseLazyImage.getLazyImageFactory().createByImageObject(imgObj); return detectFace(lazyImg); } catch (UnsupportedFormatException | NotFoundLazyImageFactoryException e) { throw new RuntimeException(e); } } @Override public CodeInfo[] detectFace(byte[] imgData) throws ImageErrorException { BaseLazyImage lazyImg = makeOpenedLazyImage(imgData); try { return detectFace(lazyImg).toArray(new CodeInfo[0]); } finally { try { lazyImg.close(); lazyImg = null; } catch (IOException e) { throw new RuntimeException(e); } } } @Override public CodeInfo[] detectAndGetCodeInfo(byte[] imgData, int faceNum) throws ImageErrorException, NotFaceDetectedException { CodeInfo[] codes = detectFace(imgData); if((faceNum == 0 && 0 == codes.length) || (faceNum > 0 && faceNum > codes.length)){ throw new NotFaceDetectedException(); } codes = getClient().getCodeInfo(imgData, faceNum, codes); // 没有检测到要求的人脸则抛出异常 if(0 == codes.length){ throw new NotFaceDetectedException(); } if(faceNum>0 && faceNum != codes.length){ throw new NotFaceDetectedException(); } return codes; } @Override public Boolean wearMask(byte[] imgData, CodeInfo faceInfo) throws ImageErrorException { return getClient().wearMask(imgData, faceInfo); } @Override public CodeInfo[] getCodeInfo(byte[] imgData, int faceNum, CodeInfo[] facePos) throws NotFaceDetectedException { return getClient().getCodeInfo(imgData, faceNum, facePos); } @Override public CodeInfo getCodeInfo(byte[] imgData, CodeInfo facePos) { return getClient().getCodeInfo(imgData, facePos); } @Override public CodeInfo[] matDetectFace(MatType matType, byte[] matData, int width, int height,int facenum) throws NotFaceDetectedException{ List faceInfo = new ArrayList<>(); nativeDetectFace(matType,matData,width,height,faceInfo, mulitFaceDetectDrend.get()); // 没有检测到要求的人脸则抛出异常 if(faceInfo.isEmpty()){ throw new NotFaceDetectedException(); } if(facenum>0 && facenum != faceInfo.size()){ throw new NotFaceDetectedException(); } return faceInfo.toArray(new CodeInfo[0]); } @Override public CodeInfo[] matDetectFace(MatType matType, byte[] matData, int width, int height) { List faceInfo = new ArrayList<>(); nativeDetectFace(matType,matData,width,height,faceInfo, mulitFaceDetectDrend.get()); return faceInfo.toArray(new CodeInfo[0]); } @Override public CodeInfo[] matGetCodeInfo(MatType matType, byte[] matData, int width, int height, int facenum, CodeInfo[] facePos) throws NotFaceDetectedException { return getClient().matGetCodeInfo(matType, matData, width, height, facenum, facePos); } @Override public CodeInfo matGetCodeInfo(MatType matType, byte[] matData, int width, int height, CodeInfo facePos) { return getClient().matGetCodeInfo(matType, matData, width, height, facePos); } @Override public CodeInfo[] matDetectAndGetCodeInfo(MatType matType, byte[] matData, int width, int height) { CodeInfo[] codes = matDetectFace(matType, matData, width, height); try { return getClient().matGetCodeInfo(matType, matData, width, height, codes.length, codes); } catch (NotFaceDetectedException e) { return new CodeInfo[0]; } } @Override public CodeInfo[] matDetectAndGetCodeInfo(MatType matType, byte[] matData, int width, int height, int faceNum) throws NotFaceDetectedException { CodeInfo[] codes = matDetectFace(matType, matData, width, height); codes = getClient().matGetCodeInfo(matType, matData, width, height, faceNum,codes); // 没有检测到要求的人脸则抛出异常 if(0 == codes.length){ throw new NotFaceDetectedException(); } if(faceNum>0 && faceNum != codes.length){ throw new NotFaceDetectedException(); } return codes; } @Override public Boolean matWearMask(MatType matType, byte[] matData, int width, int height, CodeInfo faceInfo) { return getClient().matWearMask(matType, matData, width, height, faceInfo); } @Override public FseResult[] searchFeatures(byte[] feature, double similarty, int rows, String[] imgMD5Set, int group) { return getClient().searchFeatures(feature, similarty, rows, imgMD5Set, group); } @Override public Map sdkCapacity() { Map capacity = getClient().sdkCapacity(); capacity.put(C_LOCAL_DETECT, Boolean.TRUE.toString()); return capacity; } static { try { init(); } catch (SdkInitException e) { SimpleLog.log(e); throw new ExceptionInInitializerError(e); } // add hook for release JNI resource on JVM shutdown Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { SimpleLog.log("release mtfsdk JNI resoure..."); for(int channelId = 0,channelNum = concurrency.get();channelId < channelNum;++channelId){ JNA.FSSDKRelease(channelId); } // 如果用 logger 输出不能显示,why? SimpleLog.log("release mtfsdk JNI resoure finished"); } }); // 根据配置参数初始化通道资源池 channelPool = new IntResourcePool(concurrency.get()); } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("FaceApiMtfClient [client="); builder.append(client); builder.append("]"); return builder.toString(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy