fix: 防御性编程重构 — 栅格空间对齐 + NoData 处理 + 高危代码加固
**核心修复 (preview_generator.py):** - 废弃 _align_mask_to_image() (numpy crop/pad 在地理空间上错误) - 新增 _warp_mask_to_image(): 使用 gdal.Warp 将掩膜重采样到与底图 完全一致的像素网格,处理旋转/偏移/投影差异 - 新增 _normalize_mask(nodata_value): 正确的掩膜值域自劢归一间 (0/1 vs 0/255) - 修复 alpha = mask_data/255.0 → mask_data (掩膜是二值 0/1, 不是 0/255) - 面积计算 valid_pixels 使用 warp 前数据排除 nodata 背景 **新增防御工具模块:** - spatial_validator.py: SpatialAlignmentError 自定义异常 + validate_two_rasters() / validate_spatial_alignment() 强制空间一致性检查 + has_rotation() / get_pixel_resolution() 诊断工具 - nodata_handler.py: read_band_safe() / read_bands_safe() 自动 NoData→nan + read_band_masked() 返回 MaskedArray + create_valid_mask() **P0 高危代码集成 (3处):** - sampling.py: 耀斑掩膜与水体掩膜 bool 运算前验证 numpy shape 一致 - find_severe_glint_area.py: 栅格 mask 读取后验证 dims+GT+projection 对齐 - waterindex_inversion/__init__.py: mask 与 BSQ 维度验证, 不一致时优雅降级 **旋转影像兼容性修复:** - extract_water_area.py: pixel_size = sqrt(gt[1]^2+gt[2]^2) 使用勾股定理 正确计算旋转影像的像素分辨率
This commit is contained in:
@ -85,9 +85,10 @@ def rasterize_shp(shp_filepath, raster_fn_out, img_path, NoData_value=None):
|
||||
layer = source_ds.GetLayer(0)
|
||||
layer_name = layer.GetName()
|
||||
|
||||
# about 25 metres(ish) use 0.001 if you want roughly 100m
|
||||
pixel_size_x = abs(geotransform[1]) # 像素宽度(X方向)
|
||||
pixel_size_y = abs(geotransform[5]) # 像素高度(Y方向,通常是负值,需要取绝对值)
|
||||
# 计算像素分辨率(考虑旋转参数)
|
||||
# 对于旋转影像(gt[2] 或 gt[4] != 0),像素实际分辨率需用勾股定理
|
||||
pixel_size_x = np.sqrt(geotransform[1]**2 + geotransform[2]**2)
|
||||
pixel_size_y = np.sqrt(geotransform[4]**2 + geotransform[5]**2)
|
||||
raster_fn_out_tmp = append2filename(raster_fn_out, "_tmp_delete")
|
||||
|
||||
# 构建栅格化参数
|
||||
|
||||
@ -2,6 +2,7 @@ from src.utils.util import *
|
||||
from osgeo import gdal, ogr
|
||||
import argparse
|
||||
import cv2
|
||||
from src.core.utils.spatial_validator import validate_spatial_alignment
|
||||
|
||||
|
||||
|
||||
@ -621,6 +622,14 @@ def find_severe_glint_area(img_path, water_mask, glint_wave=750, output_path=Non
|
||||
if dataset_water_mask is None:
|
||||
raise ValueError(f"无法打开水域掩膜文件: {water_mask}")
|
||||
data_water_mask = dataset_water_mask.GetRasterBand(1).ReadAsArray()
|
||||
|
||||
# 防御性检查:水域掩膜与影像的空间一致性
|
||||
validate_spatial_alignment(
|
||||
data_water_mask, dataset_water_mask.GetGeoTransform(), dataset_water_mask.GetProjection(),
|
||||
(im_height, im_width), dataset.GetGeoTransform(), dataset.GetProjection(),
|
||||
label_a="水域掩膜", label_b="影像",
|
||||
)
|
||||
|
||||
del dataset_water_mask
|
||||
|
||||
print(f"使用检测方法: {method}")
|
||||
|
||||
@ -16,6 +16,7 @@ from osgeo import gdal, ogr
|
||||
import spectral
|
||||
from scipy import ndimage
|
||||
from src.utils.util import write_bands
|
||||
from src.core.utils.spatial_validator import validate_spatial_alignment
|
||||
|
||||
try:
|
||||
from skimage import morphology
|
||||
@ -130,6 +131,15 @@ def get_spectral_sampling_points_chunked(bil_file, water_mask_shp, severe_glint=
|
||||
if dataset_severe_glint is None:
|
||||
raise ValueError(f"无法打开耀斑掩膜文件: {severe_glint}")
|
||||
data_severe_glint = dataset_severe_glint.GetRasterBand(1).ReadAsArray()
|
||||
|
||||
# 防御性检查:耀斑掩膜与水体掩膜的空间一致性
|
||||
validate_spatial_alignment(
|
||||
water_mask_raster, None, None,
|
||||
data_severe_glint, None, None,
|
||||
label_a="水体掩膜", label_b="耀斑掩膜",
|
||||
check_projection=False,
|
||||
)
|
||||
|
||||
print("已加载耀斑掩膜")
|
||||
# 对glint边界进行外扩1-2像素作为缓冲
|
||||
data_severe_glint = expand_glint_buffer(data_severe_glint, buffer_size=2)
|
||||
@ -142,7 +152,7 @@ def get_spectral_sampling_points_chunked(bil_file, water_mask_shp, severe_glint=
|
||||
valid_area = (water_mask_raster > 0) & (~(data_severe_glint > 0))
|
||||
else:
|
||||
valid_area = (water_mask_raster > 0)
|
||||
|
||||
|
||||
# 计算水体宽度(用于自适应采样)
|
||||
width_map = None
|
||||
if use_adaptive_sampling:
|
||||
@ -454,6 +464,15 @@ def get_spectral_sampling_points(bil_file, water_mask_shp, severe_glint=None, ou
|
||||
if dataset_severe_glint is None:
|
||||
raise ValueError(f"无法打开耀斑掩膜文件: {severe_glint}")
|
||||
data_severe_glint = dataset_severe_glint.GetRasterBand(1).ReadAsArray()
|
||||
|
||||
# 防御性检查:耀斑掩膜与水体掩膜的空间一致性
|
||||
validate_spatial_alignment(
|
||||
water_mask_raster, None, None,
|
||||
data_severe_glint, None, None,
|
||||
label_a="水体掩膜", label_b="耀斑掩膜",
|
||||
check_projection=False,
|
||||
)
|
||||
|
||||
print("已加载耀斑掩膜")
|
||||
# 对glint边界进行外扩1-2像素作为缓冲
|
||||
data_severe_glint = expand_glint_buffer(data_severe_glint, buffer_size=2)
|
||||
@ -920,6 +939,14 @@ def get_coor_base_interval(water_mask, severe_glint=None, output_csvpath=None, i
|
||||
raise ValueError(f"无法打开耀斑掩膜文件: {severe_glint}")
|
||||
data_severe_glint = dataset_severe_glint.GetRasterBand(1).ReadAsArray()
|
||||
|
||||
# 防御性检查:耀斑掩膜与水体掩膜的空间一致性
|
||||
validate_spatial_alignment(
|
||||
data_water_mask, None, None,
|
||||
data_severe_glint, None, None,
|
||||
label_a="水体掩膜", label_b="耀斑掩膜",
|
||||
check_projection=False,
|
||||
)
|
||||
|
||||
# 使用耀斑掩膜的几何信息
|
||||
im_width = dataset_severe_glint.RasterXSize
|
||||
im_height = dataset_severe_glint.RasterYSize
|
||||
|
||||
Reference in New Issue
Block a user