如何统计QGIS里栅格图层的面积呢

现在有这样一个需求,就是需要统计一下加载在QGIS里的图层的面积,然后保存在csv里,第一列是图层名,第二列是面积,面积以平方千米计,直接在python控制台写python脚本比较方便。如下便是代码

python 复制代码
# -*- coding: utf-8 -*-
from qgis.core import QgsProject
from osgeo import gdal
import numpy as np
import processing
import csv
import os

# -------------------------------
# 设置输出 CSV 路径
# -------------------------------
output_csv = r"C:\D\tmp\tmp.csv"

# 确保目录存在
output_dir = os.path.dirname(output_csv)
if not os.path.exists(output_dir):
    try:
        os.makedirs(output_dir)
        print(f"✅ 已创建目录: {output_dir}")
    except Exception as e:
        print(f"❌ 创建目录失败: {e}")
        exit()

# -------------------------------
# 收集所有栅格图层
# -------------------------------
layers = QgsProject.instance().mapLayers().values()
raster_layers = [lyr for lyr in layers if lyr.type() == lyr.RasterLayer]

if not raster_layers:
    print("❌ 错误:没有找到任何栅格图层")
else:
    print(f"✅ 找到 {len(raster_layers)} 个栅格图层,开始处理...")

# 存储结果
results = []

# -------------------------------
# 遍历每个图层进行处理
# -------------------------------
for idx, layer in enumerate(raster_layers):
    name = layer.name()
    source = layer.source()
    print(f"\n📌 正在处理 [{idx+1}/{len(raster_layers)}]: {name}")

    # --- 1. 重投影到 EPSG:3857(内存中)
    params = {
        'INPUT': source,
        'TARGET_CRS': 'EPSG:3857',
        'OUTPUT': 'TEMPORARY_OUTPUT'
    }

    try:
        result = processing.run("gdal:warpreproject", params)
        reprojected_path = result['OUTPUT']
    except Exception as e:
        print(f"   ❌ 重投影失败: {e}")
        results.append({'name': name, 'area_km2': None})
        continue

    # --- 2. 使用 GDAL 读取数据
    ds = gdal.Open(reprojected_path)
    if ds is None:
        print(f"   ❌ 无法打开重投影数据")
        results.append({'name': name, 'area_km2': None})
        continue

    try:
        band = ds.GetRasterBand(1)
        gt = ds.GetGeoTransform()
        pixel_width = abs(gt[1])
        pixel_height = abs(gt[5])
        nodata = band.GetNoDataValue()

        data = band.ReadAsArray()
        pixel_area_m2 = pixel_width * pixel_height
        total_pixels = data.size

        # 统计有效像元
        if nodata is not None:
            valid_mask = (data != nodata) & (~np.isnan(data))
            valid_count = np.sum(valid_mask)
        else:
            valid_count = total_pixels

        # 计算面积(km²)
        total_area_km2 = (valid_count * pixel_area_m2) / 1_000_000

        print(f"   ✅ 分辨率: {pixel_width:.4f}×{pixel_height:.4f} 米, 有效像元: {valid_count:,}")
        print(f"   📊 面积: {total_area_km2:.6f} 平方公里")

        results.append({'name': name, 'area_km2': round(total_area_km2, 6)})

    except Exception as e:
        print(f"   ❌ 数据处理出错: {e}")
        results.append({'name': name, 'area_km2': None})
    finally:
        ds = None  # 释放资源

# -------------------------------
# 保存结果到 CSV
# -------------------------------
try:
    with open(output_csv, 'w', encoding='utf-8', newline='') as f:
        writer = csv.writer(f)
        writer.writerow(['图层名', '面积_平方千米'])  # 表头
        for r in results:
            area_str = f"{r['area_km2']:.6f}" if r['area_km2'] is not None else ""
            writer.writerow([r['name'], area_str])
    print(f"\n🎉 成功!结果已保存至:\n   {output_csv}")
except Exception as e:
    print(f"❌ 保存 CSV 失败: {e}")
相关推荐
kiracrimson5 分钟前
STL:List的使用和模拟实现
开发语言·c++·list
二十七日秋13 分钟前
算法刷题笔记「Day 1|四道 OJ 入门题里的深坑」
c语言·汇编·数据结构·c++·笔记·python·算法
流年如夢35 分钟前
继承与多态_继承篇
c++·继承·面向对象·c++进阶
沫璃染墨1 小时前
从零入门计算机网络系列(十):HTTP协议进阶——从资源路径解析到状态码与请求头详解
linux·运维·服务器·网络·c++·http
xiaoye-duck1 小时前
《C++ 工具库实战》高性能日志 spdlog:从基础使用到工程化封装
c++·第三方库
努力努力再努力wz1 小时前
【Lua入门系列】从 C++ 迭代器到 Lua 迭代器:一文深入理解 Lua 有状态以及无状态迭代器与泛型for、闭包、ipairs、pairs 和 next
开发语言·c++·lua
努力实干2 小时前
第二阶段 · 第 7 课:C++ 多线程与线程安全
开发语言·c++·安全
小菜要扣篮3 小时前
Ubuntu 下使用 vscode 打开 C++ 项目后,无法通过 F12 定位到定义问题解决
c++·vscode·ubuntu
wuminyu3 小时前
JVM规范学习总结:class执行性能差异
java·linux·c语言·jvm·c++
旖旎夜光3 小时前
LCR 170:交易逆序对的总数(归并排序) —— 题解
c++·学习·算法·leetcode·排序算法