diff --git a/face-search-core/src/main/java/com/visual/face/search/core/domain/FaceInfo.java b/face-search-core/src/main/java/com/visual/face/search/core/domain/FaceInfo.java index 58b9174..c8cc44b 100755 --- a/face-search-core/src/main/java/com/visual/face/search/core/domain/FaceInfo.java +++ b/face-search-core/src/main/java/com/visual/face/search/core/domain/FaceInfo.java @@ -137,6 +137,18 @@ public class FaceInfo implements Comparable, Serializable { public float distance(Point that){ return (float) Math.sqrt(Math.pow((this.x-that.x), 2)+Math.pow((this.y-that.y), 2)); } + + /** + * 将点进行平移 + * @param top 向上移动的像素点数 + * @param bottom 向下移动的像素点数 + * @param left 向左移动的像素点数 + * @param right 向右移动的像素点数 + * @return 平移后的点 + */ + public Point move(int left, int right, int top, int bottom){ + return new Point(x - left + right, y - top + bottom); + } } /** @@ -246,6 +258,22 @@ public class FaceInfo implements Comparable, Serializable { } return points; } + + /** + * 将点进行平移 + * @param top 向上移动的像素点数 + * @param bottom 向下移动的像素点数 + * @param left 向左移动的像素点数 + * @param right 向右移动的像素点数 + * @return 平移后的点 + */ + public Points move(int left, int right, int top, int bottom){ + Points points = build(); + for(Point item : this){ + points.add(item.move(left, right, top, bottom)); + } + return points; + } } /** @@ -419,6 +447,23 @@ public class FaceInfo implements Comparable, Serializable { new Point(leftBottom.x + change_x_p2_p4, leftBottom.y + change_y_p2_p4) ); } + + /** + * 将框进行平移 + * @param top 向上移动的像素点数 + * @param bottom 向下移动的像素点数 + * @param left 向左移动的像素点数 + * @param right 向右移动的像素点数 + * @return 平移后的框 + */ + public FaceBox move(int left, int right, int top, int bottom){ + return new FaceBox( + new Point(leftTop.x - left + right, leftTop.y - top + bottom), + new Point(rightTop.x - left + right, rightTop.y - top + bottom), + new Point(rightBottom.x - left + right, rightBottom.y - top + bottom), + new Point(leftBottom.x - left + right, leftBottom.y - top + bottom) + ); + } } /** diff --git a/face-search-core/src/main/java/com/visual/face/search/core/domain/ImageMat.java b/face-search-core/src/main/java/com/visual/face/search/core/domain/ImageMat.java index 28d95af..7b7e002 100755 --- a/face-search-core/src/main/java/com/visual/face/search/core/domain/ImageMat.java +++ b/face-search-core/src/main/java/com/visual/face/search/core/domain/ImageMat.java @@ -252,6 +252,55 @@ public class ImageMat implements Serializable { } } + /** + * 对图像进行补边操作,不释放原始的图片 + * @param top 向上扩展的高度 + * @param bottom 向下扩展的高度 + * @param left 向左扩展的宽度 + * @param right 向右扩展的宽度 + * @param borderType 补边的类型 + * @return 补边后的图像 + */ + public ImageMat copyMakeBorderAndNotReleaseMat(int top, int bottom, int left, int right, int borderType){ + return this.copyMakeBorder(top, bottom, left, right, borderType, false); + } + + /** + * 对图像进行补边操作,并且释放原始的图片 + * @param top 向上扩展的高度 + * @param bottom 向下扩展的高度 + * @param left 向左扩展的宽度 + * @param right 向右扩展的宽度 + * @param borderType 补边的类型 + * @return 补边后的图像 + */ + public ImageMat copyMakeBorderAndDoReleaseMat(int top, int bottom, int left, int right, int borderType){ + return this.copyMakeBorder(top, bottom, left, right, borderType, true); + } + + /** + * 对图像进行补边操作 + * @param top 向上扩展的高度 + * @param bottom 向下扩展的高度 + * @param left 向左扩展的宽度 + * @param right 向右扩展的宽度 + * @param borderType 补边的类型 + * @param release 是否释放原始的图片 + * @return 补边后的图像 + */ + private ImageMat copyMakeBorder(int top, int bottom, int left, int right, int borderType, boolean release){ + try { + Mat tempMat = new Mat(); + Core.copyMakeBorder(mat, tempMat, top, bottom, left, right, borderType); + return new ImageMat(tempMat); + }finally { + if(release){ + this.release(); + } + } + } + + /** * 对图像进行预处理,不释放原始图片数据 * @param scale 图像各通道数值的缩放比例 diff --git a/face-search-core/src/main/java/com/visual/face/search/core/models/InsightScrfdFaceDetection.java b/face-search-core/src/main/java/com/visual/face/search/core/models/InsightScrfdFaceDetection.java index e477341..a4ef168 100755 --- a/face-search-core/src/main/java/com/visual/face/search/core/models/InsightScrfdFaceDetection.java +++ b/face-search-core/src/main/java/com/visual/face/search/core/models/InsightScrfdFaceDetection.java @@ -7,6 +7,9 @@ import com.visual.face.search.core.base.BaseOnnxInfer; import com.visual.face.search.core.base.FaceDetection; import com.visual.face.search.core.domain.FaceInfo; import com.visual.face.search.core.domain.ImageMat; +import com.visual.face.search.core.utils.ReleaseUtil; +import org.opencv.core.Core; +import org.opencv.core.Mat; import org.opencv.core.Scalar; import java.util.*; @@ -32,6 +35,10 @@ public class InsightScrfdFaceDetection extends BaseOnnxInfer implements FaceDete public final static boolean defNeedCheckFaceAngle = true; //是否需要进行角度检测的参数KEY public final static String scrfdFaceNeedCheckFaceAngleParamKey = "scrfdFaceNeedCheckFaceAngle"; + //人脸框默认需要进行角度检测 + public final static boolean defNoFaceImageNeedMakeBorder = true; + //是否需要进行角度检测的参数KEY + public final static String scrfdNoFaceImageNeedMakeBorderParamKey = "scrfdNoFaceImageNeedMakeBorder"; /** * 构造函数 @@ -51,6 +58,40 @@ public class InsightScrfdFaceDetection extends BaseOnnxInfer implements FaceDete */ @Override public List inference(ImageMat image, float scoreTh, float iouTh, Map params) { + List faceInfos = this.modelInference(image, scoreTh,iouTh, params); + //对图像进行补边操作,进行二次识别 + if(this.getNoFaceImageNeedMakeBorder(params) && faceInfos.isEmpty()){ + //防止由于人脸占用大,导致检测模型识别失败 + int t = Double.valueOf(image.toCvMat().height() * 0.2).intValue(); + int b = Double.valueOf(image.toCvMat().height() * 0.2).intValue(); + int l = Double.valueOf(image.toCvMat().width() * 0.2).intValue(); + int r = Double.valueOf(image.toCvMat().width() * 0.2).intValue(); + ImageMat tempMat = null; + try { + //补边识别 + tempMat=image.copyMakeBorderAndNotReleaseMat(t, b, l, r, Core.BORDER_CONSTANT); + faceInfos = this.modelInference(tempMat, scoreTh,iouTh, params); + for(FaceInfo faceInfo : faceInfos){ + //还原原始的坐标 + faceInfo.box = faceInfo.box.move(l, 0, t, 0); + faceInfo.points = faceInfo.points.move(l, 0, t, 0); + } + }finally { + ReleaseUtil.release(tempMat); + } + } + return faceInfos; + } + + + /** + * 模型推理,获取人脸信息 + * @param image 图像信息 + * @param scoreTh 人脸人数阈值 + * @param iouTh 人脸iou阈值 + * @return 人脸模型 + */ + public List modelInference(ImageMat image, float scoreTh, float iouTh, Map params) { OnnxTensor tensor = null; OrtSession.Result output = null; ImageMat imageMat = image.clone(); @@ -252,4 +293,24 @@ public class InsightScrfdFaceDetection extends BaseOnnxInfer implements FaceDete } return needCheckFaceAngle; } + + /**获取是否需要对没有检测到人脸的图像进行补边二次识别**/ + private boolean getNoFaceImageNeedMakeBorder(Map params){ + boolean noFaceImageNeedMakeBorder = defNoFaceImageNeedMakeBorder; + try { + if(null != params && params.containsKey(scrfdNoFaceImageNeedMakeBorderParamKey)){ + Object value = params.get(scrfdNoFaceImageNeedMakeBorderParamKey); + if(null != value){ + if (value instanceof Boolean){ + noFaceImageNeedMakeBorder = (boolean) value; + }else{ + noFaceImageNeedMakeBorder = Boolean.parseBoolean(value.toString()); + } + } + } + }catch (Exception e){ + e.printStackTrace(); + } + return noFaceImageNeedMakeBorder; + } }