基于GeoTools求解GeoTIFF的最大最小值方法

发布于:2025-06-11 ⋅ 阅读:(21) ⋅ 点赞:(0)

目录

前言

一、在QGIS中查看极值的三种方式

1、属性信息查看

2、在符号化中查看

3、直方图统计

二、GeoTools读取极值

1、直接循环遍历法

2、基于CoverageClassStats读取

三、总结


前言

        在地理信息系统(GIS)领域,GeoTIFF 作为一种常见的地理空间数据格式,承载着丰富的地理信息数据,比如常见的人口数据、地形数据、夜间灯光数据等等,覆盖了从遥感影像到地形地貌数据,GeoTIFF 文件广泛应用于地图绘制、资源勘探、环境监测等众多领域。对这些 GeoTIFF 数据进行有效的分析和处理,是挖掘其潜在价值的关键环节。而在众多的数据分析需求中,确定 GeoTIFF 数据集的最大值和最小值是一项基础且重要的任务。

        当我们面对一个 GeoTIFF 文件时,其中存储的地理要素的属性值范围对我们理解数据的分布特征、进行数据可视化以及开展后续的复杂分析都有着至关重要的意义。例如,在遥感影像分析中,不同地物类型的反射率或发射率值存在差异,通过获取影像数据的最大最小值,可以初步判断地物类型的分布情况和影像的质量状况;在地形分析中,高程数据的最大最小值能够直接反映出研究区域的海拔高差范围,为坡度、坡向等分析提供基础依据。

        本文旨在深入探讨基于 GeoTools 求解 GeoTIFF 最大最小值的方法。首先介绍 GeoTIFF 格式的相关特性和 GeoTools 中处理 GeoTIFF 数据的关键类与方法。主要介绍利用QGIS软件来读取Tif文件的最大最小值,然后详细阐述如何利用 GeoTools 的读取、解析和计算功能来获取 GeoTIFF 数据中的最大值和最小值,并对整个过程进行分析和优化,以确保得到准确可靠的结果,为后续的地理信息分析和决策提供坚实的数据基础。

一、在QGIS中查看极值的三种方式

        本节将重点介绍在QGIS中直接查看GeoTiff文件的最大最小值的三种方法,分别是在属性信息中tab页中查看,在符号化tab页中查看以及使用直方图的形式进行查看。当然,除了使用QGIS软件,还可以利用ArcMap或者ArcGIS的相关软件也是可以直接查看的。

1、属性信息查看

        利用QGIS加载相应的tif数据之后,可以单击鼠标右键,在打开的信息窗口中可以直接查看,以属性信息栏窗口为例,如下图所示:

        在这里,其实已经将一些极值的信息列了出来,供大家查阅。

STATISTICS_MAXIMUM=2095
STATISTICS_MEAN=355.64031618431
STATISTICS_MINIMUM=-35
STATISTICS_STDDEV=297.91063586873
STATISTICS_VALID_PERCENT=64.56

        可以看到,使用属性信息窗口可以在波段信息中看到极值信息。         

2、在符号化中查看

        除了在基本信息中可以直接的查看极值信息之外,在标绘时也是可以比较直观的进行查看的。在QGIS中切换到符号化的tab页,同样的波段信息下面可以看到当前tif的最大最小值,如下图所示:

        通过符号化窗口看到的最大值是2095,最小值是-35;这个值与上一小节的属性信息中看到的极值是一致的的。 

3、直方图统计

        前面介绍了两种查看tif文件极值的方法,接着介绍最后一种基于直方图的统计方法。在属性页面,与矢量数据的展示不一样的是还有一个直方图的统计页面,点击直方图tab页,会打开如下界面:

        同样的,在这里,我们依然可以看得到栅格的直方图统计信息,可以很直观的在底部可以看到当前的tif文件对应的最大值和最小值,可以看到这个最大值最小值与前面得到的值都是一致的。 

二、GeoTools读取极值

          GeoTools 作为一款功能强大的开源 GIS 工具库,为开发者提供了丰富的地理数据处理和分析功能。它具备良好的扩展性和灵活性,能够方便地与各种 GIS 数据格式进行交互,并且提供了高效的算法来处理地理空间数据。因此,借助 GeoTools 来求解 GeoTIFF 的最大最小值,不仅可以提高数据处理的效率和准确性,还能充分利用其现有的功能模块,减少重复开发的工作量,使开发者能够将更多的精力集中在数据分析和应用的深层次领域。本节分享两种使用Geotools来统计tif极值的方法,分别是采用直接循环遍历法和基于CoverageClassStats的统计方法。

1、直接循环遍历法

        第一种方法比较简单,就是采用循环读取的方式,使用Geotools中的读取栅格坐标点的信息来进行循环读取,大致的代码如下:

File file = new File("F:/vector_data/worldPop人口数据/worldpop/chn_ppp_2020_1km_Aggregated.tif");
GeoTiffReader reader = new GeoTiffReader(file, new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE));
GridCoverage2D coverage = reader.read(null);
// 设置目标坐标系并重采样
CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:4326");
coverage = (GridCoverage2D) Operations.DEFAULT.resample(coverage, targetCRS);
RenderedImage image = coverage.getRenderedImage();
GridGeometry2D geometry = coverage.getGridGeometry();
// 获取栅格数据并批量读取像素值
Raster raster = image.getData();
width = raster.getWidth();
int height = raster.getHeight();
double[] pixels = raster.getSamples(raster.getMinX(), raster.getMinY(), width, height, 0, (double[]) null);
// 收集非零像素的坐标
List<GridCoordinates2D> nonZeroCoords = new ArrayList<>();
for (int j = 0; j < height; j++) {
	for (int i = 0; i < width; i++) {
	    if (pixels[j * width + i] > 0) {
	         nonZeroCoords.add(new GridCoordinates2D(i, j));
	    }
	 }
}
// 获取仿射变换以手动计算坐标
MathTransform2D gridToCRS =  geometry.getGridToCRS2D();
if (!(gridToCRS instanceof AffineTransform2D)) {
	  throw new RuntimeException("仅支持仿射变换");
}
AffineTransform2D affine = (AffineTransform2D) gridToCRS;    
BigDecimal total = new BigDecimal("0.0");
double t = 0;
// 处理非零像素
for (GridCoordinates2D coord : nonZeroCoords) {
	  int i = coord.x;
	  int j = coord.y;
	  double[] src = new double[]{i + 0.5, j + 0.5}; // 像素中心坐标
	  double[] dest = new double[2];
	  affine.transform(src, 0, dest, 0, 1);
	  double longitude = dest[0];
	  double latitude = dest[1];
	  /*System.out.printf("像素点 (%d, %d) 的值:%f 坐标为: %f, %f%n",
	        i, j, pixels[j * width + i], longitude, latitude);*/
	  total = total.add(new BigDecimal(pixels[j * width + i]));
	  t +=  pixels[j * width + i];
}

         我们可以从栅格像素点中去读取对应的值,比如人口和海拔高程等。然后将得到的数据保存到集合中,最后使用集合排序,然后取出两个极值即为我们需要求解的目标。这种方法在范围较小的情况下,可以如此使用,大面积不建议这么使用,可能你的内存都会受不了。

2、基于CoverageClassStats读取

        与直接循环遍历方法不一样的是,在前面的QGIS软件展示极值信息时。我们曾简单的提起波段的属性信息。因此我们是否可以采取类似的方法来加速呢?这里分享一种方法,代码如下:

package com.yelang.project.geotoolstiff;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.coverage.grid.io.GridFormatFinder;
import org.geotools.gce.geotiff.GeoTiffFormat;
import org.geotools.gce.geotiff.GeoTiffReader;
import org.geotools.process.ProcessException;
import org.geotools.process.classify.ClassificationMethod;
import org.geotools.process.raster.CoverageClassStats;
import org.geotools.util.factory.Hints;
import org.jaitools.numeric.Statistic;
public class DemMinMaxStat {
	public static void main(String[] args) throws ProcessException, IOException {
		/**
		 * 湖南地形 min :-35 max:2095
		 */
		File file = new File("C:/BaiduDownload/湖南省_DEM_30m分辨率_NASA数据.tif");
		/**
		 * 全国人口 min :-99999.0 max:286414.71875
		 */
		//File file = new File("F:/vector_data/worldPop人口数据/worldpop/chn_ppp_2020_1km_Aggregated.tif");
		AbstractGridFormat format = GridFormatFinder.findFormat(file);
		if (!(format instanceof GeoTiffFormat)) {
		    throw new RuntimeException(String.format("传入文件不是geoTif格式文件"));
		}
		Hints hints = new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE);
		AbstractGridCoverage2DReader reader = format.getReader(file, hints);
		GridCoverage2D coverage = reader.read(null);
		CoverageClassStats rasterProcess = new CoverageClassStats();
		Set<Statistic> set = new HashSet<Statistic>(2);
		//最大值
		set.add(Statistic.MAX);
		//最小值
		set.add(Statistic.MIN);
		CoverageClassStats.Results results = rasterProcess.execute(coverage, set, 0, 1,
		        ClassificationMethod.QUANTILE, null, null);
		System.out.println("geometry = " + results);
		double  maxVal = results.value(0, Statistic.MAX);
		double  minVal = results.value(0, Statistic.MIN);
		System.out.println("Minimum value: " + minVal);
		System.out.println("Maximum value: " + maxVal);
	}
}

         在IDE中运行以上方法后可以在控制台中直接看到我们的极值效果,如下所示:

        通过程序运行可以看到,使用Geotools程序同样可以基于CoverageClassStats进行数据的极值采集,采集的值与使用Qgis软件提供的值完全一致,说明结果是正确的。 

三、总结

        以上就是本文的主要内容, 本文旨在深入探讨基于 GeoTools 求解 GeoTIFF 最大最小值的方法。首先介绍 GeoTIFF 格式的相关特性和 GeoTools 中处理 GeoTIFF 数据的关键类与方法。主要介绍利用QGIS软件来读取Tif文件的最大最小值,然后详细阐述如何利用 GeoTools 的读取、解析和计算功能来获取 GeoTIFF 数据中的最大值和最小值,并对整个过程进行分析和优化,以确保得到准确可靠的结果,为后续的地理信息分析和决策提供坚实的数据基础。行文仓促,定有不足之处,欢迎各位朋友在评论区批评指正,不胜感激。