package com.ktg.common.utils.face;

import cn.hutool.core.lang.Assert;
import com.ktg.common.config.RuoYiConfig;
import com.ktg.common.utils.FileDriveLetterUtils;
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.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;

/**
 * 面部裁剪工具
 *
 * @author cgj
 */
public class FaceCutUtil1
{


    // 初始化人脸探测器
    static CascadeClassifier faceDetector;
    /**
     * 图片人脸检测
     */
    public static FaceCutVO imageFaceDetection(MultipartFile file, Long userId, String url) throws IOException {
        String prodApi = RuoYiConfig.getProd();
        // ------------------------加载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);
        // 从配置文件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";
        }
        faceDetector = new CascadeClassifier(faceDetectorPath);

        // -------------------- 定义文件的基础属性----------------------------
        // 人脸存储基础路径
        String profile = RuoYiConfig.getProfile();
        String basePath = FileDriveLetterUtils.getDriveLetter() + profile + "/face/" + userId +"/";
        /*if (StringUtils.isBlank(prodApi)) {
            basePath = "C:" + basePath;
        }*/
        // 原文件裁剪后的路径
        String content = null;
        // 原文件转存后的路径
        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");
        }*/
        if (StringUtils.isBlank(prodApi)) {
            imageUrl = imagePath.replace(FileDriveLetterUtils.getDriveLetter() + profile, url + "/profile");
        } else {
            imageUrl = imagePath.replace(FileDriveLetterUtils.getDriveLetter() + 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 + "_" + currentTimestamp + "_cut.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);

        // ---------------------------开始计算裁剪后的人脸直方图-----------------
        Mat mat2 = conv_Mat(content); // 将路径对应的图像转换为灰度图像的Mat对象
        if (mat2 == null) {
            return null; // 如果转换失败，返回null
        }
        Mat hist2 = computeHistogram(mat2); // 计算第二个图像的直方图
        faceCutVO.setMatData(MatChangeUtil.matToStr(hist2));
        faceCutVO.setMatRows(hist2.rows());
        faceCutVO.setMatCols(hist2.cols());
        faceCutVO.setMatType(hist2.type());
        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);
    }

    /**
     * 灰度化人脸并返回Mat对象
     */
    public static Mat conv_Mat(String imgPath) {
        Mat mat1 = Imgcodecs.imread(imgPath); // 读取图像文件并转换为Mat对象
        Mat mat2 = new Mat(); // 创建一个新的Mat对象用于存储灰度图像
        Imgproc.cvtColor(mat1, mat2, Imgcodecs.IMREAD_COLOR); // 将彩色图像转换为灰度图像
        MatOfRect faceDetections = new MatOfRect(); // 创建用于存储检测到的人脸区域的MatOfRect对象
        faceDetector.detectMultiScale(mat1, faceDetections); // 检测人脸区域
        for (Rect rect : faceDetections.toArray()) { // 遍历检测到的人脸区域
            return new Mat(mat1, rect); // 返回包含人脸区域的子Mat对象
        }
        return null; // 如果没有检测到人脸，返回null
    }

    /**
     * 计算直方图
     */
    private static Mat computeHistogram(Mat mat) {
        Mat hist = new Mat(); // 创建用于存储直方图的Mat对象
        MatOfFloat ranges = new MatOfFloat(0f, 256f); // 定义直方图的范围
        MatOfInt histSize = new MatOfInt(100); // 定义直方图的大小（越大越精确，但计算速度越慢）
        Imgproc.calcHist(Collections.singletonList(mat), new MatOfInt(0), new Mat(), hist, histSize, ranges); // 计算直方图
        Core.normalize(hist, hist, 0, 1, Core.NORM_MINMAX); // 归一化直方图，使其值在0到1之间
        return hist; // 返回计算好的直方图
    }


}
