From d050ad9304670c20dc2c585c9ffc01e3a9abf159 Mon Sep 17 00:00:00 2001 From: inter Date: Thu, 4 Sep 2025 14:08:52 +0800 Subject: [PATCH] Add File --- .../org/dromara/easyai/tools/Watershed.java | 324 ++++++++++++++++++ 1 file changed, 324 insertions(+) create mode 100644 src/main/java/org/dromara/easyai/tools/Watershed.java diff --git a/src/main/java/org/dromara/easyai/tools/Watershed.java b/src/main/java/org/dromara/easyai/tools/Watershed.java new file mode 100644 index 0000000..893f433 --- /dev/null +++ b/src/main/java/org/dromara/easyai/tools/Watershed.java @@ -0,0 +1,324 @@ +package org.dromara.easyai.tools; + +import org.dromara.easyai.config.WaterConfig; +import org.dromara.easyai.matrixTools.Matrix; +import org.dromara.easyai.entity.Box; +import org.dromara.easyai.entity.ThreeChannelMatrix; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author lidapeng + * @description 分水岭 + * @date 10:25 上午 2020/1/13 + */ +public class Watershed { + private final Matrix matrix; + private final Matrix rainfallMap;//降雨图 + private final Matrix regionMap;//分区图 + private final int xSize;//单元高度 + private final int ySize;//单元宽度 + private final float rainTh;//灰度阈值 + private final int regionNub;//一张图分多少份 + private final Map regionBodyMap = new HashMap<>(); + private final int xMax; + private final int yMax; + private final int cutMinXSize;//分水岭切割最小取样X + private final int cutMinYSize;//分水岭切割最小取样Y + private final int cutMaxXSize;//分水岭切割最大取样X + private final int cutMaxYSize;//分水岭切割最大取样Y + private final float th;//落差阈值阈值 + + public Watershed(ThreeChannelMatrix matrix, WaterConfig config) throws Exception { + if (matrix != null) { + th = config.getTh(); + if (th < 0) { + throw new Exception("落差不能小于0"); + } + cutMaxXSize = config.getCutMaxXSize(); + cutMaxYSize = config.getCutMaxYSize(); + cutMinXSize = config.getMinXSizeTh() + 2; + cutMinYSize = config.getMinYSizeTh() + 2; + rainTh = config.getRainTh();//降雨密度图 + regionNub = config.getRegionNub();//区域大小 + this.matrix = matrix.getH(); + xSize = this.matrix.getX() / regionNub; + ySize = this.matrix.getY() / regionNub; + rainfallMap = new Matrix(this.matrix.getX(), this.matrix.getY()); + regionMap = new Matrix(regionNub, regionNub); + xMax = rainfallMap.getX() - 1; + yMax = rainfallMap.getY() - 1; + } else { + throw new Exception("matrix is null"); + } + } + + private float[] getPixels(int x, int y) throws Exception { + //八方向取值 + float left = -1;//左边 + float leftTop = -1;//左上 + float leftBottom = -1;//左下 + float right = -1;//右边 + float rightTop = -1;//右上 + float rightBottom = -1;//右下 + float top = -1;//上边 + float bottom = -1;//下边 + if (x == 0) { + top = 1; + leftTop = 1; + rightTop = 1; + } + if (y == 0) { + leftTop = 1; + left = 1; + leftBottom = 1; + } + if (x == xMax) { + leftBottom = 1; + bottom = 1; + rightBottom = 1; + } + if (y == yMax) { + rightTop = 1; + right = 1; + rightBottom = 1; + } + if (top == -1 && rainfallMap.getNumber(x - 1, y) == 0) { + top = matrix.getNumber(x - 1, y); + } + if (left == -1 && rainfallMap.getNumber(x, y - 1) == 0) { + left = matrix.getNumber(x, y - 1); + } + if (bottom == -1 && rainfallMap.getNumber(x + 1, y) == 0) { + bottom = matrix.getNumber(x + 1, y); + + } + if (right == -1 && rainfallMap.getNumber(x, y + 1) == 0) { + right = matrix.getNumber(x, y + 1); + } + if (leftTop == -1 && rainfallMap.getNumber(x - 1, y - 1) == 0) { + leftTop = matrix.getNumber(x - 1, y - 1); + } + if (leftBottom == -1 && rainfallMap.getNumber(x + 1, y - 1) == 0) { + leftBottom = matrix.getNumber(x + 1, y - 1); + } + if (rightTop == -1 && rainfallMap.getNumber(x - 1, y + 1) == 0) { + rightTop = matrix.getNumber(x - 1, y + 1); + } + if (rightBottom == -1 && rainfallMap.getNumber(x + 1, y + 1) == 0) { + rightBottom = matrix.getNumber(x + 1, y + 1); + } + return new float[]{top, left, bottom, right, leftTop, leftBottom, rightBottom, rightTop}; + } + + private int[] rain(int x, int y) throws Exception {//先往下降,直到不能再降了为止 + //有两种情况停止:1,最小值是自身。2,周围已经灌满水了,包括自身 + float[] pixels = getPixels(x, y); + int[] point = new int[8]; + float mySelf; + mySelf = matrix.getNumber(x, y); + int index = getMinIndex(pixels, mySelf);//最低点下标 + int row; + int column; + if (index > 0) {//存在可向下蔓延的点 + for (int i = 0; i < 8; i++) { + int t = index & (1 << i); + if (t > 0) { + row = x; + column = y; + switch (i) { + case 0://上 + row = x - 1; + break; + case 1://左 + column = y - 1; + break; + case 2://下 + row = x + 1; + break; + case 3://右 + column = y + 1; + break; + case 4://左上 + column = y - 1; + row = x - 1; + break; + case 5://左下 + column = y - 1; + row = x + 1; + break; + case 6://右下 + column = y + 1; + row = x + 1; + break; + case 7://右上 + column = y + 1; + row = x - 1; + break; + } + int pixel = row << 12 | column; + //等待继续往下沉降的点 + point[i] = pixel; + //降雨图修改 + rainfallMap.setNub(row, column, 1); + } + } + } + return point; + } + + private void pull(List list, int[] points) { + for (int point : points) { + if (point != 0) { + list.add(point); + } + } + } + + private void fall(int i, int j) throws Exception { + List list = new ArrayList<>(); + list.add((i << 12) | j); + do { + List list2 = new ArrayList<>(); + for (int pixel : list) { + int x = pixel >> 12; + int y = pixel & 0xfff; + int[] nodes = rain(x, y); + pull(list2, nodes); + } + list = list2; + } while (!list.isEmpty()); + + } + + public List rainfall() throws Exception {//开始降雨 + int x = matrix.getX(); + int y = matrix.getY(); + for (int i = 0; i < x; i++) { + for (int j = 0; j < y; j++) { + if (rainfallMap.getNumber(i, j) == 0) {//进行降雨 + fall(i, j); + } + } + } + //进行区域提取 + sigmaPixel(); + List boxes = new ArrayList<>(); + for (Map.Entry entry : regionBodyMap.entrySet()) { + RegionBody regionBody = entry.getValue(); + int minX = regionBody.getMinX(); + int maxX = regionBody.getMaxX(); + int minY = regionBody.getMinY(); + int maxY = regionBody.getMaxY(); + int xSize = maxX - minX; + int ySize = maxY - minY; + if (xSize >= cutMinXSize && ySize >= cutMinYSize && xSize < cutMaxXSize && ySize < cutMaxYSize) { + Box box = new Box(); + box.setX(minX); + box.setY(minY); + box.setRealX(minX + xSize / 2); + box.setRealY(minY + ySize / 2); + box.setxSize(xSize); + box.setySize(ySize); + boxes.add(box); + } + } + return boxes; + } + + private void merge() throws Exception { + int xSize = regionMap.getX(); + int ySize = regionMap.getY(); + for (int i = 0; i < xSize - 1; i++) {//132 + List list = new ArrayList<>(); + for (int j = 0; j < ySize; j++) { + int type = (int) regionMap.getNumber(i, j); + if (type > 1 && i + 1 < regionNub) { + int otherType = (int) regionMap.getNumber(i + 1, j); + if (otherType > 1 && otherType != type) { + if (!list.contains(otherType)) { + RegionBody myRegion = regionBodyMap.get(type); + RegionBody otherRegion = regionBodyMap.get(otherType); + myRegion.mergeRegion(otherRegion); + regionBodyMap.remove(otherType); + list.add(otherType); + } + } + + } + } + } + } + + private void createMerge() throws Exception { + int x = regionMap.getX(); + int y = regionMap.getY(); + int t = 0; + boolean isZero = false; + for (int i = 0; i < x; i++) { + if (!isZero) { + t++; + } + boolean isFirstOne = false; + for (int j = 0; j < y; j++) { + int type = (int) regionMap.getNumber(i, j); + if (type == 1) { + RegionBody regionBody; + if (regionBodyMap.containsKey(t)) { + regionBody = regionBodyMap.get(t); + } else { + regionBody = new RegionBody(regionMap, t, xSize, ySize); + regionBodyMap.put(t, regionBody); + } + regionBody.setPoint(i, j); + isFirstOne = true; + isZero = false; + } else if (isFirstOne) { + if (!isZero) { + t++; + } + isZero = true; + } + } + } + } + + private void sigmaPixel() throws Exception {//生成降雨密度图 + int size = xSize * ySize; + for (int i = 0; i < xSize * regionNub; i += xSize) { + for (int j = 0; j < ySize * regionNub; j += ySize) { + Matrix myMatrix = rainfallMap.getSonOfMatrix(i, j, xSize, ySize); + int sigma = 0; + for (int t = 0; t < xSize; t++) { + for (int f = 0; f < ySize; f++) { + if (myMatrix.getNumber(t, f) > 0.1) { + sigma++; + } + } + } + float cover = (float) sigma / (float) size;//降雨率产生剧烈波动时则出现坐标 + if (cover > rainTh) {//降雨密度图 + regionMap.setNub(i / xSize, j / ySize, 1); + } + } + } + //System.out.println(regionMap.getString()); + createMerge();//提取候选区 + merge();//合并候选区 + } + + private int getMinIndex(float[] array, float mySelf) {//获取最小值 + int minIdx = 0; + for (int i = 0; i < array.length; i++) { + float nub = array[i]; + float sub = mySelf - nub; + if (nub > -1 && sub > th) { + minIdx = minIdx | (1 << i); + } + } + return minIdx; + } +}