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