|
|
@@ -0,0 +1,160 @@
|
|
|
+package com.ktg.common.utils.face;
|
|
|
+
|
|
|
+import cn.hutool.core.lang.Assert;
|
|
|
+import com.ktg.common.config.RuoYiConfig;
|
|
|
+import com.ktg.common.utils.StringUtils;
|
|
|
+import com.ktg.common.vo.FaceCutVO;
|
|
|
+import org.opencv.core.*;
|
|
|
+import org.opencv.imgcodecs.Imgcodecs;
|
|
|
+import org.opencv.imgproc.Imgproc;
|
|
|
+import org.opencv.objdetect.CascadeClassifier;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.web.multipart.MultipartFile;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.nio.file.Files;
|
|
|
+import java.nio.file.Path;
|
|
|
+import java.nio.file.Paths;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 面部裁剪工具
|
|
|
+ *
|
|
|
+ * @author cgj
|
|
|
+ */
|
|
|
+public class FaceCutUtil
|
|
|
+{
|
|
|
+
|
|
|
+ @Value("${ktg-mes.prod}")
|
|
|
+ private static String prodApi;
|
|
|
+
|
|
|
+ public static void main(String[] args) throws IOException {
|
|
|
+ imageFaceDetection(null, 1L, null);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始化人脸探测器
|
|
|
+ static CascadeClassifier faceDetector;
|
|
|
+ /**
|
|
|
+ * 图片人脸检测
|
|
|
+ */
|
|
|
+ public static FaceCutVO imageFaceDetection(MultipartFile file, Long userId, String url) throws IOException {
|
|
|
+ // ------------------------加载OpenCV本地库--------------------------------------------
|
|
|
+ // System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
|
|
|
+ String loadPath = "/guoruan/app/opencv/build/java/x64/opencv_java470.dll";
|
|
|
+ if (StringUtils.isBlank(prodApi)) {
|
|
|
+ loadPath = "C:/work/app/install/opencv/build/java/x64/opencv_java470.dll";
|
|
|
+ }
|
|
|
+ System.load(loadPath);
|
|
|
+ // System.loadLibrary("C:/work/app/install/opencv/build/java/opencv-460.jar");
|
|
|
+ // 从配置文件lbpcascade_frontalface.xml中创建一个人脸识别器,文件位于opencv安装目录中
|
|
|
+ String faceDetectorPath = "/guoruan/app/opencv/sources/data/haarcascades/haarcascade_frontalface_alt.xml";
|
|
|
+ if (StringUtils.isBlank(prodApi)) {
|
|
|
+ faceDetectorPath = "C:/work/app/install/opencv/sources/data/haarcascades/haarcascade_frontalface_alt.xml";
|
|
|
+ // faceDetectorPath = "C:\\work\\app\\install\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml";
|
|
|
+ }
|
|
|
+ // CascadeClassifier faceDetector = new CascadeClassifier(faceDetectorPath);
|
|
|
+ String property = "C:/work/app/install/opencv/sources/data/haarcascades/haarcascade_frontalface_alt.xml";
|
|
|
+ System.out.println(property);
|
|
|
+ faceDetector = new CascadeClassifier(property);
|
|
|
+
|
|
|
+ // -------------------- 定义文件的基础属性----------------------------
|
|
|
+ // 人脸存储基础路径
|
|
|
+ String profile = RuoYiConfig.getProfile();
|
|
|
+ String basePath = profile + "/face/" + userId +"/";
|
|
|
+ if (StringUtils.isBlank(prodApi)) {
|
|
|
+ basePath = "C:" + basePath;
|
|
|
+ }
|
|
|
+ // 原文件裁剪后的路径
|
|
|
+ String content;
|
|
|
+ // 原文件转存后的路径
|
|
|
+ String imagePath;
|
|
|
+ // 原文件转存后的前端请求路径
|
|
|
+ String imageUrl = null;
|
|
|
+
|
|
|
+ // 时间戳
|
|
|
+ long currentTimestamp = System.currentTimeMillis();
|
|
|
+ // 设置文件路径
|
|
|
+ String filePath = basePath ;
|
|
|
+ // 确保目录存在,不存在则创建一个
|
|
|
+ Path uploadPath = Paths.get(filePath);
|
|
|
+ if (!Files.exists(uploadPath)) {
|
|
|
+ Files.createDirectories(uploadPath);
|
|
|
+ }
|
|
|
+ // 获取文件名并构建目标路径
|
|
|
+ String fileName = userId + "_" + currentTimestamp + "_" + file.getOriginalFilename();
|
|
|
+ Path targetLocation = uploadPath.resolve(fileName);
|
|
|
+ imagePath = filePath + fileName;
|
|
|
+ // 获取前端的请求路径地址
|
|
|
+ if (imagePath.contains("C:" + profile)) {
|
|
|
+ imageUrl = imagePath.replace("C:" + profile, url + "/profile");
|
|
|
+ } else if (imagePath.contains(profile)) {
|
|
|
+ imageUrl = imagePath.replace(profile, url + "/prod-api" + "/profile");
|
|
|
+ }
|
|
|
+ // 将文件写入目标路径
|
|
|
+ file.transferTo(targetLocation.toFile());
|
|
|
+
|
|
|
+ // 读取测试图片
|
|
|
+ Mat image = Imgcodecs.imread(imagePath);
|
|
|
+ if (image.empty()) {
|
|
|
+ throw new RuntimeException("图片内存为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检测脸部
|
|
|
+ MatOfRect face = new MatOfRect();
|
|
|
+ // 检测图像中的人脸
|
|
|
+ faceDetector.detectMultiScale(image, face);
|
|
|
+ // 匹配Rect矩阵
|
|
|
+ Rect[] rects = face.toArray();
|
|
|
+ System.out.println("识别人脸个数: " + rects.length);
|
|
|
+ Assert.isFalse(rects.length > 1, "识别到多张人脸,请重新调整位置!");
|
|
|
+
|
|
|
+ // 识别图片中的所有人脸并分别保存
|
|
|
+ // int i = 1;
|
|
|
+ // 上面做了限制,现在其实只会有一张人脸
|
|
|
+ FaceCutVO faceCutVO = new FaceCutVO();
|
|
|
+ for (Rect rect : face.toArray()) {
|
|
|
+ Imgproc.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 255, 0), 3);
|
|
|
+ // 进行图片裁剪
|
|
|
+ String cutImgName = userId + "_cut_" + currentTimestamp + ".jpg";
|
|
|
+ content = filePath + cutImgName;
|
|
|
+ imageCut(imagePath, content, rect.x, rect.y, rect.width, rect.height);
|
|
|
+ // i++;
|
|
|
+ faceCutVO.setUserId(userId);
|
|
|
+ faceCutVO.setType("2");
|
|
|
+ faceCutVO.setContent(content);
|
|
|
+ faceCutVO.setImageUrl(imageUrl);
|
|
|
+ faceCutVO.setImagePath(imagePath);
|
|
|
+ }
|
|
|
+ // ---------------------以下为前端的裁剪动画展示--------------------
|
|
|
+ // 图片中人脸画框保存到本地
|
|
|
+ // Imgcodecs.imwrite("C:/work/file/test1.png", image);
|
|
|
+ // 展示图片
|
|
|
+ // HighGui.imshow("人脸识别", image);
|
|
|
+ // HighGui.waitKey(0);
|
|
|
+
|
|
|
+ return faceCutVO;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 裁剪人脸
|
|
|
+ *
|
|
|
+ * @param readPath 读取文件路径
|
|
|
+ * @param outPath 写出文件路径
|
|
|
+ * @param x 坐标X
|
|
|
+ * @param y 坐标Y
|
|
|
+ * @param width 截图宽度
|
|
|
+ * @param height 截图长度
|
|
|
+ */
|
|
|
+ public static void imageCut(String readPath, String outPath, int x, int y, int width, int height) {
|
|
|
+ // 原始图像
|
|
|
+ Mat image = Imgcodecs.imread(readPath);
|
|
|
+ // 截取的区域
|
|
|
+ Rect rect = new Rect(x, y, width, height);
|
|
|
+ // Mat sub = new Mat(image,rect);
|
|
|
+ Mat sub = image.submat(rect);
|
|
|
+ Mat mat = new Mat();
|
|
|
+ Size size = new Size(width, height);
|
|
|
+ // 人脸进行截图并保存
|
|
|
+ Imgproc.resize(sub, mat, size);
|
|
|
+ Imgcodecs.imwrite(outPath, mat);
|
|
|
+ }
|
|
|
+}
|