栅格数据处理

第七章 栅格数据处理

7.1 栅格数据基础

7.1.1 栅格数据模型

栅格数据由规则网格的像元(像素)组成:

栅格数据结构
├── 头文件信息
│   ├── 行数/列数
│   ├── 像元大小
│   ├── 地理范围
│   ├── 坐标系
│   └── 无数据值
└── 像元值矩阵
    ├── 波段1
    ├── 波段2
    └── ...

7.1.2 栅格数据类型

数据类型 取值范围 应用场景
Byte 0-255 8位影像
Int16 -32768 to 32767 有符号整数
UInt16 0-65535 无符号整数
Int32 ±2.1×10⁹ 32位整数
Float32 浮点数 DEM、连续数据
Float64 双精度浮点 高精度计算

7.1.3 常见栅格格式

格式 扩展名 特点
GeoTIFF .tif 最通用,支持压缩
ERDAS IMG .img Imagine格式
JPEG2000 .jp2 高压缩比
PNG .png 无损压缩
ASCII Grid .asc 文本格式
NetCDF .nc 多维科学数据
HDF .hdf 层级数据

7.1.4 PyQGIS栅格操作基础

from qgis.core import QgsRasterLayer, QgsProject

# 加载栅格图层
layer = QgsRasterLayer("/path/to/raster.tif", "raster")
if layer.isValid():
    QgsProject.instance().addMapLayer(layer)

# 获取栅格信息
print(f"宽度: {layer.width()}")
print(f"高度: {layer.height()}")
print(f"波段数: {layer.bandCount()}")
print(f"范围: {layer.extent()}")
print(f"CRS: {layer.crs().authid()}")

# 获取像元大小
print(f"X分辨率: {layer.rasterUnitsPerPixelX()}")
print(f"Y分辨率: {layer.rasterUnitsPerPixelY()}")

# 获取数据提供者
provider = layer.dataProvider()
print(f"数据类型: {provider.dataType(1)}")  # 波段1的数据类型

7.2 栅格图层属性

7.2.1 图层属性对话框

打开方式

  • 双击图层
  • 右键 > 属性
  • 图层 > 图层属性

主要选项卡

选项卡 功能
信息 元数据和统计
数据源设置
符号 渲染方式
透明度 透明度设置
直方图 值分布
渲染 渲染选项
金字塔 概览图层
元数据 描述信息
图例 图例设置

7.2.2 栅格信息

# 获取详细统计信息
stats = provider.bandStatistics(1)  # 波段1
print(f"最小值: {stats.minimumValue}")
print(f"最大值: {stats.maximumValue}")
print(f"平均值: {stats.mean}")
print(f"标准差: {stats.stdDev}")

# 获取波段描述
for band in range(1, layer.bandCount() + 1):
    print(f"波段{band}: {provider.generateBandName(band)}")

7.2.3 无数据值设置

# 设置无数据值
provider.setNoDataValue(1, -9999)  # 波段1设置nodata为-9999

# 检查某值是否为nodata
if provider.isNoDataValue(1, value):
    print("这是无数据值")

7.3 栅格渲染

7.3.1 单波段灰度

from qgis.core import QgsSingleBandGrayRenderer, QgsContrastEnhancement

# 设置单波段灰度渲染
renderer = QgsSingleBandGrayRenderer(provider, 1)  # 波段1

# 设置对比度增强
enhancement = QgsContrastEnhancement(provider.dataType(1))
enhancement.setContrastEnhancementAlgorithm(
    QgsContrastEnhancement.StretchToMinimumMaximum
)
enhancement.setMinimumValue(0)
enhancement.setMaximumValue(255)
renderer.setContrastEnhancement(enhancement)

layer.setRenderer(renderer)
layer.triggerRepaint()

7.3.2 单波段伪彩色

from qgis.core import (
    QgsSingleBandPseudoColorRenderer,
    QgsColorRampShader,
    QgsRasterShader
)

# 创建颜色渐变
shader = QgsRasterShader()
colorRamp = QgsColorRampShader()
colorRamp.setColorRampType(QgsColorRampShader.Interpolated)

# 定义颜色节点
colorRamp.setColorRampItemList([
    QgsColorRampShader.ColorRampItem(0, QColor(0, 0, 255), "低"),
    QgsColorRampShader.ColorRampItem(50, QColor(0, 255, 0), "中"),
    QgsColorRampShader.ColorRampItem(100, QColor(255, 0, 0), "高")
])
shader.setRasterShaderFunction(colorRamp)

# 应用渲染器
renderer = QgsSingleBandPseudoColorRenderer(provider, 1, shader)
layer.setRenderer(renderer)
layer.triggerRepaint()

7.3.3 多波段彩色合成

from qgis.core import QgsMultiBandColorRenderer

# RGB合成(假设波段4=红,波段3=绿,波段2=蓝)
renderer = QgsMultiBandColorRenderer(provider, 4, 3, 2)

# 设置各波段对比度
for band in [4, 3, 2]:
    enhancement = QgsContrastEnhancement(provider.dataType(band))
    enhancement.setContrastEnhancementAlgorithm(
        QgsContrastEnhancement.StretchToMinimumMaximum
    )
    if band == 4:
        renderer.setRedContrastEnhancement(enhancement)
    elif band == 3:
        renderer.setGreenContrastEnhancement(enhancement)
    else:
        renderer.setBlueContrastEnhancement(enhancement)

layer.setRenderer(renderer)
layer.triggerRepaint()

7.3.4 调色板渲染

from qgis.core import QgsPalettedRasterRenderer

# 获取唯一值
classes = QgsPalettedRasterRenderer.classDataFromRaster(provider, 1)

# 创建渲染器
renderer = QgsPalettedRasterRenderer(provider, 1, classes)
layer.setRenderer(renderer)

7.3.5 山体阴影

from qgis.core import QgsHillshadeRenderer

# 设置山体阴影渲染
renderer = QgsHillshadeRenderer(provider, 1, 315, 45)
# 参数:提供者,波段,方位角(度),高度角(度)
renderer.setZFactor(1.0)  # 垂直放大系数

layer.setRenderer(renderer)
layer.triggerRepaint()

7.4 栅格计算器

7.4.1 GUI栅格计算器

打开方式

栅格 > 栅格计算器

界面组件

  • 栅格波段列表
  • 运算符按钮
  • 表达式输入框
  • 输出设置

表达式示例

# NDVI计算
( "landsat@4" - "landsat@3" ) / ( "landsat@4" + "landsat@3" )

# 条件判断
("dem@1" > 1000) * 1 + ("dem@1" <= 1000) * 0

# 数学运算
sqrt("raster@1" * "raster@1" + "raster@2" * "raster@2")

# 多栅格运算
"raster1@1" + "raster2@1" - "raster3@1"

# 逻辑运算
("raster@1" > 50) AND ("raster@1" < 100)

7.4.2 PyQGIS栅格计算

from qgis.analysis import QgsRasterCalculator, QgsRasterCalculatorEntry

# 准备输入栅格
entries = []

layer = QgsProject.instance().mapLayersByName("dem")[0]
entry = QgsRasterCalculatorEntry()
entry.ref = "dem@1"
entry.raster = layer
entry.bandNumber = 1
entries.append(entry)

# 计算表达式
calc = QgsRasterCalculator(
    '"dem@1" * 0.001',  # 表达式:转换单位
    '/path/to/output.tif',  # 输出路径
    'GTiff',  # 格式
    layer.extent(),  # 范围
    layer.width(),  # 宽度
    layer.height(),  # 高度
    entries  # 输入
)

result = calc.processCalculation()
if result == 0:
    print("计算成功")

7.4.3 使用Processing进行栅格计算

import processing

# GDAL栅格计算
result = processing.run("gdal:rastercalculator", {
    'INPUT_A': '/path/to/raster.tif',
    'BAND_A': 1,
    'FORMULA': 'A * 0.001',
    'OUTPUT': '/path/to/output.tif'
})

# NDVI计算示例
result = processing.run("gdal:rastercalculator", {
    'INPUT_A': layer,  # 红波段
    'BAND_A': 4,
    'INPUT_B': layer,  # 近红外波段
    'BAND_B': 5,
    'FORMULA': '(B-A)/(B+A)',
    'OUTPUT': 'memory:'
})

7.5 栅格分析

7.5.1 地形分析

坡度

result = processing.run("gdal:slope", {
    'INPUT': dem_layer,
    'BAND': 1,
    'SCALE': 1,
    'AS_PERCENT': False,
    'OUTPUT': '/path/to/slope.tif'
})

坡向

result = processing.run("gdal:aspect", {
    'INPUT': dem_layer,
    'BAND': 1,
    'TRIG_ANGLE': False,
    'ZERO_FLAT': True,
    'OUTPUT': '/path/to/aspect.tif'
})

山体阴影

result = processing.run("gdal:hillshade", {
    'INPUT': dem_layer,
    'BAND': 1,
    'Z_FACTOR': 1,
    'SCALE': 1,
    'AZIMUTH': 315,
    'ALTITUDE': 45,
    'OUTPUT': '/path/to/hillshade.tif'
})

粗糙度

result = processing.run("gdal:roughness", {
    'INPUT': dem_layer,
    'BAND': 1,
    'OUTPUT': '/path/to/roughness.tif'
})

TRI(地形粗糙指数)

result = processing.run("gdal:tpitopographicpositionindex", {
    'INPUT': dem_layer,
    'BAND': 1,
    'OUTPUT': '/path/to/tpi.tif'
})

7.5.2 栅格统计

分区统计

result = processing.run("native:zonalstatisticsfb", {
    'INPUT': polygon_layer,
    'INPUT_RASTER': raster_layer,
    'RASTER_BAND': 1,
    'COLUMN_PREFIX': 'stat_',
    'STATISTICS': [0, 1, 2, 4, 5, 6],  # Count, Sum, Mean, Std, Min, Max
    'OUTPUT': 'memory:'
})

栅格图层统计

result = processing.run("native:rasterlayerstatistics", {
    'INPUT': raster_layer,
    'BAND': 1,
    'OUTPUT_HTML_FILE': '/path/to/stats.html'
})

栅格直方图

# 获取直方图数据
histogram = provider.histogram(1)  # 波段1
for i, count in enumerate(histogram.histogramVector):
    value = histogram.minimum + i * histogram.binWidth
    print(f"值{value}: {count}个像元")

7.5.3 栅格重分类

使用查找表重分类

result = processing.run("native:reclassifybytable", {
    'INPUT_RASTER': raster_layer,
    'RASTER_BAND': 1,
    'TABLE': [0, 100, 1, 100, 200, 2, 200, 300, 3],  # min1,max1,new1,...
    'NO_DATA': -9999,
    'RANGE_BOUNDARIES': 0,  # 0=min<value<=max
    'OUTPUT': '/path/to/reclass.tif'
})

使用表达式重分类

# 通过栅格计算器实现
expression = '''
CASE 
    WHEN "raster@1" < 100 THEN 1
    WHEN "raster@1" < 200 THEN 2
    WHEN "raster@1" < 300 THEN 3
    ELSE 4
END
'''

7.5.4 等值线提取

result = processing.run("gdal:contour", {
    'INPUT': dem_layer,
    'BAND': 1,
    'INTERVAL': 10,        # 等高距
    'FIELD_NAME': 'ELEV',
    'CREATE_3D': False,
    'IGNORE_NODATA': True,
    'OUTPUT': '/path/to/contours.shp'
})

# 等值面(填充等值线)
result = processing.run("gdal:contour_polygon", {
    'INPUT': dem_layer,
    'BAND': 1,
    'INTERVAL': 10,
    'OUTPUT': '/path/to/contour_polygons.shp'
})

7.6 栅格转换

7.6.1 格式转换

# GDAL转换
result = processing.run("gdal:translate", {
    'INPUT': input_raster,
    'TARGET_CRS': 'EPSG:4326',
    'DATA_TYPE': 0,  # 0=Use input, 1=Byte, 5=Float32等
    'OUTPUT': '/path/to/output.tif'
})

7.6.2 投影转换

result = processing.run("gdal:warpreproject", {
    'INPUT': input_raster,
    'SOURCE_CRS': 'EPSG:4326',
    'TARGET_CRS': 'EPSG:32650',
    'RESAMPLING': 0,  # 0=最近邻, 1=双线性, 2=三次卷积
    'TARGET_RESOLUTION': 30,
    'OUTPUT': '/path/to/reprojected.tif'
})

7.6.3 重采样

# 修改分辨率
result = processing.run("gdal:warpreproject", {
    'INPUT': input_raster,
    'TARGET_CRS': '',
    'RESAMPLING': 1,  # 双线性
    'TARGET_RESOLUTION': 10,  # 新分辨率
    'OUTPUT': '/path/to/resampled.tif'
})

7.6.4 裁剪栅格

按范围裁剪

result = processing.run("gdal:cliprasterbyextent", {
    'INPUT': raster_layer,
    'PROJWIN': '100,120,30,45',  # xmin,xmax,ymin,ymax
    'OUTPUT': '/path/to/clipped.tif'
})

按掩膜裁剪

result = processing.run("gdal:cliprasterbymasklayer", {
    'INPUT': raster_layer,
    'MASK': polygon_layer,
    'CROP_TO_CUTLINE': True,
    'KEEP_RESOLUTION': True,
    'OUTPUT': '/path/to/masked.tif'
})

7.6.5 镶嵌

result = processing.run("gdal:merge", {
    'INPUT': [raster1, raster2, raster3],
    'PCT': False,
    'SEPARATE': False,
    'OUTPUT': '/path/to/mosaic.tif'
})

# 使用VRT虚拟镶嵌
result = processing.run("gdal:buildvirtualraster", {
    'INPUT': [raster1, raster2, raster3],
    'RESOLUTION': 0,  # 0=平均, 1=最高, 2=最低
    'SEPARATE': False,
    'OUTPUT': '/path/to/mosaic.vrt'
})

7.6.6 栅格转矢量

多边形化

result = processing.run("gdal:polygonize", {
    'INPUT': raster_layer,
    'BAND': 1,
    'FIELD': 'DN',
    'OUTPUT': '/path/to/polygons.shp'
})

等值线

result = processing.run("gdal:contour", {
    'INPUT': dem_layer,
    'BAND': 1,
    'INTERVAL': 10,
    'OUTPUT': '/path/to/contours.shp'
})

7.6.7 矢量转栅格

result = processing.run("gdal:rasterize", {
    'INPUT': vector_layer,
    'FIELD': 'value_field',
    'UNITS': 1,  # 1=像素
    'WIDTH': 1000,
    'HEIGHT': 1000,
    'EXTENT': vector_layer.extent(),
    'OUTPUT': '/path/to/rasterized.tif'
})

# 或使用像元大小
result = processing.run("gdal:rasterize", {
    'INPUT': vector_layer,
    'FIELD': 'value_field',
    'UNITS': 0,  # 0=地理单位
    'WIDTH': 10,
    'HEIGHT': 10,
    'OUTPUT': '/path/to/rasterized.tif'
})

7.7 栅格金字塔

7.7.1 什么是金字塔

栅格金字塔是预先计算的降采样版本,用于快速显示大型栅格:

原始分辨率 (Level 0)
    ↓ 2倍降采样
Level 1 (1/2分辨率)
    ↓ 2倍降采样
Level 2 (1/4分辨率)
    ↓ ...

7.7.2 创建金字塔

GUI方式

图层属性 > 金字塔 > 构建金字塔

命令行/PyQGIS

result = processing.run("gdal:overviews", {
    'INPUT': raster_layer,
    'LEVELS': '2 4 8 16',
    'CLEAN': False,
    'RESAMPLING': 0,  # 0=最近邻, 1=平均, 2=Gauss
    'FORMAT': 0  # 0=内部, 1=外部(.ovr)
})

7.7.3 删除金字塔

result = processing.run("gdal:overviews", {
    'INPUT': raster_layer,
    'CLEAN': True  # 删除金字塔
})

7.8 栅格样式

7.8.1 颜色映射表

from qgis.core import QgsColorRampShader, QgsRasterShader
from qgis.PyQt.QtGui import QColor

# 创建颜色表
colorRamp = QgsColorRampShader()
colorRamp.setColorRampType(QgsColorRampShader.Discrete)  # 离散或插值

# 设置颜色项
items = [
    QgsColorRampShader.ColorRampItem(1, QColor(255, 0, 0), "类型1"),
    QgsColorRampShader.ColorRampItem(2, QColor(0, 255, 0), "类型2"),
    QgsColorRampShader.ColorRampItem(3, QColor(0, 0, 255), "类型3"),
]
colorRamp.setColorRampItemList(items)

# 应用到图层
shader = QgsRasterShader()
shader.setRasterShaderFunction(colorRamp)
renderer = QgsSingleBandPseudoColorRenderer(provider, 1, shader)
layer.setRenderer(renderer)

7.8.2 透明度设置

# 设置整体透明度
layer.renderer().setOpacity(0.5)

# 设置无数据值透明
renderer = layer.renderer()
renderer.setNodataColor(QColor(0, 0, 0, 0))

# 设置特定值透明
from qgis.core import QgsRasterTransparency

transparency = QgsRasterTransparency()
# 设置单值透明
pixelList = [
    QgsRasterTransparency.TransparentSingleValuePixel(0, 0, 100)  # 值,透明度
]
transparency.setTransparentSingleValuePixelList(pixelList)
renderer.setRasterTransparency(transparency)

7.8.3 混合模式

from qgis.PyQt.QtGui import QPainter

# 设置图层混合模式
layer.setBlendMode(QPainter.CompositionMode_Multiply)

# 可用混合模式:
# CompositionMode_SourceOver (正常)
# CompositionMode_Multiply (正片叠底)
# CompositionMode_Screen (滤色)
# CompositionMode_Overlay (叠加)
# ...

7.9 栅格数据导出

7.9.1 导出为文件

# 使用Processing导出
result = processing.run("gdal:translate", {
    'INPUT': layer,
    'OPTIONS': 'COMPRESS=LZW',  # 压缩选项
    'DATA_TYPE': 5,  # Float32
    'OUTPUT': '/path/to/output.tif'
})

7.9.2 导出带样式

# 渲染后导出为图像
from qgis.core import QgsMapSettings, QgsMapRendererSequentialJob

settings = QgsMapSettings()
settings.setLayers([layer])
settings.setExtent(layer.extent())
settings.setOutputSize(QSize(1000, 1000))

job = QgsMapRendererSequentialJob(settings)
job.start()
job.waitForFinished()
image = job.renderedImage()
image.save('/path/to/rendered.png')

7.9.3 Cloud Optimized GeoTIFF (COG)

result = processing.run("gdal:translate", {
    'INPUT': layer,
    'OPTIONS': 'TILED=YES|COMPRESS=DEFLATE|COPY_SRC_OVERVIEWS=YES',
    'OUTPUT': '/path/to/output_cog.tif'
})

# 或使用专门的COG驱动
result = processing.run("gdal:translate", {
    'INPUT': layer,
    'FORMAT': 'COG',
    'OUTPUT': '/path/to/output.tif'
})

7.10 遥感图像处理

7.10.1 NDVI计算

# 计算NDVI (归一化植被指数)
# NDVI = (NIR - Red) / (NIR + Red)

result = processing.run("gdal:rastercalculator", {
    'INPUT_A': landsat_layer,  # 红波段
    'BAND_A': 4,
    'INPUT_B': landsat_layer,  # 近红外波段
    'BAND_B': 5,
    'FORMULA': '(B-A)/(B+A)',
    'OUTPUT': '/path/to/ndvi.tif'
})

7.10.2 影像分类

非监督分类(K-means)

result = processing.run("grass7:i.cluster", {
    'input': multiband_raster,
    'signaturefile': '/path/to/signature',
    'classes': 5,
    'output': '/path/to/classified.tif'
})

7.10.3 直方图匹配

result = processing.run("saga:histogrammatching", {
    'GRID': input_raster,
    'REFERENCE': reference_raster,
    'METHOD': 0,
    'RESULT': '/path/to/matched.tif'
})

7.11 小结

本章详细介绍了QGIS中栅格数据处理的各种操作:

关键要点

  1. 理解栅格数据模型和数据类型
  2. 掌握各种栅格渲染方式
  3. 熟练使用栅格计算器
  4. 了解常用地形分析工具
  5. 能够进行栅格格式转换和处理
  6. 掌握栅格金字塔和性能优化

栅格数据处理是遥感和空间分析的重要组成部分。


上一章第06章 矢量数据处理

下一章第08章 坐标参考系统与投影

posted @ 2026-01-08 14:04  我才是银古  阅读(15)  评论(0)    收藏  举报