优化模型及添加图片存储实现,实现自动调度刷新milvus数据

This commit is contained in:
divenswu 2022-06-26 21:34:44 +08:00
parent 857c3e155b
commit 8b921fbb83
227 changed files with 1375 additions and 34 deletions

0
face-search-client/pom.xml Normal file → Executable file
View File

View File

@ -0,0 +1,47 @@
package com.visual.face.search;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.visual.face.search.handle.CompareHandler;
public class FaceCompare {
/**服务地址**/
private String serverHost;
/**实例对象**/
private final static Map<String, FaceCompare> ins = new ConcurrentHashMap<>();
/**
* 构建集合对象
* @param serverHost 服务地址
* @return
*/
private FaceCompare(String serverHost){
this.serverHost = serverHost;
}
/**
* 构建集合对象
* @param serverHost 服务地址
* @return
*/
public static FaceCompare build (String serverHost){
String key = serverHost;
if(!ins.containsKey(key)){
synchronized (FaceCompare.class){
if(!ins.containsKey(key)){
ins.put(key, new FaceCompare(serverHost));
}
}
}
return ins.get(key);
}
/**
* 人脸比对操作对象
* @return CollectHandler
*/
public CompareHandler compare(){
return CompareHandler.build(serverHost);
}
}

View File

@ -17,6 +17,7 @@ public class Api {
public static final String face_create = "/visual/face/create"; public static final String face_create = "/visual/face/create";
public static final String visual_search = "/visual/search/do"; public static final String visual_search = "/visual/search/do";
public static final String visual_compare = "/visual/compare/do";
public static String getUrl(String host, String uri){ public static String getUrl(String host, String uri){
host = host.replaceAll ("/+$", ""); host = host.replaceAll ("/+$", "");

View File

@ -47,7 +47,9 @@ public class CollectHandler extends BaseHandler<CollectHandler>{
.setSampleColumns(collect.getSampleColumns()) .setSampleColumns(collect.getSampleColumns())
.setFaceColumns(collect.getFaceColumns()) .setFaceColumns(collect.getFaceColumns())
.setSyncBinLog(collect.isSyncBinLog()) .setSyncBinLog(collect.isSyncBinLog())
.setShardsNum(collect.getShardsNum()); .setShardsNum(collect.getShardsNum())
.setStorageFaceInfo(collect.getStorageFaceInfo())
.setStorageEngine(collect.getStorageEngine());
return HttpClient.post(Api.getUrl(this.serverHost, Api.collect_create), collectReq); return HttpClient.post(Api.getUrl(this.serverHost, Api.collect_create), collectReq);
} }

View File

@ -0,0 +1,58 @@
package com.visual.face.search.handle;
import com.alibaba.fastjson.TypeReference;
import com.visual.face.search.common.Api;
import com.visual.face.search.http.HttpClient;
import com.visual.face.search.model.*;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class CompareHandler {
/**服务地址**/
protected String serverHost;
/**实例对象**/
private final static Map<String, CompareHandler> ins = new ConcurrentHashMap<>();
public String getServerHost() {
return serverHost;
}
public CompareHandler setServerHost(String serverHost) {
this.serverHost = serverHost;
return this;
}
/**
* 构建集合对象
* @param serverHost 服务地址
* @return
*/
public static CompareHandler build(String serverHost){
String key = serverHost;
if(!ins.containsKey(key)){
synchronized (CollectHandler.class){
if(!ins.containsKey(key)){
ins.put(key, new CompareHandler().setServerHost(serverHost));
}
}
}
return ins.get(key);
}
/**
* 人脸比对
* @param compare 集合的定义信息
* @return 是否创建成功
*/
public Response<CompareRep> faceCompare(Compare compare){
CompareReq compareReq = CompareReq.build()
.setImageBase64A(compare.getImageBase64A())
.setImageBase64B(compare.getImageBase64B())
.setFaceScoreThreshold(compare.getFaceScoreThreshold())
.setNeedFaceInfo(compare.getNeedFaceInfo());
return HttpClient.post(Api.getUrl(this.serverHost, Api.visual_compare), compareReq, new TypeReference<Response<CompareRep>>() {});
}
}

View File

@ -20,6 +20,10 @@ public class Collect<ExtendsVo extends Collect<ExtendsVo>> implements Serializab
private List<FiledColumn> faceColumns = new ArrayList<>(); private List<FiledColumn> faceColumns = new ArrayList<>();
/**启用binlog同步**/ /**启用binlog同步**/
private Boolean syncBinLog = false; private Boolean syncBinLog = false;
/**是否保留图片及人脸信息**/
private Boolean storageFaceInfo = false;
/**保留图片及人脸信息的存储组件**/
private StorageEngine storageEngine;
/** /**
* 构建集合对象 * 构建集合对象
@ -92,4 +96,26 @@ public class Collect<ExtendsVo extends Collect<ExtendsVo>> implements Serializab
} }
return (ExtendsVo) this; return (ExtendsVo) this;
} }
public boolean getStorageFaceInfo() {
return null == storageFaceInfo ? false : storageFaceInfo;
}
public ExtendsVo setStorageFaceInfo(Boolean storageFaceInfo) {
if(null != storageFaceInfo){
this.storageFaceInfo = storageFaceInfo;
}
return (ExtendsVo) this;
}
public StorageEngine getStorageEngine() {
return storageEngine;
}
public ExtendsVo setStorageEngine(StorageEngine storageEngine) {
if(null != storageEngine){
this.storageEngine = storageEngine;
}
return (ExtendsVo) this;
}
} }

View File

@ -0,0 +1,67 @@
package com.visual.face.search.model;
import java.io.Serializable;
public class Compare <ExtendsVo extends Compare<ExtendsVo>> implements Serializable {
/**图像Base64编码值**/
private String imageBase64A;
/**图像Base64编码值**/
private String imageBase64B;
/**人脸质量分数阈值:人脸质量分数阈值,范围:[0,100]默认0。当设置为0时会默认使用当前模型的默认值该方法为推荐使用方式**/
private Float faceScoreThreshold = 0f;
/**是否需要人脸信息**/
private Boolean needFaceInfo = true;
/**
* 构建比对对象
* @return
*/
public static Compare build(){
return new Compare();
}
public String getImageBase64A() {
return imageBase64A;
}
public ExtendsVo setImageBase64A(String imageBase64A) {
this.imageBase64A = imageBase64A;
return (ExtendsVo) this;
}
public String getImageBase64B() {
return imageBase64B;
}
public ExtendsVo setImageBase64B(String imageBase64B) {
this.imageBase64B = imageBase64B;
return (ExtendsVo) this;
}
public Float getFaceScoreThreshold() {
return faceScoreThreshold;
}
public ExtendsVo setFaceScoreThreshold(Float faceScoreThreshold) {
if(null != faceScoreThreshold && faceScoreThreshold >= 0 && faceScoreThreshold <= 100){
this.faceScoreThreshold = faceScoreThreshold;
}
return (ExtendsVo) this;
}
public Boolean getNeedFaceInfo() {
return needFaceInfo;
}
public ExtendsVo setNeedFaceInfo(Boolean needFaceInfo) {
if(null != needFaceInfo){
this.needFaceInfo = needFaceInfo;
}
return (ExtendsVo) this;
}
}

View File

@ -0,0 +1,47 @@
package com.visual.face.search.model;
public class CompareFace {
/**A图片人脸分数:[0,100]**/
private Float faceScoreA;
/**B图片人脸分数:[0,100]**/
private Float faceScoreB;
/**A图片人脸位置信息**/
private FaceLocation locationA;
/**B图片人脸位置信息**/
private FaceLocation locationB;
public Float getFaceScoreA() {
return faceScoreA;
}
public void setFaceScoreA(Float faceScoreA) {
this.faceScoreA = faceScoreA;
}
public FaceLocation getLocationA() {
return locationA;
}
public void setLocationA(FaceLocation locationA) {
this.locationA = locationA;
}
public Float getFaceScoreB() {
return faceScoreB;
}
public void setFaceScoreB(Float faceScoreB) {
this.faceScoreB = faceScoreB;
}
public FaceLocation getLocationB() {
return locationB;
}
public void setLocationB(FaceLocation locationB) {
this.locationB = locationB;
}
}

View File

@ -0,0 +1,40 @@
package com.visual.face.search.model;
import java.io.Serializable;
public class CompareRep implements Serializable {
/**向量欧式距离:>=0**/
private Float distance;
/**余弦距离转换后的置信度:[-100,100],值越大,相似度越高。**/
private Float confidence;
/**人脸信息,参数needFaceInfo=false时值为null**/
private CompareFace faceInfo;
public Float getDistance() {
return distance;
}
public CompareRep setDistance(Float distance) {
this.distance = distance;
return this;
}
public Float getConfidence() {
return confidence;
}
public CompareRep setConfidence(Float confidence) {
this.confidence = confidence;
return this;
}
public CompareFace getFaceInfo() {
return faceInfo;
}
public CompareRep setFaceInfo(CompareFace faceInfo) {
this.faceInfo = faceInfo;
return this;
}
}

View File

@ -0,0 +1,13 @@
package com.visual.face.search.model;
public class CompareReq extends Compare<CompareReq> {
/**
* 构建比对对象
* @return
*/
public static CompareReq build(){
return new CompareReq();
}
}

View File

@ -0,0 +1,8 @@
package com.visual.face.search.model;
public enum StorageEngine {
CURR_DB,
ALI_OSS,
TCE_COS,
MIN_IO
}

0
face-search-core/pom.xml Normal file → Executable file
View File

View File

@ -0,0 +1,37 @@
package com.visual.face.search.core.utils;
public class ArrayUtil {
public static double [] floatToDouble(float[] input){
if (input == null){
return null;
}
double[] output = new double[input.length];
for (int i = 0; i < input.length; i++){
output[i] = input[i];
}
return output;
}
public static float [] doubleToFloat(double[] input){
if (input == null){
return null;
}
float[] output = new float[input.length];
for (int i = 0; i < input.length; i++){
output[i] = Double.valueOf(input[i]).floatValue();
}
return output;
}
public static double matrixNorm(double[][] matrix){
double sum=0.0;
for(double[] temp1:matrix){
for(double temp2:temp1){
sum+=Math.pow(temp2,2);
}
}
return Math.sqrt(sum);
}
}

View File

@ -1,6 +1,8 @@
package com.visual.face.search.core.utils; package com.visual.face.search.core.utils;
import org.opencv.core.Mat; import org.opencv.core.Mat;
import org.opencv.core.Range;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -42,9 +44,6 @@ public class MatUtil {
byteArrayOutputStream = new ByteArrayOutputStream(); byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(matToBufferedImage(mat), "jpg", byteArrayOutputStream); ImageIO.write(matToBufferedImage(mat), "jpg", byteArrayOutputStream);
byte[] bytes = byteArrayOutputStream.toByteArray(); byte[] bytes = byteArrayOutputStream.toByteArray();
// 新版本JDK被移除替换为Base64.Encoder
// BASE64Encoder encoder = new BASE64Encoder();
// return encoder.encodeBuffer(Objects.requireNonNull(bytes));
Base64.Encoder encoder = Base64.getMimeEncoder(); Base64.Encoder encoder = Base64.getMimeEncoder();
return encoder.encodeToString(Objects.requireNonNull(bytes)); return encoder.encodeToString(Objects.requireNonNull(bytes));
}catch (Exception e){ }catch (Exception e){
@ -58,4 +57,41 @@ public class MatUtil {
} }
} }
/**
* 横向拼接两个图像的数据Mat该两个图像的类型必须是相同的类型均为CvType.CV_8UC3类型
* @author bailichun
* @since 2020.02.20 15:00
* @param m1 要合并的图像1左图
* @param m2 要合并的图像2右图
* @return 拼接好的Mat图像数据集其高度等于两个图像中高度较大者的高度其宽度等于两个图像的宽度之和类型与两个输入图像相同
* @throws Exception 当两个图像数据的类型不同时抛出异常
*/
public static Mat concat(Mat m1, Mat m2){
if(m1.type() != m2.type()){
throw new RuntimeException("concat:两个图像数据的类型不同!");
}
long time = System.currentTimeMillis();
//宽度为两图的宽度之和
double w = m1.size().width + m2.size().width;
//高度取两个矩阵中的较大者的高度
double h = m1.size().height > m2.size().height ? m1.size().height : m2.size().height;
//创建一个大矩阵对象
Mat des = Mat.zeros((int)h, (int)w, m1.type());
//在最终的大图上标记一块区域用于存放复制图1左图的数据大小为从第0列到m1.cols()
Mat rectForM1 = des.colRange(new Range(0, m1.cols()));
//标记出位于rectForM1的垂直方向上中间位置的区域高度为图1的高度此时该区域的大小已经和图1的大小相同用于存放复制图1左图的数据
int rowOffset1 = (int)(rectForM1.size().height-m1.rows())/2;
rectForM1 = rectForM1.rowRange(rowOffset1, rowOffset1 + m1.rows());
//在最终的大图上标记一块区域用于存放复制图2右图的数据
Mat rectForM2 = des.colRange(new Range(m1.cols(), des.cols()));
//标记出位于rectForM2的垂直方向上中间位置的区域高度为图2的高度此时该区域的大小已经和图2的大小相同用于存放复制图2右图的数据
int rowOffset2 = (int)(rectForM2.size().height-m2.rows())/2;
rectForM2 = rectForM2.rowRange(rowOffset2, rowOffset2 + m2.rows());
//将图1拷贝到des的指定区域 rectForM1
m1.copyTo(rectForM1);
//将图2拷贝到des的指定区域 rectForM2
m2.copyTo(rectForM2);
return des;
}
} }

View File

@ -1,5 +1,8 @@
package com.visual.face.search.core.utils; package com.visual.face.search.core.utils;
import org.apache.commons.math3.linear.RealMatrix;
import static com.visual.face.search.core.utils.ArrayUtil.matrixNorm;
public class Similarity { public class Similarity {
/** /**
@ -52,4 +55,25 @@ public class Similarity {
return (float) distance; return (float) distance;
} }
/**
* 向量余弦相似度,加入了norm变换
* @param leftVector
* @param rightVector
* @return
*/
public static float cosineSimilarityNorm(float[] leftVector, float[] rightVector) {
RealMatrix rm1 = MathUtil.createMatrix(1, ArrayUtil.floatToDouble(leftVector));
RealMatrix rm2 = MathUtil.createMatrix(1, ArrayUtil.floatToDouble(rightVector));
RealMatrix num = rm1.multiply(rm2.transpose());
double deco = matrixNorm(rm1.getData()) * matrixNorm(rm2.getData());
double cos = num.getEntry(0, 0) / deco;
double sim = cos;
if(cos >= 0.5){
sim = cos + 2 * (cos - 0.5) * (1 - cos);
}else if(cos >= 0){
sim = cos - 2 * (cos - 0.5) * (0 - cos);
}
return Double.valueOf(sim).floatValue();
}
} }

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 150 KiB

View File

Before

Width:  |  Height:  |  Size: 248 KiB

After

Width:  |  Height:  |  Size: 248 KiB

0
face-search-engine/libs/milvus-java-sdk-2.0.0.jar Normal file → Executable file
View File

Binary file not shown.

0
face-search-engine/libs/proxima-be-java-sdk-0.2.0.jar Normal file → Executable file
View File

Some files were not shown because too many files have changed in this diff Show More