package org.jeecg.modules.opencv.utils;

import cn.com.ctop.common.module.utils.ResultMapUtils;
import cn.com.ctop.common.module.utils.StatusCode;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import java.util.*;

/**
 * 角点检测
 */

public class CornerCheck {
    static {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    }

    private static int EXPAND_SIZE = 3;
    public static void main(String[] args) {
        detectConers();
    }

    public static Map<String, Object> detectConers() {
        Map<String, Object> result = new HashMap<>();
        try {
            System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

            final int maxCorners = 8;
            int blockSize = 5;
            final double qualityLevel = 0.01;
            double minDistance = 10;
            double k = 0.06;
            final boolean useHarrisDetector = false;
            MatOfPoint corners = new MatOfPoint();

            Mat src = Imgcodecs.imread("D:\\data\\model\\src\\1.jpg");
            if (src.empty()) {
                throw new Exception("no file");
            }
            Mat dst = src.clone();
            Mat gray = new Mat();
            //灰度
            Imgproc.cvtColor(src, gray, Imgproc.COLOR_RGB2GRAY);
            Mat binary = new Mat();
            Rect area = new Rect(324, 402, 218, 370);
            Mat mask = new Mat(gray, area);
            //二值化mask
            Imgproc.threshold(mask, binary, 1, 255, Imgproc.THRESH_TOZERO);
            Imgcodecs.imwrite("D:\\data\\binary.jpg", binary);
            Imgproc.goodFeaturesToTrack(binary, corners, maxCorners, qualityLevel, minDistance, new Mat()
                    , blockSize, useHarrisDetector, k);
            Point[] pCorners = corners.toArray();
            List<Point> pointList = new ArrayList<>();
            for (int i = 0; i < pCorners.length; i++) {
                Point p = new Point(pCorners[i].x + 324, pCorners[i].y + 402);
                Imgproc.circle(dst, p, 2, new Scalar(0, 0, 0), Imgproc.FILLED);
            }
            Imgcodecs.imwrite("D:\\data\\allConers.jpg", dst);
            List<Point> cornerPoints = new ArrayList<>();
//            {139.0, 240.0} 左上 {144.0, 837.0} 左下
//            {482.0, 238.0} 右上 {532.0, 825.0} 右下
            Collections.sort(cornerPoints, new Comparator<Point>() {
                @Override
                public int compare(Point p1, Point p2) {
                    return (int) (p1.x + p1.y - p2.x - p2.y);
                }
            });
            Imgcodecs.imwrite("D:\\data\\coners.jpg", dst);
            for (Point p : cornerPoints) {

            }
//            result.put("leftTop", cornerPoints.get(0));
//            result.put("rightBottom", cornerPoints.get(3));
//            if (cornerPoints.get(2).y > cornerPoints.get(1).y) {
//                result.put("rightTop", cornerPoints.get(1));
//                result.put("leftBottom", cornerPoints.get(2));
//            } else {
//                result.put("rightTop", cornerPoints.get(2));
//                result.put("leftBottom", cornerPoints.get(1));
//            }
            ResultMapUtils.setResultMap(result, StatusCode.COMMON_SUCCESS);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            ResultMapUtils.setResultMap(result, StatusCode.COMMON_SERVER_ERROR);
            return result;
        }
    }

    public static List<Point> matCornerList(List<Point> points) {
        List<Point> matCornerList = new ArrayList<>();
        matCornerList.add(points.get(0));
        matCornerList.add(points.get(1));
        matCornerList.add(points.get(3));
        matCornerList.add(points.get(2));
        return matCornerList;
    }

    public static List<Point> detectConerList(String filePath) {
        List<Point> result = new ArrayList<>();
        try {
            System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
            Mat src = Imgcodecs.imread(filePath);
            if (src.empty()) {
                throw new Exception("no file");
            }
            final int maxCorners = 1000, blockSize = 5;
            final double qualityLevel = 0.05, minDistance = 10.0, k = 0.04;
            final boolean useHarrisDetector = false;
            MatOfPoint corners = new MatOfPoint();

            for (int i = 0; i < src.cols(); i++) {
                for (int j = 0; j < src.rows(); j++) {
                    if (i > 160 && i < 470 && j > 250 && j < 750) {
                        Imgproc.circle(src, new Point(i, j), 1, new Scalar(0, 236, 2), Imgproc.FILLED);
                    }
                }
            }
//            //卷积
//            Mat kernel = new Mat(3, 3, CvType.CV_16SC1);
//            kernel.put(0, 0, 0, -1, 0, -1, 5, -1, 0, -1, 0);
//            Imgproc.filter2D(src, src, src.depth(), kernel);
//            //降噪
//            Imgproc.GaussianBlur(src, src, new Size(3, 3), 0, 0, 1);
            Mat dst = src.clone();
            Mat gray = new Mat();
            //灰度
            Imgproc.cvtColor(src, gray, Imgproc.COLOR_RGB2GRAY);
//            //归一处理
//            Core.normalize(gray,gray);
            //Sobel算子
//            Mat grad_x = new Mat(), grad_y = new Mat();
//            Mat abs_grad_x = new Mat(), abs_grad_y = new Mat();
//            int scale = 1;
//            int delta = 0;
//            //Gradient X
//            Imgproc.Sobel(gray, grad_x, CvType.CV_16S, 1, 0, 3, scale, delta, 1);
//            //Gradient y
//            Imgproc.Sobel(gray, grad_y, CvType.CV_16S, 0, 1, 3, scale, delta, 1);
//
//            Core.convertScaleAbs(grad_x, abs_grad_x);
//            Core.convertScaleAbs(grad_y, abs_grad_y);
//
//            /// Total Gradient (approximate)
//            Mat grad = new Mat();
//            Core.addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);

            Imgproc.goodFeaturesToTrack(gray, corners, maxCorners, qualityLevel, minDistance, new Mat(), blockSize, useHarrisDetector, k);
            Point[] pCorners = corners.toArray();
            List<Point> pointList = new ArrayList<>();
            double maxX = 0d;
            double maxY = 0d;
            double minX = 10000d;
            double minY = 100000d;
            for (int i = 0; i < pCorners.length; i++) {
//                Imgproc.circle(dst, pCorners[i], 4, new Scalar(255, 0, 255), Imgproc.FILLED);
                if (pCorners[i].x > 120 && pCorners[i].x < 555 && pCorners[i].y > 200 && pCorners[i].y < 860) {
                    if (pCorners[i].x >= maxX) {
                        maxX = pCorners[i].x;
                    }
                    if (pCorners[i].y >= maxY) {
                        maxY = pCorners[i].y;
                    }

                    if (pCorners[i].x <= minX) {
                        minX = pCorners[i].x;
                    }

                    if (pCorners[i].y <= minY) {
                        minY = pCorners[i].y;
                    }
                    pointList.add(pCorners[i]);
                }
            }
            Imgproc.line(dst, new Point(minX, minY), new Point(minX, maxY), new Scalar(255, 255, 255));
            Imgproc.line(dst, new Point(minX, maxY), new Point(maxX, maxY), new Scalar(255, 255, 255));
            Imgproc.line(dst, new Point(maxX, maxY), new Point(maxX, minY), new Scalar(255, 255, 255));
            Imgproc.line(dst, new Point(maxX, minY), new Point(minX, minY), new Scalar(255, 255, 255));
            List<Point> cornerPoints = new ArrayList<>();
            for (Point point : pointList) {
                double getX = point.x;
                double getY = point.y;
                if ((getY >= (minY + 50) && getY <= (maxY - 50)) || (getX >= (minX + 25) && getX <= (maxX - 70))) {
                    Imgproc.circle(dst, point, 4, new Scalar(0, 255, 0), Imgproc.FILLED);
                } else {
                    Imgproc.circle(dst, point, 4, new Scalar(255, 0, 255), Imgproc.FILLED);
                    cornerPoints.add(point);
                }
            }
            Point[] cornerArray = new Point[cornerPoints.size()];

            for (int i = 0; i < cornerPoints.size(); i++) {
                cornerArray[i] = cornerPoints.get(i);
            }
            /*MatOfPoint2f srcPoint = new MatOfPoint2f(cornerArray);
            MatOfPoint2f destPoint = new MatOfPoint2f();
            Imgproc.approxPolyDP(srcPoint,destPoint,100,true);
            Point []des = destPoint.toArray();
            for (int i=0;i<des.length-2;i++) {
                Imgproc.line(dst,des[i],des[i+1],new Scalar(255,255,255));
            }*/
            Collections.sort(cornerPoints, new Comparator<Point>() {
                @Override
                public int compare(Point p1, Point p2) {
                    return (int) (p1.x + p1.y - p2.x - p2.y);
                }
            });
            List<Mat> channels = new ArrayList<>();
            Core.split(src, channels);
            List<Mat> mbgr = new ArrayList<>();
            Mat hideChannel = new Mat(src.size(), CvType.CV_8UC1, new Scalar(0));
            Mat imageGR = new Mat(src.size(), CvType.CV_8UC3);
            mbgr = new ArrayList<>();
            mbgr.add(hideChannel);
            mbgr.add(channels.get(1));
            mbgr.add(channels.get(2));
            Core.merge(mbgr, imageGR);
            List<Point> checkPoints = new ArrayList<>();
            Point rightDown = cornerPoints.get(cornerPoints.size() - 1);
            for (Point point : cornerPoints) {
                if (imageGR.get((int) point.y, (int) point.x)[1] >= 120) {
                    if (point.x <= rightDown.x) {
                        checkPoints.add(point);
                    }
                }
            }
            cornerPoints = checkPoints;
            Collections.sort(cornerPoints, new Comparator<Point>() {
                @Override
                public int compare(Point p1, Point p2) {
                    return (int) (p1.x + p1.y - p2.x - p2.y);
                }
            });
            //左上
            result.add(new Point(cornerPoints.get(0).x - EXPAND_SIZE, cornerPoints.get(0).y - EXPAND_SIZE));
            if (cornerPoints.get(2).y > cornerPoints.get(1).y) {
                //右上
                result.add(new Point(cornerPoints.get(1).x + EXPAND_SIZE, cornerPoints.get(1).y - EXPAND_SIZE));
                //左下
                result.add(new Point(cornerPoints.get(2).x - EXPAND_SIZE, cornerPoints.get(2).y + EXPAND_SIZE));
            } else {
                //右上
                result.add(new Point(cornerPoints.get(2).x + EXPAND_SIZE, cornerPoints.get(2).y - EXPAND_SIZE));
                //左下
                result.add(new Point(cornerPoints.get(1).x - EXPAND_SIZE, cornerPoints.get(1).y + EXPAND_SIZE));
            }
            //右下
            result.add(new Point(cornerPoints.get(cornerPoints.size() - 1).x + EXPAND_SIZE, cornerPoints.get(cornerPoints.size() - 1).y + EXPAND_SIZE));

            for (Point point : result) {
                Imgproc.circle(dst, point, 10, new Scalar(255, 0, 255), Imgproc.FILLED);
            }
            Imgcodecs.imwrite("D:\\data\\allConers.jpg", dst);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return result;
        }
    }

    public static void channelSplit() {
        Mat srcImage = Imgcodecs.imread("D:\\data\\163.jpg", Imgcodecs.IMREAD_COLOR);
        List<Mat> channels = new ArrayList<>();
        Core.split(srcImage, channels);

        //创建类型为Mat，数组长度为3的变量mbgr
        List<Mat> mbgr = new ArrayList<>();
        Mat hideChannel = new Mat(srcImage.size(), CvType.CV_8UC1, new Scalar(0));

        Mat imageB = new Mat(srcImage.size(), CvType.CV_8UC3);
        mbgr.add(channels.get(0));
        mbgr.add(hideChannel);
        mbgr.add(hideChannel);
        Core.merge(mbgr, imageB);
        List<Point> points = detectConerList("D:\\data\\imageB.jpg");
        for (Point point : points) {
            Imgproc.circle(imageB, point, 5, new Scalar(0, 0, 0));
        }
        Imgcodecs.imwrite("D:\\data\\imageB.jpg", imageB);

        mbgr = new ArrayList<>();
        Mat imageG = new Mat(srcImage.size(), CvType.CV_8UC3);
        mbgr.add(hideChannel);
        mbgr.add(channels.get(1));
        mbgr.add(hideChannel);
        Core.merge(mbgr, imageG);
        points = detectConerList("D:\\data\\imageG.jpg");
        for (Point point : points) {
            Imgproc.circle(imageG, point, 5, new Scalar(0, 0, 0));
        }
        Imgcodecs.imwrite("D:\\data\\imageG.jpg", imageG);

        mbgr = new ArrayList<>();
        Mat imageR = new Mat(srcImage.size(), CvType.CV_8UC3);
        mbgr.add(hideChannel);
        mbgr.add(hideChannel);
        mbgr.add(channels.get(2));
        Core.merge(mbgr, imageR);
        points = detectConerList("D:\\data\\imageR.jpg");
        for (Point point : points) {
            Imgproc.circle(imageR, point, 5, new Scalar(0, 0, 0));
        }
        Imgcodecs.imwrite("D:\\data\\imageR.jpg", imageR);

        mbgr = new ArrayList<>();
        Mat imageBG = new Mat(srcImage.size(), CvType.CV_8UC3);
        mbgr.add(channels.get(0));
        mbgr.add(channels.get(1));
        mbgr.add(hideChannel);
        Core.merge(mbgr, imageBG);
        points = detectConerList("D:\\data\\imageBG.jpg");
        for (Point point : points) {
            Imgproc.circle(imageBG, point, 5, new Scalar(0, 0, 0));
        }
        Imgcodecs.imwrite("D:\\data\\imageBG.jpg", imageBG);

        Mat imageGR = new Mat(srcImage.size(), CvType.CV_8UC3);
        mbgr = new ArrayList<>();
        mbgr.add(hideChannel);
        mbgr.add(channels.get(1));
        mbgr.add(channels.get(2));
        Core.merge(mbgr, imageGR);
        points = detectConerList("D:\\data\\imageGR.jpg");
        for (Point point : points) {
            Imgproc.circle(imageGR, point, 5, new Scalar(0, 0, 0));
        }
        Imgcodecs.imwrite("D:\\data\\imageGR.jpg", imageGR);

        mbgr = new ArrayList<>();
        Mat imageBR = new Mat(srcImage.size(), CvType.CV_8UC3);
        mbgr.add(channels.get(0));
        mbgr.add(hideChannel);
        mbgr.add(channels.get(2));
        Core.merge(mbgr, imageBR);
        points = detectConerList("D:\\data\\imageBR.jpg");
        for (Point point : points) {
            Imgproc.circle(imageBR, point, 5, new Scalar(0, 0, 0));
        }
        Imgcodecs.imwrite("D:\\data\\imageBR.jpg", imageBR);
    }
}
