利用Geotools来转换影像的坐标系[转]

本文介绍了一种基于影像变化检测的方法,通过相减与二值化操作,识别出两幅无人机影像之间的差异部分。利用GeoTools库进行矢量化处理,并通过过滤小面积多边形,最终将结果以GeoJSON格式返回。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用Operations类下的resample方法(重采样)可以解决这个问题,它的方法定义如下: 

Coverage 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.resample(old2D, WGS);
System.err.println(String.format("目标坐标系为: %s", new2D.getCoordinateReferenceSystem().getName()));
}
---------------------
作者:WilsonOnIsland
来源:优快云
原文:https://blog.youkuaiyun.com/u013323965/article/details/79453383

 

1.计算指定像素坐标点的坡度
public float calcSlope(int cellX, int cellY, PlanarImage image) throws IOException {
        DecimalFormat df = new DecimalFormat("#.0000");
        final int[] dest = null;
        int e = image.getTile(image.XToTileX(cellX), image.YToTileY(cellY)).getPixel(cellX, cellY, dest)[0];
        int e1 = image.getTile(image.XToTileX(cellX - 1), image.YToTileY(cellY)).getPixel(cellX - 1, cellY, dest)[0];
        int e2 = image.getTile(image.XToTileX(cellX), image.YToTileY(cellY - 1)).getPixel(cellX, cellY - 1, dest)[0];
        int e3 = image.getTile(image.XToTileX(cellX + 1), image.YToTileY(cellY)).getPixel(cellX + 1, cellY, dest)[0];
        int e4 = image.getTile(image.XToTileX(cellX), image.YToTileY(cellY + 1)).getPixel(cellX, cellY + 1, dest)[0];
        int e5 = image.getTile(image.XToTileX(cellX - 1), image.YToTileY(cellY - 1)).getPixel(cellX - 1, cellY - 1,
                dest)[0];
        int e6 = image.getTile(image.XToTileX(cellX + 1), image.YToTileY(cellY - 1)).getPixel(cellX + 1, cellY - 1,
                dest)[0];
        int e7 = image.getTile(image.XToTileX(cellX + 1), image.YToTileY(cellY + 1)).getPixel(cellX + 1, cellY + 1,
                dest)[0];
        int e8 = image.getTile(image.XToTileX(cellX - 1), image.YToTileY(cellY + 1)).getPixel(cellX - 1, 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 testCalcSlope() 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.add(new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE));
        // 默认坐标系EPSG:3857 
//      tiffHints.add(new Hints(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, CRS.decode("EPSG:4326")));
        tiffHints.add(new Hints(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, DefaultGeographicCRS.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, float diffLimit)
            throws IOException {
        File sourceTiff = new File(sourceTiffPath);
        File targetTiff = new File(targetTiffPath);

        if (!sourceTiff.exists() || !targetTiff.exists()) {
            throw new FileNotFoundException(sourceTiffPath + " or " + targetTiffPath + " do not exist!");
        }

        // 中间数据tiff存储路径
        String tempTiff = sourceTiff.getParent() + File.separator + "output.tiff";
        // tiff文件坐标系设置
        Hints tiffHints = new Hints();
        tiffHints.add(new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE));
        tiffHints.add(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);
        RenderedImage sourceImage = sourceCoverage.getRenderableImage(0, 1).createDefaultRendering();
        RenderedImage targetImage = targetCoverage.getRenderableImage(0, 1).createDefaultRendering();
        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();
        GridCoverage2D outputCoverage = factory.create("subtractTiff", difference, sourceEnv);
        GeoTiffWriter writer = new GeoTiffWriter(new File(tempTiff));
        writer.write(outputCoverage, null);
        writer.dispose();
        return outputCoverage;
    }
2.调用geoTools的PolygonExtractionProcess将图像相减操作结果进行矢量化
    public String polygonExtraction(GridCoverage2D tiffCoverage, String shpPath)
            throws MismatchedDimensionException, IndexOutOfBoundsException, NoSuchAuthorityCodeException,
            ParseException, FactoryException, TransformException, SchemaException, IOException {
        PolygonExtractionProcess process = new PolygonExtractionProcess();
        SimpleFeatureCollection features = process.execute(tiffCoverage, 0, Boolean.TRUE, null, null, null, null);

        features = this.polygonPostprocess(features, 10d);

        SimpleFeatureType type = features.getSchema();

//      ShapeFileWriter.INSTANCE.write(shpPath, features, type);
        this.toGeoJSON(features);

        return shpPath;
    }
3.对矢量化后的多边形对象进行过滤,删除面积过小的细碎多边形
private SimpleFeatureCollection polygonPostprocess(SimpleFeatureCollection features, double aeraLimit)
            throws IndexOutOfBoundsException, ParseException, NoSuchAuthorityCodeException, FactoryException,
            MismatchedDimensionException, TransformException, SchemaException {
        //坐标转换,从4326转成3857
        CoordinateReferenceSystem dataCRS = DefaultGeographicCRS.WGS84;
        CoordinateReferenceSystem targerCRS = CRS.decode("EPSG:3857");
        boolean lenient = true; // allow for some error due to different datums
        MathTransform transform = CRS.findMathTransform(dataCRS, targerCRS, lenient);

        final SimpleFeatureType TYPE = DataUtilities.createType("Location",
                "the_geom:Polygon:srid=3857,DN:String,Aera:Double");

        List<SimpleFeature> projectedFeatureList = new ArrayList<SimpleFeature>();

        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
        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
来源:简书
 

转载于:https://www.cnblogs.com/zany-hui/articles/11105923.html

<think>好的,用户想了解如何在Java中读取TIFF影像坐标系。首先,我需要回忆一下处理地理空间TIFF文件的常见方法。通常,TIFF文件可能包含地理参考信息,比如坐标系统、投影参数等,这些信息通常存储在GeoTIFF标签中。 用户提到的是Java,所以需要考虑Java库的支持。常见的库有GDAL,但GDAL本身是用C++写的,不过有Java绑定。另外,GeoTools也是一个处理地理空间数据的Java库,可能支持读取GeoTIFF的坐标系信息。还有Apache SIS,不过可能不如前两者常用。 接下来,我需要确定具体步骤。首先,用户需要添加相关依赖,比如GeoTools或GDAL的Java绑定。然后,通过代码示例展示如何读取TIFF文件并提取坐标系信息。需要注意不同库的使用方法,比如GDAL可能需要初始化,而GeoTools可能有不同的API。 可能的陷阱包括依赖配置的问题,比如GeoTools的版本和仓库设置,或者GDAL的环境变量配置(如gdal_data路径)。此外,TIFF文件可能没有正确的地理信息标签,导致读取失败,需要处理异常情况。 还需要考虑用户可能的环境限制,比如是否允许使用本地安装的库,或者是否需要纯Java解决方案。例如,GDAL的Java绑定可能需要本地库,而GeoTools是纯Java的,可能更便于部署。 另外,坐标系信息的表示方式,比如EPSG代码、WKT字符串等,需要解释如何从读取的数据中提取这些信息,并可能转换为用户友好的格式。 最后,确保代码示例正确,包括正确的异常处理,比如文件找不到、无法读取标签等情况,以增强示例的健壮性。同时,提醒用户检查TIFF文件是否确实包含地理参考信息,因为普通TIFF可能没有这些数据。</think>在Java中读取TIFF影像坐标系信息,主要涉及地理空间数据的解析。以下是分步骤解决方案: 1. **文件格式确认** - 确保TIFF文件包含地理参考信息(GeoTIFF格式) - 验证文件是否包含以下元数据: $$ \text{坐标原点}(X_0,Y_0),\ \text{像素尺寸}(dX,dY),\ \text{投影参数} $$ 2. **依赖库选择** ```xml <!-- GeoTools示例依赖 --> <dependency> <groupId>org.geotools</groupId> <artifactId>gt-geotiff</artifactId> <version>30.0</version> </dependency> ``` 3. **核心代码实现** ```java File file = new File("image.tiff"); GeoTiffReader reader = new GeoTiffReader(file); GridCoverage2D coverage = reader.read(null); // 获取坐标系 CoordinateReferenceSystem crs = coverage.getCoordinateReferenceSystem(); System.out.println("坐标系标识:" + crs.getName()); System.out.println("WKT格式:" + crs.toWKT()); ``` 4. **关键参数解析** - 通过`GridGeometry2D`获取地理转换参数: ```java GridGeometry2D gridGeometry = coverage.getGridGeometry(); AffineTransform transform = (AffineTransform) gridGeometry.getGridToCRS(); // 输出坐标原点 System.out.println("X原点:" + transform.getTranslateX()); System.out.println("Y原点:" + transform.getTranslateY()); ``` 5. **异常处理** - 处理可能出现的异常情况: ```java try { // 读取操作 } catch (IOException e) { System.err.println("文件读取失败:" + e.getMessage()); } catch (FactoryException e) { System.err.println("坐标系解析失败:" + e.getMessage()); } ``` 6. **扩展方案(使用GDAL)** ```java gdal.AllRegister(); Dataset dataset = gdal.Open("image.tiff"); String projection = dataset.GetProjection(); double[] geoTransform = new double[6]; dataset.GetGeoTransform(geoTransform); ``` **注意事项:** 1. 普通TIFF可能不包含坐标系信息,需确认是否为GeoTIFF 2. 不同库的坐标系表示方式差异: - GeoTools返回`CoordinateReferenceSystem`对象 - GDAL返回WKT字符串 3. 需要处理栅格数据与坐标系的对应关系: $$ X = X_0 + p \times dX + l \times dY $$ $$ Y = Y_0 + p \times dY + l \times dX $$ 其中$(p,l)$为像素坐标 建议使用GeoTools作为首选方案,若需要更复杂的地理空间操作,可结合使用JTS拓扑套件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值