GeoTools 读取影像元数据
前言
❝元数据是用来描述数据的数据,其作为数据的"说明书",是实现空间数据有效管理与深度应用的基础支撑。它通过记录数据来源、投影信息、属性定义、采集精度等核心要素,确保GIS数据的可理解性与可追溯性,为数据使用者提供准确的背景信息,在GIS开发中具有重要意义。
本篇教程在之前一系列文章的基础上讲解
GeoTools 开发环境搭建[1] 将 Shp 导入 PostGIS 空间数据的五种方式(全)[2] GeoTools 结合 OpenLayers 实现空间查询[3]
如果你还没有看过,建议从那里开始。
1. 开发环境
本文使用如下开发环境,以供参考。
时间:2025年
GeoTools:v34-SNAPSHOT
IDE:IDEA2025.1.2
JDK:v17
2. GeoTIFF 元素据内容
2.1. 图像基本信息
元数据项 | 描述 |
图像宽度 | 水平方向像素数量 |
图像高度 | 垂直方向像素数量 |
数据类型 | 像素值的数据类型(如Byte、Int16、Float32等) |
波段数量 | 图像的光谱波段数 |
2.2. 坐标参考系统(CRS)信息
(1)地理坐标系参数
地理类型代码:指定地理坐标系类型(如WGS84、北京54等) 大地基准面代码:参考椭球体参数代码 本初子午线:起始经线定义(通常为格林威治) 线性单位:坐标单位(米、度等) 角度单位:角度测量单位(弧度、度等) 椭圆体参数:自定义椭圆体的长半轴、短半轴和扁率
(2)投影坐标系参数
投影编码:投影类型代码(如UTM、兰伯特等) 标准纬线:投影的标准纬线纬度 中央经线:投影中心经线 原点坐标:投影原点的东向和北向坐标 比例因子:投影的缩放比例 假东距/假北距:东向和北向偏移值
2.3. 地理空间信息
地理范围
最小X坐标:图像西边界坐标 最大X坐标:图像东边界坐标 最小Y坐标:图像南边界坐标 最大Y坐标:图像北边界坐标 角点坐标:四个角点的精确地理坐标
3. GeoTIFF 元数据读取
在开发工具中新建一个类ReadGeoTIFFMeta用来读取影像元素据信息。
代码主要包括三个部分,分别是【读取图像信息】、【读取坐标系统信息】以及【读取地理范围信息】
package org.geotools.data.image;
import org.geotools.api.referencing.crs.CoordinateReferenceSystem;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.gce.geotiff.GeoTiffReader;
import org.locationtech.jts.geom.Envelope;
import java.awt.image.RenderedImage;
import java.io.File;
/**
* @name: ReadGeoTIFFMeta
* @description: 用于读取GeoTIFF元数据信息
* @author: gis_road
* @date: 2025-08-19
*/
public class ReadGeoTIFFMeta {
public static void main(String[] args) throws Exception {
// GeoTIFF 文件地址
String tiffPath = "D:\App\GeoTIFF\LC08_B1.tif";
File tiffFile = new File(tiffPath);
// 读取 GeoTIFF 文件
try{
GeoTiffReader tiffReader = new GeoTiffReader(tiffFile);
// 读取GridCoverage2D对象
GridCoverage2D gridCoverage2D = tiffReader.read(null);
// 读取元数据信息
System.out.println("======================== 开始读取 GeoTIFF 元数据信息 ========================"+"n");
// 1. 读取图像信息
RenderedImage image = gridCoverage2D.getRenderedImage();
System.out.println("【图像宽度 x 图像高度】:"+image.getWidth()+" x "+image.getHeight()+" 像素");
System.out.println("【图像波段数量】:"+image.getSampleModel().getNumBands());
// 2. 读取坐标系统信息
CoordinateReferenceSystem crs = gridCoverage2D.getCoordinateReferenceSystem();
System.out.println("n【坐标系统名称】:"+crs.getName());
System.out.println("【坐标系EPSG编码】:"+crs.getIdentifiers());
// 3. 读取地理范围信息
Envelope envelope = gridCoverage2D.getEnvelope2D();
System.out.println("n【最小X边界】:"+envelope.getMinX());
System.out.println("【最小Y边界】:"+envelope.getMinY());
System.out.println("【最大X边界】:"+envelope.getMaxX());
System.out.println("【最大Y边界】:"+envelope.getMaxY());
System.out.println("n======================== 读取 GeoTIFF 元数据信息结束 ========================");
}catch (Exception e){
throw new Exception("文件读取异常:"+e.getMessage());
}
}
}
读取信息显示如下。
完整的GeoTIFF属性信息显示如下。
<?xml version="1.0" encoding="UTF-8"?>
<metadata xml:lang="zh">
<Esri>
<CreaDate>20240908</CreaDate>
<CreaTime>16235000</CreaTime>
<ArcGISFormat>1.0</ArcGISFormat>
<SyncOnce>FALSE</SyncOnce>
<DataProperties>
<itemProps>
<itemName Sync="TRUE">LC08_B1.tif</itemName>
<itemLocation>
<linkage Sync="TRUE">LC08_B1.tif</linkage>
<protocol Sync="TRUE">Local Area Network</protocol>
</itemLocation>
<imsContentType Sync="TRUE">002</imsContentType>
<nativeExtBox>
<westBL Sync="TRUE">244815.000000</westBL>
<eastBL Sync="TRUE">363405.000000</eastBL>
<southBL Sync="TRUE">2622315.000000</southBL>
<northBL Sync="TRUE">2773365.000000</northBL>
<exTypeCode Sync="TRUE">1</exTypeCode>
</nativeExtBox>
</itemProps>
<coordRef>
<type Sync="TRUE">Projected</type>
<geogcsn Sync="TRUE">GCS_WGS_1984</geogcsn>
<csUnits Sync="TRUE">Linear Unit: Meter (1.000000)</csUnits>
<projcsn Sync="TRUE">WGS_1984_UTM_zone_48N</projcsn>
<peXml Sync="TRUE"><ProjectedCoordinateSystem xsi:type='typens:ProjectedCoordinateSystem' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xs='http://www.w3.org/2001/XMLSchema' xmlns:typens='http://www.esri.com/schemas/ArcGIS/10.1'><WKT>PROJCS[&quot;WGS_1984_UTM_zone_48N&quot;,GEOGCS[&quot;GCS_WGS_1984&quot;,DATUM[&quot;D_WGS_1984&quot;,SPHEROID[&quot;WGS_1984&quot;,6378137.0,298.257223563]],PRIMEM[&quot;Greenwich&quot;,0.0],UNIT[&quot;Degree&quot;,0.0174532925199433]],PROJECTION[&quot;Transverse_Mercator&quot;],PARAMETER[&quot;false_easting&quot;,500000.0],PARAMETER[&quot;false_northing&quot;,0.0],PARAMETER[&quot;central_meridian&quot;,105.0],PARAMETER[&quot;scale_factor&quot;,0.9996],PARAMETER[&quot;latitude_of_origin&quot;,0.0],UNIT[&quot;Meter&quot;,1.0],AUTHORITY[&quot;EPSG&quot;,32648]]</WKT><XOrigin>-5120900</XOrigin><YOrigin>-9998100</YOrigin><XYScale>450445547.3910538</XYScale><ZOrigin>-100000</ZOrigin><ZScale>10000</ZScale><MOrigin>-100000</MOrigin><MScale>10000</MScale><XYTolerance>0.001</XYTolerance><ZTolerance>0.001</ZTolerance><MTolerance>0.001</MTolerance><HighPrecision>true</HighPrecision><WKID>32648</WKID><LatestWKID>32648</LatestWKID></ProjectedCoordinateSystem></peXml>
</coordRef>
<RasterProperties>
<General>
<PixelDepth Sync="TRUE">16</PixelDepth>
<HasColormap Sync="TRUE">FALSE</HasColormap>
<CompressionType Sync="TRUE">LZW</CompressionType>
<NumBands Sync="TRUE">1</NumBands>
<Format Sync="TRUE">TIFF</Format>
<HasPyramids Sync="TRUE">TRUE</HasPyramids>
<SourceType Sync="TRUE">continuous</SourceType>
<PixelType Sync="TRUE">unsigned integer</PixelType>
<NoDataValue Sync="TRUE">0</NoDataValue>
</General>
</RasterProperties>
<lineage>
<Process ToolSource="d:arcgis10.2desktop10.2ArcToolboxToolboxesData Management Tools.tbxClip" Date="20240908" Time="162350">Clip LC08_L2SP_129043_20211120_20211130_02_T1_SR_B1.TIF "244844.439378736 2622315.0081752 363387.169819487 2773349.70606439" E:OpenLayersdatarasterexportLC08_B1.tif Polygon 0 ClippingGeometry NO_MAINTAIN_EXTENT</Process>
</lineage>
</DataProperties>
<SyncDate>20240908</SyncDate>
<SyncTime>16235000</SyncTime>
<ModDate>20240908</ModDate>
<ModTime>16235000</ModTime>
</Esri>
<dataIdInfo>
<envirDesc Sync="TRUE"> Version 6.2 (Build 9200) ; Esri ArcGIS 10.2.0.3348</envirDesc>
<dataLang>
<languageCode value="zho" Sync="TRUE"/>
<countryCode value="CHN" Sync="TRUE"/>
</dataLang>
<idCitation>
<resTitle Sync="TRUE">LC08_B1.tif</resTitle>
<presForm>
<PresFormCd value="005" Sync="TRUE"/>
</presForm>
</idCitation>
<spatRpType>
<SpatRepTypCd value="002" Sync="TRUE"/>
</spatRpType>
<dataExt>
<geoEle>
<GeoBndBox esriExtentType="search">
<exTypeCode Sync="TRUE">1</exTypeCode>
<westBL Sync="TRUE">102.470569</westBL>
<eastBL Sync="TRUE">103.660139</eastBL>
<northBL Sync="TRUE">25.069838</northBL>
<southBL Sync="TRUE">23.691526</southBL>
</GeoBndBox>
</geoEle>
</dataExt>
</dataIdInfo>
<mdLang>
<languageCode value="zho" Sync="TRUE"/>
<countryCode value="CHN" Sync="TRUE"/>
</mdLang>
<mdChar>
<CharSetCd value="004" Sync="TRUE"/>
</mdChar>
<distInfo>
<distFormat>
<formatName Sync="TRUE">Raster Dataset</formatName>
</distFormat>
</distInfo>
<mdHrLv>
<ScopeCd value="005" Sync="TRUE"/>
</mdHrLv>
<mdHrLvName Sync="TRUE">dataset</mdHrLvName>
<refSysInfo>
<RefSystem>
<refSysID>
<identCode code="32648" Sync="TRUE"/>
<idCodeSpace Sync="TRUE">EPSG</idCodeSpace>
<idVersion Sync="TRUE">8.1.1</idVersion>
</refSysID>
</RefSystem>
</refSysInfo>
<spatRepInfo>
<Georect>
<cellGeo>
<CellGeoCd Sync="TRUE" value="002"/>
</cellGeo>
<numDims Sync="TRUE">2</numDims>
<tranParaAv Sync="TRUE">1</tranParaAv>
<chkPtAv Sync="TRUE">0</chkPtAv>
<cornerPts>
<pos Sync="TRUE">244815.000000 2622315.000000</pos>
</cornerPts>
<cornerPts>
<pos Sync="TRUE">244815.000000 2773365.000000</pos>
</cornerPts>
<cornerPts>
<pos Sync="TRUE">363405.000000 2773365.000000</pos>
</cornerPts>
<cornerPts>
<pos Sync="TRUE">363405.000000 2622315.000000</pos>
</cornerPts>
<centerPt>
<pos Sync="TRUE">304110.000000 2697840.000000</pos>
</centerPt>
<axisDimension type="002">
<dimSize Sync="TRUE">3953</dimSize>
<dimResol>
<value Sync="TRUE" uom="Meter">30.000000</value>
</dimResol>
</axisDimension>
<axisDimension type="001">
<dimSize Sync="TRUE">5035</dimSize>
<dimResol>
<value Sync="TRUE" uom="Meter">30.000000</value>
</dimResol>
</axisDimension>
<ptInPixel>
<PixOrientCd Sync="TRUE" value="001"/>
</ptInPixel>
</Georect>
</spatRepInfo>
<contInfo>
<ImgDesc>
<contentTyp>
<ContentTypCd Sync="TRUE" value="001"/>
</contentTyp>
<covDim>
<Band>
<dimDescrp Sync="TRUE">Band_1</dimDescrp>
<bitsPerVal Sync="TRUE">16</bitsPerVal>
<valUnit>
<UOM type="length"/>
</valUnit>
</Band>
</covDim>
</ImgDesc>
</contInfo>
<mdDateSt Sync="TRUE">20240908</mdDateSt>
</metadata>
GeoTools 开发环境搭建:
[2]将 Shp 导入 PostGIS 空间数据的五种方式(全)
[3]GeoTools 结合 OpenLayers 实现空间查询