From 0f36da742f20afd5c4501337ead1664307a81156 Mon Sep 17 00:00:00 2001 From: DXC Date: Fri, 8 May 2026 09:27:07 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A4=9A=E6=AD=A5=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E6=97=B6=E5=8F=82=E6=95=B0=E4=BC=A0=E9=80=92=E5=8F=8A?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E8=AF=BB=E5=8F=96=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../water_quality_inversion_pipeline_GUI.py | 64 +++++++++++++++++-- src/gui/core/worker_thread.py | 2 +- src/utils/extract_water_area.py | 54 +++++++++++++++- 3 files changed, 111 insertions(+), 9 deletions(-) diff --git a/src/core/water_quality_inversion_pipeline_GUI.py b/src/core/water_quality_inversion_pipeline_GUI.py index 796067a..defdcc2 100644 --- a/src/core/water_quality_inversion_pipeline_GUI.py +++ b/src/core/water_quality_inversion_pipeline_GUI.py @@ -81,8 +81,14 @@ except ImportError: print("警告: scipy未安装,0值像素插值功能可能无法正常工作") # 导入GDAL用于影像读写 try: - from osgeo import gdal + from osgeo import gdal, ogr GDAL_AVAILABLE = True + # 注册所有 GDAL/OGR 驱动,确保 ESRI Shapefile 驱动可用 + gdal.AllRegister() + ogr.RegisterAll() + # 启用 GDAL/OGR 异常,使错误以 Python 异常形式抛出(而不是静默失败) + gdal.UseExceptions() + ogr.UseExceptions() except ImportError: GDAL_AVAILABLE = False print("警告: GDAL未安装,新算法可能无法正常工作") @@ -369,7 +375,8 @@ class WaterQualityInversionPipeline: # 执行栅格化 from src.utils.extract_water_area import rasterize_shp - rasterize_shp(mask_path, shp_output_path, img_path) + safe_mask_path = os.path.abspath(mask_path).replace('\\', '/') + rasterize_shp(safe_mask_path, shp_output_path, img_path) self.water_mask_path = shp_output_path step_end_time = time.time() self._record_step_time("步骤1: 生成水域mask", step_start_time, step_end_time) @@ -1134,10 +1141,54 @@ class WaterQualityInversionPipeline: # 从shp文件创建掩膜(这种情况应该很少,因为步骤1已经统一转换为dat) try: from src.utils.extract_water_area import rasterize_shp + + # 路径标准化:转为绝对路径,统一正斜杠 + safe_shp_path = os.path.abspath(water_mask).replace('\\', '/') + print(f"[DEBUG] 标准化后的 SHP 路径: {safe_shp_path}") + + # 检查必要的伴随文件是否存在 + shp_dir = os.path.dirname(safe_shp_path) + shp_base = os.path.splitext(safe_shp_path)[0] + for ext in ['.dbf', '.shx', '.prj']: + companion = shp_base + ext + if not os.path.exists(companion): + print(f"[DEBUG] 缺失伴随文件: {companion}") + + # 检查 ESRI Shapefile 驱动是否可用 + if GDAL_AVAILABLE: + driver = ogr.GetDriverByName("ESRI Shapefile") + if driver is None: + raise RuntimeError("系统中未找到 ESRI Shapefile 驱动!请检查 GDAL 安装。") + print(f"[DEBUG] ESRI Shapefile 驱动可用: {driver.GetName()}") + + # 尝试用 ogr.Open 打开,捕获详细错误 + try: + ogr_ds = ogr.Open(safe_shp_path) + if ogr_ds is None: + # 通过 gdal.OpenEx 再试一次,获取详细原因 + ogr_ds2 = gdal.OpenEx(safe_shp_path, gdal.OF_VECTOR) + if ogr_ds2 is None: + raise RuntimeError( + f"ogr.Open 和 gdal.OpenEx 均无法打开 SHP 文件。\n" + f"可能原因:\n" + f" 1. 文件路径包含中文/特殊字符(当前路径: {safe_shp_path})\n" + f" 2. .dbf/.shx 等伴随文件缺失或损坏\n" + f" 3. GDAL 驱动未注册\n" + f"建议:将 SHP 文件复制到纯英文路径下重试" + ) + else: + print(f"[DEBUG] ogr.Open 成功打开 SHP,图层数: {ogr_ds.GetLayerCount()}") + ogr_ds = None # 仅用于诊断,不做后续处理 + except Exception as ogr_err: + raise RuntimeError( + f"OGR 打开 SHP 时出错(详细原因): {str(ogr_err)}\n" + f"文件路径: {safe_shp_path}" + ) + # 使用固定路径,避免重复转换 - shp_name = Path(water_mask).stem + shp_name = Path(safe_shp_path).stem temp_mask_path = str(self.water_mask_dir / f"water_mask_{shp_name}.dat") - + # 如果文件已存在,直接使用 if Path(temp_mask_path).exists(): print(f"使用已存在的栅格化掩膜: {temp_mask_path}") @@ -1146,10 +1197,11 @@ class WaterQualityInversionPipeline: # 需要栅格化(需要img_path) if img_path is None: raise ValueError("当water_mask为shp格式时,需要提供img_path参数用于栅格化") - rasterize_shp(water_mask, temp_mask_path, img_path) + # 传入标准化后的路径 + rasterize_shp(safe_shp_path, temp_mask_path, img_path) water_mask = temp_mask_path print(f"已将shp格式的水域掩膜栅格化为: {temp_mask_path}") - + # 读取栅格化的掩膜 if not GDAL_AVAILABLE: raise ImportError("GDAL未安装,无法读取掩膜文件") diff --git a/src/gui/core/worker_thread.py b/src/gui/core/worker_thread.py index 0ee6f90..3ac0aab 100644 --- a/src/gui/core/worker_thread.py +++ b/src/gui/core/worker_thread.py @@ -310,7 +310,7 @@ class WorkerThread(QThread): step_config.pop('prediction_csv_dir', None) step_config.pop('recursive_csv_scan', None) - if step_name in ['step2', 'step3', 'step4', 'step5', 'step7', 'step8', 'step8_5', 'step8_75']: + if step_name in ['step2', 'step3', 'step4', 'step5', 'step6', 'step7', 'step8', 'step8_5', 'step8_75']: step_config.pop('output_path', None) if step_name == 'step8_5' and 'models_dir' in step_config: diff --git a/src/utils/extract_water_area.py b/src/utils/extract_water_area.py index 05c67a3..f92537a 100644 --- a/src/utils/extract_water_area.py +++ b/src/utils/extract_water_area.py @@ -14,17 +14,67 @@ def rasterize_envi_xml(shp_filepath): @timeit def rasterize_shp(shp_filepath, raster_fn_out, img_path, NoData_value=None): + # ---------- 防御性处理:路径标准化 ---------- + shp_filepath = os.path.abspath(shp_filepath).replace('\\', '/') + print(f"[DEBUG rasterize_shp] 标准化后的 SHP 路径: {shp_filepath}") + + # 检查伴随文件完整性 + shp_base = os.path.splitext(shp_filepath)[0] + for ext in ['.dbf', '.shx', '.prj']: + companion = shp_base + ext + if os.path.exists(companion): + print(f"[DEBUG rasterize_shp] 伴随文件存在: {companion}") + else: + print(f"[WARNING rasterize_shp] 伴随文件缺失: {companion}") + + # 确保 GDAL/OGR 驱动已注册 + gdal.AllRegister() + ogr.RegisterAll() + + # 检查 ESRI Shapefile 驱动 + driver = ogr.GetDriverByName("ESRI Shapefile") + if driver is None: + raise RuntimeError( + "系统中未找到 ESRI Shapefile 驱动!请检查 GDAL 是否正确安装及是否包含 Shapefile 支持。" + ) + print(f"[DEBUG rasterize_shp] ESRI Shapefile 驱动: {driver.GetName()}") + + # 打开参考影像获取尺寸信息 dataset = gdal.Open(img_path) + if dataset is None: + raise ValueError(f"无法打开参考影像文件: {img_path}") im_width = dataset.RasterXSize im_height = dataset.RasterYSize geotransform = dataset.GetGeoTransform() imgdata_in = dataset.GetRasterBand(1).ReadAsArray() del dataset - # Open the data source and read in the extent + # ---------- 打开 SHP 文件(双重尝试获取详细错误) ---------- source_ds = gdal.OpenEx(shp_filepath, gdal.OF_VECTOR) if source_ds is None: - raise ValueError(f"无法打开shapefile: {shp_filepath}") + # gdal.OpenEx 失败,尝试 ogr.Open 获取更详细的错误信息 + try: + ogr_ds = ogr.Open(shp_filepath) + except Exception as ogr_err: + raise RuntimeError( + f"GDAL/OGR 无法打开 SHP 文件(详细原因):\n" + f" ogr.Open 抛出异常: {str(ogr_err)}\n" + f" 文件路径: {shp_filepath}\n" + f"常见原因:\n" + f" 1. 路径包含中文/空格/特殊字符(建议复制到纯英文路径下重试)\n" + f" 2. .dbf 或 .shx 伴随文件缺失或损坏\n" + f" 3. GDAL 未注册 ESRI Shapefile 驱动\n" + f" 4. 文件被其他程序锁定" + ) + if ogr_ds is None: + raise RuntimeError( + f"ogr.Open 和 gdal.OpenEx 均返回 None,无法打开 SHP 文件。\n" + f"文件路径: {shp_filepath}\n" + f"请检查:\n" + f" 1. 所有伴随文件(.dbf/.shx/.prg)是否齐全\n" + f" 2. 文件是否被其他程序占用\n" + f" 3. 路径中是否存在不支持的字符" + ) # 检查图层数量,如果有多层,指定使用第一层 layer_count = source_ds.GetLayerCount()