GDAL 读取遥感影像数据

前言

为了进一步对遥感影像数据进行处理,需要访问遥感影像中的数据,即影像像元灰度值。在 GDAL 中,提供了 ReadRaster() 和 ReadAsArray() 两个方法用来访问影像数据。

本篇教程在之前一系列文章的基础上讲解

  • GDAL 简介[1]
  • GDAL 下载安装[2]
  • GDAL 开发起步[3]

如果你还没有看过,建议从那里开始。

1. 开发环境

本文使用如下开发环境,以供参考。

时间:2025年

系统:Windows 10

Python:3.11.7

GDAL:3.7.3

Numpy:1.24.3

2. ReadRaster 方法

ReadRaster方法返回一个栅格字节流数据,具有多个参数。

  • xoff,yoff :目标点距离全图原点的位置(以像元为单位)
  • xsize,ysize : 目标图像的矩形的长和宽(以像元为单位)
  • buf_xsize,buf_ysize :图像缩放大小。用来定义缩放后图像最终的宽和高
  • buf_type :对读取的数据类型进行转换(比如原图数据类型是short,可以将其缩小成byte
  • band_list :适应多波段的情况。可以指定要读取的波段。
ini 复制代码
from osgeo import gdal

# 启用异常处理(推荐)
gdal.UseExceptions()

# 打开影像文件
dataset = gdal.Open("LC08_L1TP_130042_20210212_20210304_01_T1_B1.TIF")

print(help(dataset.ReadRaster()))
# 获取目标波段数据
band = dataset.GetRasterBand(1)

print("波段数据:",band)

# 读取整个波段为字节流
bytes_stream = band.ReadRaster()

# 读取指定区域
xoff,yoff,xsize,ysize = 100,100,200,200
buf_xsize,buf_ysize = 200,200

data_bytes_region = band.ReadRaster(xoff,yoff,xsize,ysize,buf_xsize,buf_ysize)
# print("n 数据区域:",data_bytes_region)

# 指定数据类型
data_bytes_float = band.ReadRaster(buf_type=gdal.GDT_Float32)
# print("n 数据类型:",data_bytes_float3

3. ReadAsArray 方法

ReadAsArray方法与ReadRaster方法相似具有多个参数,不同的是起返回的数据为类型数组。

  • xoff,yoff :目标点距离全图原点的位置(以像元为单位)
  • xsize,ysize : 目标图像的矩形的长和宽(以像元为单位)
  • buf_xsize,buf_ysize :图像缩放大小。用来定义缩放后图像最终的宽和高
  • buf_type :对读取的数据类型进行转换(比如原图数据类型是short,可以将其缩小成byte
  • band_list :适应多波段的情况。可以指定要读取的波段。
ini 复制代码
from osgeo import gdal
import numpy as np

# 启用异常处理(推荐)
gdal.UseExceptions()

# 打开影像文件
dataset = gdal.Open("LC08_L1TP_130042_20210212_20210304_01_T1_B1.TIF")

band = dataset.GetRasterBand(1)

# 读取整个波段
array = band.ReadAsArray()
print(type(array)) # <class 'numpy.ndarray'>
print(array.shape) # (行数, 列数)

# 读取指定区域
xoff,yoff,xsize,ysize = 100,100,200,200
sub_array = band.ReadAsArray(xoff,yoff,xsize,ysize)

# 分块读取
buf_xsize,buf_ysize = 100,100
array_buf = band.ReadAsArray(buf_xsize=buf_xsize,buf_ysize=buf_ysize)

4. 读取多波段数据

本例中未进行波段合成,只有一个波段数据,所以直接用dataset.GetRasterBand(1)读取波段数据。

ini 复制代码
"""
读取多波段数据
"""
import numpy as np
from osgeo import gdal

# 启用异常处理(推荐)
gdal.UseExceptions()

# 打开影像文件
dataset = gdal.Open("D:AppLC81300422021043LGN00LC08_L1TP_130042_20210212_20210304_01_T1_B1.TIF")

def read_multi_band(dataset,method="array"):
    # 获取波段总数
    bands_count = dataset.RasterCount
    rows,cols = dataset.RasterYSize,dataset.RasterXSize

    if method == "array":
        # 使用 ReadAsArray
        data = np.zeros((rows,cols,bands_count))
        for i in range(bands_count):
            band = dataset.GetRasterBand(1)
            if band:
                data[:,:,i] = band.ReadAsArray()
    elif method == "raster":
        # 使用 ReadRaster
        data = np.zeros((rows,cols,bands_count))
        for i in range(bands_count):
            band = dataset.GetRasterBand(1)
            if band:
                data_bytes = band.ReadRaster()
                # 数据转换
                band_array = np.frombuffer(data_bytes,dtype=gdal.GetDataTypeName(band.DataType).lower())
                data[:, :, i] = band_array.reshape((rows, cols))

    return data

data_bytes = read_multi_band(dataset,'raster') 
data_array = read_multi_band(dataset,'array')  

print(f"数据相等:{data_bytes == data_array}") 

5. 性能测试

在GDAL中,使用ReadAsArray方法与ReadRaster方法读取栅格数据在效率上存在较大差距。经过测试发现,ReadRaster方法比起ReadAsArray方法要快很多。

python 复制代码
"""
性能测试
"""
import time
import numpy as np
from osgeo import gdal

# 启用异常处理(推荐)
gdal.UseExceptions()

# 打开影像文件
dataset = gdal.Open("D:AppLC81300422021043LGN00LC08_L1TP_130042_20210212_20210304_01_T1_B1.TIF")

band = dataset.GetRasterBand(1)

def perfomanse(band):
    # 测试ReadArray
    start_time = time.time()
    array1 = band.ReadAsArray()
    time_array = time.time() - start_time

    # 测试ReadRaster
    start_time = time.time()
    data_bytes = band.ReadRaster()
    array2 = np.frombuffer(data_bytes,dtype=gdal.GetDataTypeName(band.DataType).lower())
    array2 = array2.reshape((band.YSize,band.XSize))
    time_raster = time.time() - start_time

    print(f"ReadArray时间:{time_array:.4f} s")
    print(f"ReadRaster时间:{time_raster:.4f} s")
    print(f"结果相等: {np.array_equal(array1, array2)}")

    return time_array, time_raster

perfomanse(band)

以下是输出结果。

6. 主要区别

ReadAsArray方法与ReadRaster方法存在以下区别。ReadAsArray()方法更简单、更直接,适合大多数应用场景;而ReadRaster()方法更灵活、更底层,适合需要精细控制的高级应用。

特性 ReadRaster() ReadAsArray()
返回类型 二进制字节流 (bytes) NumPy数组
内存使用 较低,需要手动处理 较高,自动转换为数组
灵活性 高,可控制数据类型和读取区域 较低,但更易用
性能 需要额外转换步骤 直接返回数组,性能更好
使用复杂度 较高,需要更多代码 较低,简单易用

参考资料

1\]GDAL 简介 \[2\]GDAL 下载安装 \[3\]GDAL 开发起步

相关推荐
木易 士心8 小时前
Ref 和 Reactive 响应式原理剖析与代码实现
前端·javascript·vue.js
程序员博博8 小时前
概率与决策 - 模拟程序让你在选择中取胜
前端
被巨款砸中8 小时前
一篇文章讲清Prompt、Agent、MCP、Function Calling
前端·vue.js·人工智能·web
sophie旭8 小时前
一道面试题,开始性能优化之旅(1)-- beforeFetch
前端·性能优化
Cache技术分享8 小时前
204. Java 异常 - Error 类:表示 Java 虚拟机中的严重错误
前端·后端
uhakadotcom8 小时前
execjs有哪些常用的api,如何逆向分析网站的加签机制
前端·javascript·面试
ObjectX前端实验室8 小时前
【图形编辑器架构】:无限画布标尺与网格系统实现解析
前端·canvas·图形学
你的电影很有趣9 小时前
lesson71:Node.js与npm基础全攻略:2025年最新特性与实战指南
前端·npm·node.js
闲蛋小超人笑嘻嘻9 小时前
find数组方法详解||Vue3 + uni-app + Wot Design(wd-picker)使用自定义插槽内容写一个下拉选择器
前端·javascript·uni-app
小牛itbull9 小时前
初始化electron项目运行后报错 electron uninstall 解决方法
前端·javascript·electron