GDAL+Java实现获取对应栅格影像经纬度对应的像素值

news2024/11/26 5:38:11

从前面的GDAL系列博文中,可以指导GDAL可以将栅格影像文件读出为对应的多维数组,可以读出每一个像素格对应的像素值。但如何根据经纬度直接读取像素值呢?博主从查阅了网上的相关文档,发现有个人写的计算公式是错误的,用代码跑出来的结果都是错误的。于是自己查阅了相关文档,自己实现了一遍,跟大家分享一下。

图像坐标空间到地理参考坐标空间的转换

可以用GDAL读取出每个影像文件的空间地理变换,地理变换是从图像坐标空间(行、列),也称为(像素、线)到地理参考坐标空间(投影或地理坐标)的仿射变换。可以用GetGeoTransform读取出来,由以下六个参数组成

  • GT(0) 左上像素左上角的x坐标。
  • GT(1) w-e像素分辨率/像素宽度。
  • GT(2) 行旋转(通常为零)。
  • GT(3) 左上像素左上角的y坐标。
  • GT(4) 列旋转(通常为零)。
  • GT(5) n-s像素分辨率/像素高度(北上图像为负值)。

从图像坐标空间到地理参考坐标空间的转换关系如下:

X_geo = GT(0) + X_pixel * GT(1) + Y_line * GT(2)
Y_geo = GT(3) + X_pixel * GT(4) + Y_line * GT(5)

X_geo为实际X坐标,Y_geo为实际Y坐标,X_pixel代表栅格数据的第n列,Y_line代表栅格数据的第n行。
注意,上面的像素/线坐标是从左上角的(0.0,0.0)到右下角的(宽度单位为像素,高度单位为像素)。因此,左上角像素中心的像素/线位置为(0.5,0.5)。
如果是北向图像
GT(2) , GT(4) 系数为零。
GT(1) , GT(5) 是像素大小。
GT(0) , GT(3) 位置是栅格左上角像素的左上角。

计算公式

从前面的关系中,可以倒退出对应的计算关系,和计算二元一次方程是一样的。

X_pixel =(GT(5)*X_geo-GT(2)*Y_geo-GT(5)*GT(0)+GT(2)*GT(3))/(GT(5)*GT(1)-GT(2)*GT(4))
Y_line =(Y_geo-GT(3)-xPixel*GT(4))/GT(5)

注意
GT(2) , GT(4)不能作为被除数,这可能导致计算错误

代码实现

package com.meteorology.clock.common;

import org.gdal.gdal.Band;
import org.gdal.gdal.Dataset;
import org.gdal.gdal.Driver;
import org.gdal.gdal.gdal;
import org.gdal.gdalconst.gdalconstConstants;

import java.util.Arrays;

public class RasterTool {
    public static void main(String[] args) {
        //指定经纬度
        double Latitude  =  28.850445;
        double longitude = 119.100341;

        String filepath = "E:\\Z_NAFP_C_BABJ_20230712180520_P_HRCLDAS_RT_BEZZ_0P01_HOR-WIND-2023071218.img";
        //注册
        gdal.AllRegister();
        //打开文件获取数据集
        Dataset dataset = gdal.Open(filepath,
                gdalconstConstants.GA_ReadOnly);
        if (dataset == null) {
            System.out.println("打开"+filepath+"失败"+gdal.GetLastErrorMsg());
            System.exit(1);
        }
        //获取驱动
        Driver driver = dataset.GetDriver();
        //获取驱动信息
        System.out.println("driver long name: " + driver.getLongName());
        //获取栅格数量
        int bandCount = dataset.getRasterCount();
        System.out.println("RasterCount: " + bandCount);
        //构造仿射变换参数数组,并获取数据
        double[] gt = new double[6];
        dataset.GetGeoTransform(gt);
        System.out.println("仿射变换参数"+ Arrays.toString(gt));



        //经纬度转换为栅格像素坐标
        int[] ColRow=Coordinates2ColRow(gt,longitude,Latitude);

        //判断是否坐标超出范围
        if(ColRow[0]<0||ColRow[1]<0||ColRow[0]>=dataset.getRasterXSize()||ColRow[1]>=dataset.getRasterYSize()){
            System.out.println(Arrays.toString(ColRow)+"坐标值超出栅格范围!");
            return;
        }

        //遍历波段,获取该点对应的每个波段的值并打印到屏幕
        for (int i = 0;i<bandCount;i++){
            Band band = dataset.GetRasterBand(i+1);
            double[] values = new double[1];
            band.ReadRaster(ColRow[0], ColRow[1], 1, 1, values);
            double value = values[0];
            System.out.println("横坐标:"+Latitude +","+"纵坐标:"+longitude);
            System.out.format("Band"+(i+1)+": %s", value);
        }
        //释放资源
        dataset.delete();

    }

    /**
     * 将地图坐标转换为栅格像素坐标
     * @param gt 仿射变换参数
     * @param X 横坐标
     * @param Y 纵坐标
     * @return
     */
    public static int[] Coordinates2ColRow(double[] gt, double X, double Y){
//        GT(0) 左上像素左上角的x坐标。
//        GT(1) w-e像素分辨率/像素宽度。
//        GT(2) 行旋转(通常为零)。
//        GT(3) 左上像素左上角的y坐标。
//        GT(4) 列旋转(通常为零)。
//        GT(5) n-s像素分辨率/像素高度(北上图像为负值)

//        如果是北向图像:
//        GT(2) , GT(4) 系数为零。
//        GT(1) , GT(5) 是像素大小。
//        GT(0) , GT(3) 位置是栅格左上角像素的左上角。

//        X_geo = GT(0) + X_pixel * GT(1) + Y_line * GT(2)
//        Y_geo = GT(3) + X_pixel * GT(4) + Y_line * GT(5)
        int[] ints = new int[2];
        //向下取整,如果向上取整会导致计算结果偏大,从而在后面读取到邻近像元的数据
        double xPixel=(gt[5]*X-gt[2]*Y-gt[5]*gt[0]+gt[2]*gt[3])/(gt[5]*gt[1]-gt[2]*gt[4]);
        double yLine=(Y-gt[3]-xPixel*gt[4])/gt[5];
        ints[0]= (int) Math.floor(xPixel);
        ints[1]=(int) Math.floor(yLine);
        System.out.println(ints[0]);
        System.out.println(ints[1]);
        return ints;
    }
}

结果验证

使用ArcGIS工具,打开栅格影像,并查询对应的像素值
ArcGIS结果
程序结果:
代码结果
从上面可以看出,结果一致,而且小数位比ArcGIS更多。

注意

我这里使用的测试栅格影像是WGS84坐标系的,所以这样的计算没有问题,要是其他坐标系的,需要进行坐标转换。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1009277.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

日期类完善

目录 日期类&#xff1a; 运算符重载&#xff1a; ​编辑 赋值重载&#xff1a; 拷贝构造和赋值重载的区别&#xff1a; 实现赋值重载&#xff1a; 划分成员函数&#xff1a; 日期类的声明和定义分离 日期类-&#xff1a; 日期类- 前置后置 日期类&#xff1a; 写一个简…

获取一个对象的直接接口和间接接口

package com.ljr;import java.util.*;public class InterfaceUtils {public static List<Class<?>> getInterfaces(Object obj) {List<Class<?>> interfaces new ArrayList<>();Class<?> clazz obj.getClass();while (clazz ! null) …

(09_13)杭州站|阿里云 Serverless 技术实践营(Serverless + 大数据)开启报名!

活动简介 “Serverless 技术实战与创新沙龙 ” 是一场以 Serverless 为主题的开发者活动&#xff0c;通过一个下午的时间增进对 Serverless 技术的理解&#xff0c;快速上手,活动受众以关注 Serverless 技术的开发者、企业决策人、云原生领域创业者为主&#xff0c;活动形式为…

肖sir__mysql之子查询语句__006

一、子查询 定义:一个查询嵌套另一个查询 例如&#xff1a; 题目&#xff1a;财务部门的收入总和&#xff1b; dept&#xff1a;财务部门 incoming&#xff1a;工资 &#xff08;1&#xff09;先将一个结果查询出来&#xff1a;财务部门的编号查询出来 select dept1 from dept …

管理类联考——数学——汇总篇——知识点突破——代数——等差数列

⛲️ 一、考点讲解 1.定义 如果在数列{ a n a_n an​}中&#xff0c; a n 1 − a n d a_{n1}-a_nd an1​−an​d&#xff08;常数&#xff09; &#xff08; n ∈ N &#xff0b; &#xff09; &#xff08;n∈N_&#xff0b;&#xff09; &#xff08;n∈N&#xff0b;​&a…

一文详解融资融券操作方法和交易规则!

融资融券是投资者利用券商提供的资金或证券进行交易的一种加杠杆的金融操作方式。通过融资融券&#xff0c;投资者可以利用杠杆效应扩大自己的投资规模&#xff0c;提高投资回报。现在有很多投资者使用融资融券账户加杠杆操作&#xff0c;但很多朋友开通了融资融券却也不太会操…

《计算机视觉中的多视图几何》笔记(3)

3 Projective Geometry and Transformations of 3D 这章主要讲的是3D的射影几何&#xff0c;与2D的射影几何差不多。主要区别是&#xff1a; 3D射影几何对偶的是点和平面&#xff0c;直线是自对偶的。3D空间中直线有4个自由度&#xff0c;这一现象并不是那么容易直接得出。一…

DHCP与静态IP:哪种适合你的网络需求?

​如今&#xff0c;大多数网络设备&#xff08;如路由器或网络交换机&#xff09;都使用IP协议作为通过网络进行通信的标准。在IP协议中&#xff0c;网络上的每个设备都有一个唯一的标识符&#xff0c;称为IP地址。实现这一点的最简单方法是配置固定IP地址或静态IP地址。由于静…

Hyperopt:分布式异步超参数优化(Distributed Asynchronous Hyperparameter Optimization)

1、概述 在深度学习的训练模型过程中&#xff0c;参数的优化是一个比较繁琐的过程&#xff0c;一般使用网格搜索Grid search与人工搜索Manual search&#xff0c;所以这个参数优化有时候看起来就像太上老君炼丹&#xff0c;是一个有点玄的东西。 那有没有一种可以自动去调优的…

c\c++ windows自动打开cmd并进入mysql

每次不用可视化工具查看数据库的时候饭都要winr->cmd->mysql -u root -p->密码 虽然不麻烦但是多少也得消耗你几秒钟&#xff0c;秉承着时间就是金钱的观念 我决定通过windows模拟输入实现快速通过命令行查看mysql数据库 涉及到的知识: windows拉起进程&#xff0c;…

无线耳机能不能设计成我想象的这样的?

市面上有没有这种耳钉式的无线耳机啊&#xff0c;有的话能推荐一下吗&#xff1f;没有的话无线耳机的厂家能不能考虑一下这个方案&#xff0c;这样我们女生带耳机穿衣服或者梳头发的时候就不用摘下来了&#xff0c;也不会经常到处找耳机了 这样既能当耳机&#xff0c;又能做装…

测试 c++ 之 is_function_v

如图&#xff0c;给 is_function_v 传入一个类&#xff0c;为假&#xff0c;传入一个函数对象则为真 。 &#xff08;2&#xff09;以下是文心一言的解释&#xff0c;真好&#xff1a; 在 C 中&#xff0c;std::is_function_v 是一个类型特征&#xff08;type trait&#xff09…

数组和指针笔试题解析之【数组】

前言&#xff1a; 1.数组名的意义&#xff1a; sizeof(数组名)&#xff1a;这里的数组名表示整个数组&#xff0c;计算的是整个数组的大小&#xff0c;单位是字节。&数组名&#xff1a;这里的数组名表示整个数组&#xff0c;取出的是整个数组的地址。除此之外所有的数组名都…

爬虫逆向实战(33)-某联社数据(webpack)

一、数据接口分析 主页地址&#xff1a;某联社 1、抓包 通过抓包可以发现数据接口是/nodeapi/telegraphList 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看“载荷”模块可以发现有一个sign加密参数 请求头是否加密&#xff1f; 无 响应是否加密&#x…

uni-app 新增 微信小程序之新版隐私协议

一、manifest.json中配置 "__usePrivacyCheck__": true 二、编写封装后的组件 <template><view class"privacy" v-if"showPrivacy"><view class"content"><view class"title">隐私保护指引</…

无涯教程-JavaScript - SHEET函数

描述 SHEET函数返回参考图纸的图纸编号。 语法 SHEET (value)争论 Argument描述Required/OptionalValue 值是您要为其指定工作表编号的工作表名称或参考。 如果省略value,则SHEET返回包含该功能的工作表的编号。 Optional Notes 除了所有其他工作表类型(宏,图表或对话框工…

【Python爬虫】python打印本地代理

目录 前言 代理 IP 的使用 1. 获取代理 IP 2. 选择合适的代理 IP 3. 设置代理 IP 4. 验证代理 IP 代码案例 总结 前言 在进行网络爬虫时&#xff0c;使用代理是非常重要的。因为爬虫经常会被网站封 IP&#xff0c;而代理可以隐藏你的真实 IP 地址&#xff0c;让你可以…

智慧港口4G+UWB+GPS/北斗RTK人员定位系统解决方案

港口人员定位系统能够帮助企业实现对港口作业人员的全面监控和管理&#xff0c;不仅可以保障人员的人身安全&#xff0c;还可以提高人员的作业效率&#xff0c;为港口的可持续发展提供有力保障。接下来为大家分享智慧港口人员定位系统解决方案。 方案背景 1、港口作业人员多&a…

APK安装过程解析

应用端发起安装APK的代码一般如下&#xff1a; Intent installintent new Intent();installintent.setAction(Intent.ACTION_VIEW);installintent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);installintent.setDataAndType(xxx,"application/vnd.android.package-archive&…

SpringMVC系列(四)之SpringMVC实现文件上传和下载

目录 前言 一. SpringMVC文件上传 1. 配置多功能视图解析器 2. 前端代码中&#xff0c;将表单标记为多功能表单 3. 后端利用MultipartFile 接口&#xff0c;接收前端传递到后台的文件 4. 文件上传示例 1. 相关依赖&#xff1a; 2. 逆向生成对应的类 3. 后端代码&#xf…