当前位置: 首页 > web >正文

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">&lt;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'&gt;&lt;WKT&gt;PROJCS[&amp;quot;WGS_1984_UTM_zone_48N&amp;quot;,GEOGCS[&amp;quot;GCS_WGS_1984&amp;quot;,DATUM[&amp;quot;D_WGS_1984&amp;quot;,SPHEROID[&amp;quot;WGS_1984&amp;quot;,6378137.0,298.257223563]],PRIMEM[&amp;quot;Greenwich&amp;quot;,0.0],UNIT[&amp;quot;Degree&amp;quot;,0.0174532925199433]],PROJECTION[&amp;quot;Transverse_Mercator&amp;quot;],PARAMETER[&amp;quot;false_easting&amp;quot;,500000.0],PARAMETER[&amp;quot;false_northing&amp;quot;,0.0],PARAMETER[&amp;quot;central_meridian&amp;quot;,105.0],PARAMETER[&amp;quot;scale_factor&amp;quot;,0.9996],PARAMETER[&amp;quot;latitude_of_origin&amp;quot;,0.0],UNIT[&amp;quot;Meter&amp;quot;,1.0],AUTHORITY[&amp;quot;EPSG&amp;quot;,32648]]&lt;/WKT&gt;&lt;XOrigin&gt;-5120900&lt;/XOrigin&gt;&lt;YOrigin&gt;-9998100&lt;/YOrigin&gt;&lt;XYScale&gt;450445547.3910538&lt;/XYScale&gt;&lt;ZOrigin&gt;-100000&lt;/ZOrigin&gt;&lt;ZScale&gt;10000&lt;/ZScale&gt;&lt;MOrigin&gt;-100000&lt;/MOrigin&gt;&lt;MScale&gt;10000&lt;/MScale&gt;&lt;XYTolerance&gt;0.001&lt;/XYTolerance&gt;&lt;ZTolerance&gt;0.001&lt;/ZTolerance&gt;&lt;MTolerance&gt;0.001&lt;/MTolerance&gt;&lt;HighPrecision&gt;true&lt;/HighPrecision&gt;&lt;WKID&gt;32648&lt;/WKID&gt;&lt;LatestWKID&gt;32648&lt;/LatestWKID&gt;&lt;/ProjectedCoordinateSystem&gt;</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>
参考资料
[1]

GeoTools 开发环境搭建:

[2]

将 Shp 导入 PostGIS 空间数据的五种方式(全)

[3]

GeoTools 结合 OpenLayers 实现空间查询

http://www.xdnf.cn/news/18332.html

相关文章:

  • OpenHarmony 之多模态输入子系统源码深度架构解析
  • Web3.0 时代的电商系统:区块链如何解决信任与溯源问题?
  • SWMM排水管网水力、水质建模及在海绵与水环境中的应用
  • C++常见面试题-2.C++类相关
  • EPM240T100I5N Altera FPGA MAX II CPLD
  • 深度学习-167-MCP技术之工具函数的设计及注册到MCP服务器的两种方式
  • TensorFlow 面试题及详细答案 120道(11-20)-- 操作与数据处理
  • 【Linux】文件系统
  • 前端面试核心技术30问
  • 《C++进阶之STL》【二叉搜索树】
  • 神经网络中的那些关键设计:从输入输出到参数更新
  • Python 函数进阶:深入理解参数、装饰器与函数式编程
  • Java 大视界 -- Java 大数据在智能物流无人配送车路径规划与协同调度中的应用
  • 暴雨中的“天眼”:天通哨兵PS02卫星图传系统筑牢防汛安全网
  • 前端面试题1
  • 边缘智能体:Go编译在医疗IoT设备端运行轻量AI模型(上)
  • Springboot使用Selenium+ChormeDriver在服务器(Linux)端将网页保存为图片或PDF
  • Rust学习笔记(七)|错误处理
  • 0819 使用IP多路复用实现TCP并发服务器
  • 反向代理实现服务器联网
  • Auto-CoT:大型语言模型的自动化思维链提示技术
  • 微服务-08.微服务拆分-拆分商品服务
  • 深度学习环境搭建Windows+ TensorFlow 2.6.0 GPU 版
  • 亚矩阵云手机智能定位:助力Snapchat矩阵账号的本地化内容运营穿透技术
  • Apache IoTDB(4):深度解析时序数据库 IoTDB 在Kubernetes 集群中的部署与实践指南
  • 连接远程服务器上的 jupyter notebook,解放本地电脑
  • VSCode 从安装到精通:下载安装与快捷键全指南
  • 11.第11章 开发环境优化
  • 【C语言强化训练16天】--从基础到进阶的蜕变之旅:Day7
  • Nacos-6--Naco的QUIC协议实现高可用的工作原理