geotif 添加坐标_利用Geotools来转换影像的坐标系[转]
采用Operations类中的重采样技术(Resampling technique)来应对这一挑战非常有效;其具体实现方式如下。
CoverageSet org.geotools.coverage.processing.Operations.resample(Coverage source, CoordinateReferenceSystem crs) throws CoverageProcessingException
File file = new File("xxxx.tif");
if(file.exists()){
Reader br = new Reader();
GridCoverage2D old2D = br.getGridCoverage2D(file);
final CoordinateReferenceSystem WGS = CRS.decode("EPSG:3857");
final CoordinateReferenceSystem sourceCRS = old2D.getCoordinateReferenceSystem();
System.out.println(String.format("源坐标系为: %s", sourceCRS.getName()));
GridCoverage2D new2D: (GridCoverage2D) Operations.DEFAULT instance. resample(old2D, WGS);
new2D.getCoordinateReferenceSystem().getName()/
new2D.getCoordinateReferenceSystem().getName()/
new2D.getCoordinateReferenceSystem().getName()/
new2D.getCoordinateReferenceSystem().getName()/
新坐标系名称
}
---------------------
作者:WilsonOnIsland
来源:
原文:
1.计算指定像素坐标点的坡度
public float calculateSlope(int cellX, int cellY; PlanarImage image = null) throws IOException {
DecimalFormat df = new DecimalFormat("#.0000");
final int[] dest = null;
整型变量e等于从图像中获取转瓷砖坐标的像素值结果中提取指定像素位置[索引为0]
integer e1 = image.retrieve a tile at (image.XToTileX(cellX - 1), image.YToTileY(cellY)) and fetch the pixel at (cellX - 1, cellY, dest) using [0] as the index.
int e2 = image.retrieve a tile using image.XToTileX(cellX) and image.YToTileY(cellY - 1). Then, this tile's pixel at position (cellX, cellY - 1) with destination is assigned to e2. Finally, the [0] index of this pixel is used.
int e3 = getImage().retrieveImageInTiles(convert X to Tile X position of cellX incremented by one, convert Y to Tile Y position of cellY).fetchPixel at coordinates (incremented cell X position, cellY, destination))[0];
int e4Value = imgTiles(imgTilesIndexX, verticalIndexPlusOne)
.getPixel(firstCoordinate, yCoordinatePlusOne, targetDestination)
.get(0);
int e5 = getImageAt(imageComputeTiles(cellXMinusOne, cellYMinusOne)).fetch(cellXMinusOne, cellYMinusOne);
dest)[0];
int e6 = getImageAt(getImageToTileX(tileIndex_X), getImageToTileY(tileIndex_Y)).getImageAt(tileIndex_X, tileIndex_Y,
dest)[0];
该算法通过调用图像获取函数获取指定区域的像素值来实现目标效果。
dest)[0];
int e8 = image.getPixel(
image.XToTileX(cellX - 1),
image.YToTileY(cellY + 1)
);
dest)[0];
double slopeWE = ((e8 + 2 * e1 + e5) - (e7 + 2 * e3 + e6)) / (8 * 2041.823085);// 东西方向坡度
double slopeNW = ((e7 + 2 * e4 + e8) - (e6 + 2 * e2 + e5)) / (8 * 2041.823085);// 南北方向坡度
double slope = 100*(Math.sqrt(Math.pow(slopeWE, 2) + Math.pow(slopeNW, 2)));
return Float.parseFloat(df.format(slope));
}
2.DEM数据测试用例
@Test
public void validateSlopeCalculation() throws NoSuchAuthorityCodeException, FactoryException, IOException {
String path = "D:\ workData\ geotiff\ testTiff.tif";
String outputPath = "D:\ workData\ geotiff\ output.tif";
File file = new File(path);
// 设置tiff影像默认设置
Hints tiffHints = new Hints();
tiffHints.append(createNew Hints(Enums-enforce-longitudinal-first-axis-order, Boolean.TRUE));
// 默认坐标系EPSG:3857
tiffHints.add(new Hints(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, CRS.decode("EPSG:4326")));
tiffHints包含一个新的配置项:新的CoordinateReferenceSystemClass,默认设置为WGS84类
GeoTiffReader reader = new GeoTiffReader(file, tiffHints);
GridCoverage2D coverage = reader.read(null);
Envelope env = coverage.getEnvelope();
PlanarImage image = (PlanarImage) coverage.getRenderedImage();
int width = image.getWidth(); // Image Width
int height = image.getHeight(); // Image Height
// 计算每个栅格的坡度
float[][] slopeData = new float[height][width];
for (int i = 1; i < height + 1; i++) {
for (int j = 1; j < width + 1; j++) {
float slope = SlopeUtil.INSTANCE.calcSlope(j, i, image);
slopeData[i - 1][j - 1] = slope;
}
}
GridCoverageFactory factory = new GridCoverageFactory();
GridCoverage2D outputCoverage = factory.create("test", slopeData, env);
GeoTiffWriter writer = new GeoTiffWriter(new File(outputPath));
writer.write(outputCoverage, null);
writer.dispose();
}
功能需求:接收同一时间段内来自同一区域的无人机影像数据集合;通过分析确定区域内影像变化的空间特征;将识别到的变化区域矢量化为GeoJSON格式,并将其发送至前端端点。
1.将两幅图像进行相减与二值化操作
public GridCoverage2D对象 tiffSubtract(String sourceTiffPath, String targetTiffPath, 浮点数diffLimit)
throws IOException {
File sourceTiff = new File(sourceTiffPath);
File targetTiff = new File(targetTiffPath);
if (!sourceTiff.exists() || !targetTiff.exists()) {
throws new FileNotFoundException(sourceTiffPath + " or " + targetTiffPath + " does not exist");
}
// 中间数据tiff存储路径
String tempTiff = sourceTiff.getParent() + File.separator + "output.tiff";
// tiff文件坐标系设置
Hints tiffHints = new Hints();
tiffHints.insert(new Hints(ForceLongitudeFirstAxisOrder, true));
tiffHints.define(new Hints(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, DefaultGeographicCRS.WGS84));
GeoTiffReader sourceReader = new GeoTiffReader(sourceTiff, tiffHints);
GeoTiffReader targetReader = new GeoTiffReader(targetTiff, tiffHints);
GridCoverage2D sourceCoverage = sourceReader.read(null);
GridCoverage2D targetCoverage = targetReader.read(null);
源图像sourceImage = sourceCoverage获取渲染图像0,1创建默认渲染();
目标渲染图像 targetImage 被赋值为 targetCoverage 获取第0个可渲染图像并生成默认渲染结果。
Raster sourceRaster = sourceImage.getData();
Raster targetRaster = targetImage.getData();
int width = sourceRaster.getWidth();
int height = sourceRaster.getHeight();
// System.out.println("pixels : width:" + width + ";height:" + height);
Envelope2D sourceEnv = sourceCoverage.getEnvelope2D();
float[][] difference = new float[height][width];
float s;
float t;
// 修改算法,提取差异值大于阈值的部分
// 将图像二值化
for (int x = 0; x < width - 1; x++) {
for (int y = 0; y < height - 1; y++) {
// System.out.println("x:" + x + ";y:" + y);
s = sourceRaster.getSampleFloat(x, y, 1);
t = targetRaster.getSampleFloat(x, y, 1);
float diff = t - s;
if (diff > diffLimit) {
difference[y][x] = 100f;
} else {
difference[y][x] = 0f;
}
}
}
GridCoverageFactory factory = new GridCoverageFactory();
通过调用 factory 创建一个 Grid Coverage 二维对象
GeoTiffWriter writer = new GeoTiffWriter(new File(tempTiff));
writer.write(outputCoverage, null);
writer.dispose();
return outputCoverage;
}
利用geoTools中的PolygonExtractionProcess对图像相减的结果进行向量化处理
public String polygonExtract(2D GridCoverage tiffCoverage, shapefilePath shpPath)
throws Dimension mismatch exception, Invalid index exception, Unauthorized code exception,
ParseException, FactoryException, TransformException, SchemaException, IOException {
PolygonExtractionProcess process = new PolygonExtractionProcess();
featureSet = workflow.run(tiffCoverage, 0, Boolean.TRUE)
features = this.polygonPostprocess(features, 10d);
SimpleFeatureType type = features.getSchema();
// ShapeFileWriter.INSTANCE.write(shpPath, features, type);
this.toGeoJSON(features);
return shpPath;
}
3.对矢量化后的多边形对象进行过滤,删除面积过小的细碎多边形
该函数属于一个私有的SimpleFeatureCollection类,并名为polygonProcessing(featureSet),其接收两个参数:一个为SimpleFeatureCollection类型的featureSet和一个为double类型的areaLimit值。
IndexRelatedError, Problem, AuthorityCodeNotFoundError, FactoryError
当遇到以下几种情况时会触发该错误:维度配对失败异常、转换失败异常以及方案构建失败异常。
//坐标转换,从4326转成3857
CoordinateReferenceSystem dataCRS = DefaultGeographicCRS.WGS84;
CoordinateReferenceSystem targerCRS = CRS.decode("EPSG:3857");
boolean lenient = true; // allow for some error due to different datums
A mathematical transform is determined as transform = CRS.determine(Mathematical Transform, CoordinateReferenceSystem1, CoordinateReferenceSystem2, optional).
final SimpleFeatureType TYPE = DataUtilities.createType("Location",
"the_geom:Polygon:srid=3857,DN:String,Aera:Double");
List projectedFeatureList = new ArrayList();
geometry object geometryObject = JTSFactoryFinder.retrieveGeometryObject();
WKTReader reader = new WKTReader(geometryFactory);
SimpleFeatureBuilder builder = new SimpleFeatureBuilder(TYPE);
SimpleFeatureIterator iterator = features.features();
try {
while (iterator.hasNext()) {
SimpleFeature feature = iterator.next();
Polygon polygon = (Polygon) feature.getDefaultGeometry();
polygon = (Polygon) JTS.transform(polygon, transform);
double aera = polygon.getArea();
// 多边形面积大于阈值
if (aera >= aeraLimit) {
builder.add(polygon);
builder.add(feature.getAttribute(1).toString());
builder.add(aera);
SimpleFeature tempFeature = builder.buildFeature(null);
projectedFeatureList.add(tempFeature);
}
}
} finally {
iterator.close();
}
System.out.println(projectedFeatureList.size());
return new ListFeatureCollection(TYPE, projectedFeatureList);
}
4.将最终结果以GeoJSON格式返回
private void toGeoJSON(SimpleFeatureCollection featureCollection) {
SimpleFeatureIterator it = featureCollection.features();
GeoJsonWriter geoJsonWriter = new GeoJsonWriter();
while(it.hasNext()) {
SimpleFeature tempFeature = it.next();
Geometry geometry = (Geometry) tempFeature.getDefaultGeometry();
String json = geoJsonWriter.write(geometry);
System.out.println(json);
}
}
作者:z362831561
链接:https://www.jianshu.com/p/6b7addbe8739
来源:简书
