001package net.gdface.sdk; 002 003import java.nio.ByteBuffer; 004import java.util.ArrayList; 005import java.util.List; 006import java.util.Map; 007 008import net.gdface.image.BaseLazyImage; 009import net.gdface.image.ImageErrorException; 010import net.gdface.image.MatType; 011import net.gdface.image.NotImageException; 012import net.gdface.image.UnsupportedFormatException; 013import net.gdface.sdk.fse.FeatureSe; 014import net.gdface.utils.Assert; 015 016/** 017 * {@link FaceApi}抽象实现,SDK接å£ç±»å¿…须从æ¤ç±»æ´¾ç”Ÿ<br> 018 * @author guyadong 019 * 020 */ 021public abstract class BaseFaceApi implements FaceApi{ 022 023 protected BaseFaceApi() { 024 } 025 @Override 026 public double compare2Face(byte[] imgData1, CodeInfo facePos1, byte[] imgData2, CodeInfo facePos2) 027 throws NotFaceDetectedException { 028 if(0==imgData1.length){ 029 imgData1=null; 030 } 031 if(0==imgData2.length){ 032 imgData2=null; 033 } 034 byte[] code1, code2; 035 Assert.notNull(facePos1, "facePos1"); 036 Assert.notNull(facePos2, "facePos2"); 037 if (imgData1 == imgData2||null==imgData2) { 038 CodeInfo[] codes = getCodeInfo(imgData1, 2, new CodeInfo[] { facePos1, facePos2 }); 039 code1 = codes[0].getCode(); 040 code2 = codes[1].getCode(); 041 } else { 042 code1 = getCodeInfo(imgData1, 1, new CodeInfo[] { facePos1 })[0].getCode(); 043 code2 = getCodeInfo(imgData2, 1, new CodeInfo[] { facePos2 })[0].getCode(); 044 } 045 return compareCode(code1, code2); 046 } 047 @Override 048 public CompareResult compareFaces(byte[] code, byte[] imgData, int faceNum) 049 throws NotFaceDetectedException, ImageErrorException { 050 CodeInfo[] codes = detectAndGetCodeInfo(imgData,faceNum); 051 double[] similartys = compareCodes(code,codes); 052 return new CompareResult(codes,similartys); 053 } 054 @Override 055 public double detectAndCompare2Face(byte[] imgData1, FRect detectRect1, byte[] imgData2, FRect detectRect2) 056 throws ImageErrorException, NotFaceDetectedException { 057 if(null != imgData1 && 0==imgData1.length){ 058 imgData1=null; 059 } 060 if(null != imgData2 && 0==imgData2.length){ 061 imgData2=null; 062 } 063 byte[] code1, code2; 064 if (imgData1 == imgData2||null==imgData2) { 065 if (detectRect1 == null || null == detectRect2){ 066 throw new IllegalArgumentException("detectRect1,detectRect2 must not be null"); 067 } 068 CodeInfo[] codes = detectAndGetCodeInfo(imgData1, 2); 069 if((detectRect1.contains(codes[0].getPos()) && detectRect2.contains(codes[1].getPos())) 070 || (detectRect2.contains(codes[0].getPos()) && detectRect1.contains(codes[1].getPos()))){ 071 code1 = codes[0].getCode(); 072 code2 = codes[1].getCode(); 073 }else{ 074 // 如果任何检测区域一个没有检测到人脸,则抛出异常 075 throw new NotFaceDetectedException("not found face in detect rectangle"); 076 } 077 } else { 078 code1 = detectAndGetCodeInfo(imgData1, 1)[0].getCode(); 079 code2 = detectAndGetCodeInfo(imgData2, 1)[0].getCode(); 080 } 081 return compareCode(code1, code2); 082 } 083 @Override 084 public List<Double> compareFeatures(byte[] code1,List<byte[]> codes){ 085 if(null == code1 || null == codes){ 086 throw new NullPointerException("code1 or codes is null"); 087 } 088 ArrayList<Double> result = new ArrayList<Double>(codes.size()); 089 for(byte[] code2:codes){ 090 result.add(compareCode(code1,code2)); 091 } 092 return result; 093 } 094 @Override 095 public double[] compareCodes(byte[] code1,CodeInfo[] codes){ 096 if(null == code1 || null == codes){ 097 throw new NullPointerException("code1 or codes is null"); 098 } 099 double[] result = new double[codes.length]; 100 for(int i = 0;i<result.length;++i){ 101 result[i] = compareCode(code1,codes[i].getCode()); 102 } 103 return result; 104 } 105 /** 106 * é€šè¿‡å›¾åƒæ•°æ®å—节æµ(byte[])创建FaceImage对象<br> 107 * 调用{@link BaseLazyImage#setAutoClose(boolean)}设置 autClose为{@code false}<br> 108 * å¦‚æžœæœ‰ç‰¹æ®Šè¦æ±‚,åç±»å¯ä»¥é‡å†™æ¤æ–¹æ³• 109 * @param imgData 110 * @return 111 * @throws UnsupportedFormatException 112 * @throws NotImageException 113 * @see BaseLazyImage#open() 114 * @see BaseLazyImage#setAutoClose(boolean) 115 */ 116 protected BaseLazyImage makeOpenedLazyImage(byte[] imgData) throws UnsupportedFormatException, NotImageException { 117 return BaseLazyImage.getLazyImageFactory().create(imgData).setAutoClose(false).open(); 118 } 119 120 @Override 121 public CodeInfo detectCenterFace(byte[] imgData) throws NotFaceDetectedException, ImageErrorException { 122 BaseLazyImage lazyImg = BaseLazyImage.getLazyImageFactory().create(imgData); 123 CodeInfo centerFace; 124 CodeInfo[] codes = detectFace(imgData); 125 if(codes.length == 0){ 126 throw new NotFaceDetectedException(); 127 } 128 FInt2 center=new FInt2(lazyImg.getWidth()>>1,lazyImg.getHeight()>>1); 129 centerFace=codes[0]; 130 double minDistance = RectUtils.distance(centerFace.getPos(), center); 131 for(int i=1;i<codes.length;++i){ 132 CodeInfo f=codes[i]; 133 double d = RectUtils.distance(f.getPos(), center); 134 if(d<minDistance){ 135 centerFace=f; 136 minDistance=d; 137 } 138 } 139 return centerFace; 140 } 141 protected CodeInfo findMaxFace(CodeInfo[] facePos){ 142 if(facePos != null && facePos.length != 0){ 143 int maxArea = 0; 144 CodeInfo maxFace = null; 145 // 按矩形é¢ç§¯æŒ‘出最大人脸矩形 146 for(CodeInfo c:facePos){ 147 if(c != null){ 148 FRect rect = c.getPos(); 149 if(rect != null){ 150 int area = rect.getWidth()*rect.getHeight(); 151 if(maxArea < area){ 152 maxArea = area; 153 maxFace = c; 154 } 155 } 156 } 157 } 158 return maxFace; 159 } 160 return null; 161 } 162 @Override 163 public CodeInfo detectMaxFace(byte[] imgData) throws NotFaceDetectedException, ImageErrorException { 164 CodeInfo[] codes = detectFace(imgData); 165 CodeInfo maxFace = findMaxFace(codes); 166 if(maxFace == null){ 167 throw new NotFaceDetectedException(); 168 } 169 return maxFace; 170 } 171 @Override 172 public boolean hasFace(byte[] imgData) throws ImageErrorException { 173 try { 174 detectAndGetCodeInfo(imgData, 0); 175 return true; 176 } catch (NotFaceDetectedException e) { 177 return false; 178 } 179 } 180 @Override 181 public boolean matHasFace(MatType matType,byte[] matData,int width, int height){ 182 try { 183 matDetectAndGetCodeInfo(matType, matData, width,height, 0); 184 return true; 185 } catch (NotFaceDetectedException e) { 186 return false; 187 } 188 } 189 @Override 190 public CodeInfo matDetectMaxFace(MatType matType,byte[] matData,int width, int height) throws NotFaceDetectedException { 191 CodeInfo[] facePos = matDetectFace(matType, matData, width,height); 192 CodeInfo maxFace = findMaxFace(facePos); 193 if(maxFace == null){ 194 throw new NotFaceDetectedException(); 195 } 196 return maxFace; 197 } 198 @Override 199 public byte[] getFeature(Map<ByteBuffer, CodeInfo> faces) throws NotFaceDetectedException { 200 throw new UnsupportedOperationException(); 201 } 202 @Override 203 public FseResult[] searchFaces(byte[] imgData, CodeInfo facePos, double similarty, int rows) 204 throws NotFaceDetectedException, ImageErrorException { 205 if(null == facePos ){ 206 facePos = detectAndGetCodeInfo(imgData, 1)[0]; 207 }else if(null == facePos.getCode()){ 208 facePos = getCodeInfo(imgData, 1, new CodeInfo[] {facePos})[0]; 209 } 210 return this.searchFeatures(facePos.getCode(), similarty, rows); 211 } 212 @Override 213 public FseResult[] matSearchFaces(MatType matType, byte[] matData, int width, int height, CodeInfo facePos, double similarty, 214 int rows) throws NotFaceDetectedException, ImageErrorException { 215 if(null == facePos ){ 216 facePos = matDetectAndGetCodeInfo(matType,matData,width,height, 1)[0]; 217 }else if(null == facePos.getCode()){ 218 facePos = matGetCodeInfo(matType,matData,width,height, facePos); 219 } 220 return this.searchFeatures(facePos.getCode(), similarty, rows); 221 } 222 /** 223 * è¿”å›žç”¨äºŽå›¾åƒæ£€æµ‹å’Œå»ºæ¨¡çš„图åƒçŸ©é˜µçš„(色彩空间)类型<br> 224 * ä¸å¯è¿”回{@code null} 225 * @return 矩阵类型 226 */ 227 protected abstract MatType getNativeMatrixType(); 228 /** 229 * 将指定的图åƒçŸ©é˜µè½¬ä¸ºå›¾åƒæ£€æµ‹å’Œå»ºæ¨¡çš„图åƒçŸ©é˜µçš„(色彩空间)类型(å‚è§ {@link #getNativeMatrixType()}) 230 * @param matType 输入矩阵类型 231 * @param matData çŸ©é˜µæ•°æ® 232 * @param width 矩阵宽度 233 * @param height 矩阵高度 234 * @return 转æ¢åŽçš„çŸ©é˜µæ•°æ® 235 */ 236 protected abstract byte[] toNativeMatrix(MatType matType, byte[] matData, int width, int height); 237 /** 238 * 从{@link FaceApi}实例获å–å†…å˜æœç´¢å¼•擎接å£å®žä¾‹<br> 239 * 如果{@link FaceApi}䏿˜¯{@link BaseFaceApiLocal}实例返回{@code null} 240 * @param faceapi 241 * @return 242 */ 243 public static final FeatureSe getFeatureSeInstance(FaceApi faceapi){ 244 if(faceapi instanceof BaseFaceApiLocal){ 245 return ((BaseFaceApiLocal)faceapi).getFeatureSe(); 246 } 247 return null; 248 } 249}