现在有这样一个需求,就是需要统计一下加载在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}")