Add File
This commit is contained in:
324
src/main/java/org/dromara/easyai/tools/Watershed.java
Normal file
324
src/main/java/org/dromara/easyai/tools/Watershed.java
Normal file
@@ -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<Integer, RegionBody> 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<Integer> list, int[] points) {
|
||||||
|
for (int point : points) {
|
||||||
|
if (point != 0) {
|
||||||
|
list.add(point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fall(int i, int j) throws Exception {
|
||||||
|
List<Integer> list = new ArrayList<>();
|
||||||
|
list.add((i << 12) | j);
|
||||||
|
do {
|
||||||
|
List<Integer> 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<Box> 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<Box> boxes = new ArrayList<>();
|
||||||
|
for (Map.Entry<Integer, RegionBody> 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<Integer> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user