package com.xhkjedu.smarking.utils.opencv;

import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Point;
import org.opencv.imgproc.Imgproc;

import java.util.Vector;

/**
 * 轮廓工具类
 */
public class CvContoursUtils {

    /**
     * 获取图片的四个顶点
     *
     * @param img 原图
     * @return Point[]
     */
    public static Point[] getAllPoints(Mat img) {
        Point[] potArr = new Point[4];
        for (int i = 0; i < 4; i++) {
            potArr[i] = new Point(-1, -1);
        }

        int[] spaceArr = new int[]{-1, -1, -1, -1};
        int cols = img.cols();
        int rows = img.rows();
        int x1 = cols / 3;
        int x2 = cols * 2 / 3;
        int y1 = rows / 3;
        int y2 = rows * 2 / 3;
        for (int x = 0; x < cols; x++) {
            for (int y = 0; y < rows; y++) {
                if (x > x1 && x < x2 && y > y1 && y < y2) {
                    continue;
                }
                double[] darr = img.get(y, x);
                if (darr != null && darr.length >= 1 && darr[0] == 0) {
                    if (spaceArr[0] == -1) {
                        potArr[0].x = x;
                        potArr[0].y = y;
                        potArr[1].x = x;
                        potArr[1].y = y;
                        potArr[2].x = x;
                        potArr[2].y = y;
                        potArr[3].x = x;
                        potArr[3].y = y;
                        spaceArr[0] = getSpace(0, 0, x, y);
                        spaceArr[1] = getSpace(cols, 0, x, y);
                        spaceArr[2] = getSpace(cols, rows, x, y);
                        spaceArr[3] = getSpace(0, rows, x, y);
                    } else {
                        int s0 = getSpace(0, 0, x, y);
                        int s1 = getSpace(cols, 0, x, y);
                        int s2 = getSpace(cols, rows, x, y);
                        int s3 = getSpace(0, rows, x, y);
                        if (s0 < spaceArr[0]) {
                            spaceArr[0] = s0;
                            potArr[0].x = x;
                            potArr[0].y = y;
                        }
                        if (s1 < spaceArr[1]) {
                            spaceArr[1] = s1;
                            potArr[1].x = x;
                            potArr[1].y = y;
                        }
                        if (s2 < spaceArr[2]) {
                            spaceArr[2] = s2;
                            potArr[2].x = x;
                            potArr[2].y = y;
                        }
                        if (s3 < spaceArr[3]) {
                            spaceArr[3] = s3;
                            potArr[3].x = x;
                            potArr[3].y = y;
                        }
                    }

                }
            }
        }
        return potArr;
    }

    /**
     * 轮廓识别，使用最外轮廓发抽取轮廓RETR_EXTERNAL，轮廓识别方法为CHAIN_APPROX_SIMPLE
     *
     * @param source 传入进来的图片Mat对象
     * @return 返回轮廓结果集
     */
    public static Vector<MatOfPoint> findContours(Mat source) {
        Mat rs = new Mat();

        /*
          定义轮廓识别方法
          边缘近似方法(除了RETR_RUNS使用内置的近似，其他模式均使用此设定的近似算法)。可取值如下:
         CV_CHAIN_CODE:以Freeman链码的方式输出轮廓，所有其他方法输出多边形(顶点的序列)。
         CHAIN_APPROX_NONE:将所有的连码点，转换成点。
         CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分，也就是，函数只保留他们的终点部分。
         CHAIN_APPROX_TC89_L1，CV_CHAIN_APPROX_TC89_KCOS:使用the flavors of Teh-Chin chain近似算法的一种。
         LINK_RUNS:通过连接水平段的1，使用完全不同的边缘提取算法。使用CV_RETR_LIST检索模式能使用此方法。
         */
        Vector<MatOfPoint> contours = new Vector<>();
        Imgproc.findContours(
                source,
                contours,
                rs,
                Imgproc.RETR_LIST,
                Imgproc.CHAIN_APPROX_SIMPLE
        );
        return contours;
    }


    private static int getSpace(int x1, int y1, int x2, int y2) {
        int xspace = Math.abs(x1 - x2);
        int yspace = Math.abs(y1 - y2);
        return (int) Math.sqrt(Math.pow(xspace, 2) + Math.pow(yspace, 2));
    }

}
