001package net.gdface.sdk.fse; 002 003import java.io.File; 004import java.util.Collection; 005import java.util.HashSet; 006import java.util.Set; 007 008import net.gdface.utils.Assert; 009import net.gdface.utils.Judge; 010import net.gdface.utils.SimpleLog; 011import net.gdface.utils.TimeCostProbe; 012 013/** 014 * 特征码内存搜索引擎(FSE,feature search engine)java接口类(JNI)<br> 015 * 与{@link FseJniBridge}拆分开主要是为了便于生成c header文件<br> 016 * @author guyadong 017 * 018 */ 019public abstract class BaseFeatureSearchEngine extends FseJniBridge { 020 protected static final String ENV_FSE = "FSE_HOME"; 021 protected static final String PROP_FSE = ENV_FSE.toLowerCase(); 022 protected static final String PROP_LIBNAME = "fse_libname"; 023 protected static final String FSE_LIBNAME = getFseLibname(); 024 025 protected BaseFeatureSearchEngine(){ 026 } 027 028 /** 029 * 加载名为{@code libname}的动态库, 030 * 如果{@code libdir}为{@code null}则调用{@link System#loadLibrary(String)}在系统搜索路径下查找动态库, 031 * 否则调用{@link System#load(String)}加载{@code libdir}指定路径下的动态库 032 * @param libdir 033 * @param libname 034 */ 035 protected static void loadLibrary(String libdir, String libname) { 036 Assert.notEmpty(libname, "libname"); 037 if(null == libdir){ 038 SimpleLog.log("load dynamic library: {}", libname); 039 System.loadLibrary(libname); 040 }else{ 041 String filename = new File(libdir,System.mapLibraryName(libname)).getAbsolutePath(); 042 SimpleLog.log("load dynamic library: {}", filename); 043 System.load(filename); 044 } 045 } 046 047 /** 048 * 查找 fse_home变量<br> 049 * 优先在系统变量定义中查找'fse_home',如果找不到,再在环境变量中查找'FSE_HOME'<br> 050 * 如果都找不到则返回{@code null} 051 * @return 052 */ 053 protected static final String getFseHome() { 054 String fseHome = System.getProperty(PROP_FSE); 055 if(null==fseHome){ 056 if(null == (fseHome=System.getenv(ENV_FSE))){ 057 SimpleLog.log("UNDEFINED {}," 058 + "you can defined the variable by java -D{}=<value> OR set environment variable '{}'", 059 PROP_FSE,PROP_FSE,ENV_FSE); 060 }else{ 061 SimpleLog.log("environment variable {}={}",ENV_FSE, fseHome); 062 } 063 }else{ 064 SimpleLog.log("{}={},defined by java -D<name>=<value>",PROP_FSE, fseHome); 065 } 066 return fseHome; 067 } 068 protected static final String getFseLibname() { 069 String libname = System.getProperty(PROP_LIBNAME); 070 if(null!=libname){ 071 SimpleLog.log("{}={},defined by java -D<name>=<value>", PROP_LIBNAME,libname); 072 } 073 return libname; 074 } 075 /** 076 * 用缺省值初始化 077 */ 078 protected static void init(){ 079 init(DEFAULT_MODE,DEFAULT_INITIAL_CAPACITY,DEFAULT_LOAD_FACTOR,DEFAULT_OVERBLOCK_CAPACITY); 080 } 081 /** 082 * 特征码{@code code}与数据库中的特征码比对,以相似度降序返回比对结果<br> 083 * 084 * @param code 085 * @param sim 086 * @param rows 087 * @param imgMD5Set 088 * @param timeCost 089 * @return {@link CodeBean}数组 090 * @see #searchCode(byte[], double, int, String[]) 091 */ 092 public static final CodeBean[] searchCode(byte[] code, double sim, int rows, Set<String>imgMD5Set, TimeCostProbe timeCost){ 093 if(null!=timeCost){ 094 timeCost.begin(); 095 } 096 try{ 097 return searchCode(code, sim, rows, imgMD5Set==null?null:imgMD5Set.toArray(new String[0])); 098 }finally{ 099 if(null!=timeCost){ 100 timeCost.end(); 101 } 102 } 103 } 104 105 /** 106 * 参见 {@link #searchCode(byte[], double, int, Set, TimeCostProbe)} 107 * @param code 108 * @param sim 109 * @param rows 110 * @param imgMD5Set 111 * @param timeCost 112 * @return 113 * @see #searchCode(byte[], double, int, Set, TimeCostProbe) 114 */ 115 public static final CodeBean[] searchCode(byte[] code, double sim, int rows, Collection<String>imgMD5Set, TimeCostProbe timeCost){ 116 return searchCode(code, sim, rows, imgMD5Set==null?null:new HashSet<String>(imgMD5Set), timeCost); 117 } 118 119 /** 120 * @return 动态库已经正确加载则返回false,否则返回false 121 */ 122 public static boolean isLibraryLoaded() { 123 return libraryLoaded; 124 } 125 126 /** 127 * 实现{@link FeatureSe} 128 * @author guyadong 129 * 130 */ 131 public static class FeatureSeImpl extends BaseFeatureSeImpl{ 132 private final String name; 133 /** 134 * @param name 封装实现{@link FseJniBridge}的类名,用于区分实例 135 */ 136 public FeatureSeImpl(String name) { 137 super(); 138 this.name = name; 139 } 140 141 @Override 142 public CodeBean[] searchCode(byte[] code, double sim, int rows) { 143 return BaseFeatureSearchEngine.searchCode(code, sim, rows, null); 144 } 145 146 @Override 147 public CodeBean getFeature(byte[] featureId) { 148 return Judge.isEmpty(featureId) ? null : BaseFeatureSearchEngine.getFeature(featureId); 149 } 150 151 @Override 152 public boolean addFeature(byte[] featureId, byte[] feature, String imgMD5) { 153 return Judge.isEmpty(feature) ? false : BaseFeatureSearchEngine.addFeature(featureId, feature, imgMD5); 154 } 155 @Override 156 public boolean addFeature(byte[] featureId, byte[] feature, long appid) { 157 return addFeature(featureId, feature, CodeBean.asImgMD5(appid)); 158 } 159 @Override 160 public boolean removeFeature(byte[] featureId) { 161 return Judge.isEmpty(featureId) ? false : BaseFeatureSearchEngine.removeFeature(featureId); 162 } 163 @Override 164 public void clearAll(){ 165 BaseFeatureSearchEngine.clearAll(); 166 } 167 168 @Override 169 public int size() { 170 return BaseFeatureSearchEngine.size(); 171 } 172 @Override 173 public String toString() { 174 StringBuilder builder = new StringBuilder(); 175 builder.append("BaseFeatureSe [jniBridge=").append(name).append("]"); 176 return builder.toString(); 177 } 178 }; 179 180}