Commit Graph

86 Commits

Author SHA1 Message Date
3f023cffd4 fix: step11 移除 ProcessPoolExecutor 改用顺序生成避免 Windows spawn 死锁
问题: ProcessPoolExecutor 在 Windows spawn 模式下,每个 worker
  需重新导入 __main__ (water_quality_gui_v2.py) 及全部依赖
  (PyQt5, GDAL, rasterio...),启动极慢且极易因环境差异死锁。

修复: 改为顺序 for 循环,每个 CSV 直接在当前 WorkerThread 调用
  _process_one_map。每张图生成前发进度通知,完全透明。

时间预估: 16 块 × ~25s/块 ≈ 6-8 分钟/张,63 张 ≈ 6-8 小时。
  用户可随时看到进度,心跳线程持续保活防止超时误杀。
2026-07-08 14:18:40 +08:00
29a5aaa9ab fix: Goodman 全局裁剪反射率 ≥0,消除非水体像素的负值
问题: 光谱查看时发现起始波段和部分后续波段反射率为负值。
  物理上反射率不应为负。

根因: 之前的 np.maximum(R[water], 0) 仅裁剪了水体像素。
  非水体像素保留原始值,而大气校正在短波边缘波段
  (375-400nm) 和长波末端 (950-1000nm) 因低 SNR 常过校正
  产生负反射率。

修复: 在每个处理路径末尾添加全局 np.maximum(R, 0, out=R):
  - 行段跳跃模式: 水体校正后 + 全局裁剪
  - 全图+掩膜模式: 水体校正后 + 全局裁剪 (新增)
  - 无掩膜模式: 全局裁剪 (原有,不变)
  确保输出文件所有像素反射率 ≥ 0
2026-07-07 17:21:52 +08:00
c6e42c3d2f perf: Goodman 水体像素原地校正 + 行段跳跃大幅提速大尺度影像
核心优化 (消除 ~95% 的无效计算):

1. 原地校正 (in-place on water pixels only):
   旧: corrected = R - R_750 + A + B*diff (全图 86M 像素)
        np.where(water, corrected, R) (再分配 329MB)
   新: R[water] = R[water] - R_750[water] + A + B*diff[water]
        (仅水体像素, 零额外分配, 无 np.where)
   效果: 水体占 5% 时, 浮点运算减少 20×, 中间数组消除

2. 行段跳跃 (water row ranges):
   预计算含水行段, 纯陆地行直接跳过不做任何计算
   水域 < 50% 时自动启用 (_find_water_row_ranges)

3. SIMD 友好路径 (无掩膜时):
   np.subtract/add(..., out=R) 替代表达式
   避免临时中间数组, 利用 NumPy SIMD 向量化

预期效果 (6522×13215×150, 水体 10%):
  每波段耗时: ~62s → 估计 ~25-35s (计算部分加速 ~20×)
  IO 仍然占主导 (~15-20s 读+写 329MB)
2026-07-07 14:18:37 +08:00
d920863a0c fix: Goodman 流式处理 — 逐波段写入磁盘杜绝 OOM
问题: 6522×13215×150 大影像处理到第 142 波段时崩溃
  'Unable to allocate 329. MiB for an array'
  根因: _get_corrected_bands_gdal 将全部 150 个波段累积在
  corrected_bands 列表中 (≈46 GB),内存耗尽。

修复 (Goodman.py):
- _get_corrected_bands_gdal(): 新增 out_dataset 参数,
  流式模式下每处理完一个波段立即 WriteArray→FlushCache→del
- 新增 _get_corrected_bands_streaming(): 创建输出文件后
  调用流式处理,内存峰值 ≈ 3 波段 (NIR×2 + 当前) ≈ 1 GB
- get_corrected_bands(): output_path 已设置时自动走流式模式
- 原 _get_corrected_bands_numpy() 和 _gdal_mem() 的
  output_path=None 路径保持向后兼容

修复 (glint_removal_step.py):
- corrected_bands 为 None 时跳过 _save_bands_as_image
  (流式模式已直接写入磁盘)

性能微优化:
- corrected = R - R_750 → += self.A → += self.B*diff (原地)
- del R_640 提早释放
- WriteArray + FlushCache 确保数据及时落盘
2026-07-07 14:10:47 +08:00
2b5c77131e fix: BIP 格式兼容 — 鲁棒 HDR 查找 + find_band_number GDAL 回退
问题: 用户导入 3ref.bip 文件,step2 报 FileNotFoundError: 3ref.hdr 不存在。

根本原因: get_hdr_file_path() 只用 os.path.splitext()[0]+.hdr,
对于 3ref.bip 只查找 3ref.hdr,不兼容 3ref.bip.hdr 等其他命名规范。

修复内容:

**util.py (核心):**
- get_hdr_file_path(): 改为多候选路径查找(按优先级):
  3ref.hdr → 3ref.bip.hdr → 3ref.HDR → 3ref.bip.HDR
- find_band_number(): 三级回退 —
  1) ENVI .hdr 文件 → spectral 解析
  2) GDAL 元数据域 (ENVI/wavelength, WAVELENGTH_1..N)
  3) 线性估算 (假设 400-1000nm 或 400-2500nm)
- 新增 _read_wavelengths_from_gdal() 辅助函数

**同模式修复 (4 处):**
- get_spectral.py: get_hdr_file_path() 多候选
- get_spectral-test.py: 同上
- waterindex_inversion/__init__.py: 两处 hdr 构造均改为多候选
- sampling.py: 波长读取的 hdr 查找改为多候选
2026-07-07 10:32:02 +08:00
1f6c81158b fix: 动态查找 PROJ/GDAL 路径 + Warp 1 像素浮点舍入容错
**water_quality_gui_v2.py:**
- 废弃硬编码 conda_env 路径
- 新增 _find_and_set_gdal_env(): 基于 sys.prefix 自动推断
  Library/share/proj 和 Library/share/gdal,验证 proj.db 存在后
  强设 PROJ_LIB 和 GDAL_DATA 环境变量
- 兼容 Windows (Library/share/...) 和 Linux/Mac (share/...) 路径

**preview_generator.py _warp_mask_to_image():**
- 尺寸验证从严格相等改为 ±2 像素容差
- 新增 _snap_array_to_shape(): warp 输出与 target_shape
  相差 ≤2px 时自动 slice(截断)或 pad(填充),不再回退到盲读模式
- 解决坐标系转换浮点舍入导致的 1048x522 vs 1047x521 问题
2026-07-07 10:01:31 +08:00
826f110894 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) 使用勾股定理
  正确计算旋转影像的像素分辨率
2026-07-07 09:10:40 +08:00
c46f78e69d fix: 补齐缺失的 handler 文件 + IDW 插值退化检测 + V1 代码归档 2026-07-06 15:57:29 +08:00
1824d62d10 格式统一 2026-07-01 15:12:25 +08:00
1611001a72 格式统一 2026-07-01 13:19:46 +08:00
8de73db80e 格式统一 2026-07-01 11:32:32 +08:00
a3c20d3e49 格式统一 2026-07-01 09:57:27 +08:00
9e433395f4 feat: 波长偏移修正 + 项目架构文档
- BandMathCalculator 支持 wavelength_offset 参数,公式波长统一加减偏移后匹配传感器波段
- WaterQualityIndexCalculator 全链传递偏移量 (band_math → calculate_one → calculate_many)
- WaterIndexCsvProcessor / Step7Handler / DataPreparationStep 传播偏移参数
- Step7/Step10 面板新增 QDoubleSpinBox 波长偏移控件 (±200nm, 默认0)
- 偏移控件去除单位后缀,避免编辑时需手动移动光标
- 新增 ARCHITECTURE.md 完整项目架构文档
2026-06-30 13:13:38 +08:00
48d17ef0ca fix: 全局UX修复与Step4交互可视化重构
=== 自动填入过于激进(幽灵路径级联)===
- 所有面板 update_from_config 移除 os.makedirs(),目录创建留给 pipeline 执行
- 输出路径仅 widget 为空时填入默认值,不覆盖用户已选
- 输入路径从上游读取后添加 os.path.exists() 检查,阻断幽灵路径级联
- panel_factory._replay_live_panel_inputs 广播前校验文件确实存在
- step10 update_from_config 添加 os.path.isfile() 存在性检查
- 清理 step8/9/11 中冗余局部 import os(修复 UnboundLocalError)

=== 输出目录缺失 ===
- step7 新增 output_file FileSelectWidget,默认路径 7_Water_Quality_Indices/
- step9 output_file 从文件模式改为目录模式 (Directories)

=== 空目录自动创建 ===
- step12 _setup_prediction_output_dirs 移除 mkdir() 调用,改为只读日志

=== 过期依赖与缺失 import ===
- panel_registry Step10 依赖 bsq_file→sampling_csv_file(匹配 CSV 模式重构)
- step7 添加缺失的 import pandas as pd(修复 NameError)

=== 导航与 UI 一致性 ===
- water_quality_gui_v2 新增 _select_first_nav_item(),启动时默认选中第一项
- step1 输出卡片对齐 step8 风格
- step8 补充缺失的样式表和统一边距

=== Step4 交互式光谱探针重构 ===
- 左右分栏 QSplitter 布局:左侧控制区 + 右侧 Matplotlib 视图
- 1x2 子图:ax1 散点图 + ax2 光谱曲线
- Hover 悬停 Annotation 显示坐标,Click 点击高亮+绘制光谱
- NavigationToolbar2QT 工具栏(保存/缩放/平移)
- 自动检测坐标列和波段列,完善异常处理
2026-06-30 09:38:27 +08:00
DXC
e337f01312 全局修正 2026-06-29 16:16:55 +08:00
DXC
43f50ec07b 测试修改 2026-06-25 15:50:02 +08:00
DXC
67aaaaa6b2 refactor(step10): 拆分 WaterIndexCsvProcessor 到独立子模块 + smoke test 2026-06-24 12:52:56 +08:00
DXC
b0ace0bde8 feat(step10): 新增 WaterIndexCsvProcessor 散点处理入口 2026-06-24 11:39:52 +08:00
DXC
b8d263e494 测试修改 2026-06-23 14:39:54 +08:00
DXC
d6c003a211 fix: Step7 UI坍塌修复+EventBus打通 + DRY抽离spxy/ks + GridSearchCV→RandomizedSearchCV + smoke test死链修复 2026-06-18 11:18:27 +08:00
DXC
3ee4e90b31 fix: step_default_outputs 支持列表候选文件名,解决动态命名导致 OutputUpdated 断链 2026-06-18 10:36:52 +08:00
DXC
3f217e95b0 fix: 修复下游面板自动填充断裂的三处根因 + 清理过时 pipeline→panel 映射 2026-06-18 10:28:14 +08:00
DXC
2261b4b30e feat: Step1~Step14 面板单步按钮 EventBus 解耦 + Handler 补全(Step8~Step14)+ 旧上帝类删除
- 9 个面板(step1~step6/step8_ml_train/step8_qaa/step9_ml_predict/step10)单步执行按钮从 parent 链上溯改为 global_event_bus.publish('RequestRunSingleStep')

- PipelineExecutor 新增 _on_request_run_single_step 订阅

- 新增 Handler: step8_ml_train / step9_ml_predict / step10_qaa_inversion / step11_concentration / step12_kriging / step13_visualization / step14_report

- 删除旧 water_quality_inversion_pipeline_GUI.py(上帝类已肢解完毕)
2026-06-18 09:19:51 +08:00
DXC
f1cc339d4a feat: Step2~Step7 Handler 批量生成 + WorkerThread 接入新调度器
- 新增 6 个 Handler:Step2GlintDetection / Step3GlintRemoval / Step4Sampling / Step5ProcessCsv / Step6ExtractSpectra / Step7CalcIndices

- 新增 register_handlers.py:register_all_handlers() 一键注册 Step1~Step7

- 更新 __init__.py:导出全部 7 个 Handler

- 重构 worker_thread.py:移除旧 WaterQualityInversionPipeline 导入,改用 PipelineScheduler + register_all_handlers

- run_single_step 改为 scheduler.run_step() 调用,保留外部模型透传逻辑
2026-06-17 18:02:31 +08:00
DXC
f6455b71ba fix: PanelFactory 信号风暴修复 + 后端上帝类肢解(BaseStepHandler/调度器/Step1打样) 2026-06-17 17:48:40 +08:00
DXC
bb5c2a50f8 refactor: 引入 EventBus 事件总线,实现各步骤面板间的去中心化自动参数传导,完成最终解耦 2026-06-17 16:27:26 +08:00
DXC
1949711cda refactor: 提取 WorkspaceManager,将文件扫描与路径业务逻辑从主 GUI 解耦 2026-06-17 15:35:02 +08:00
DXC
91881d564a fix: 修复 Step8 模型生成路径错误及特征分离未过滤坐标列导致的 0 模型 Bug
- view 层 Step8View.update_work_directory 不再生成 <work_dir>/indices/<basename>_indices.csv,改为生成标准的 <work_dir>/8_Modeling/ 模型存放目录;FileSelectWidget 标签与文件过滤器同步调整为目录语义(输出模型目录 / All Files (*.*)),消除'保存目录被存成 csv 文件'导致的 train_models 跳过判定。
2026-06-17 14:15:34 +08:00
DXC
5084f7d049 Step10 Kriging 输出路径强制 14_visualization + Step11 掩膜自动填入 2026-06-16 14:12:10 +08:00
DXC
0238aa66ab 路径归一化:统一 14 个子目录 helper 接口 + 修复 getattr 张冠李戴
新增 _step_path_resolver.py(STEP_DATA_SOURCE 映射表 + _FALLBACK_DIR_TABLE 40+ keys + resolve_subdir / get_step_output_path / resolve_step_widget 三层 API),与 pipeline.get_step_output_dir 互为表里、互不依赖。

pipeline 新增 get_step_output_dir(step_name) 唯一权威接口(class-level _STEP_OUTPUT_DIR_MAP 延迟构造 + 未知 key 回退 work_dir + 调试日志)。

全量重构 src/gui/panels/step*.py(17 个文件)

* 消除全部 os.path.join(wp, "X_subdir") 硬编码(14 个预定义子目录)

* 8 处 getattr(main_window.stepXX_panel, ...) 张冠李戴死代码全部修复(错位属性名 → 通过 STEP_DATA_SOURCE 映射到正确的 main_window 长名属性)

* 删除 step12_viz_panel.py 中 self.step11_ml_panel / step11_panel / step12_panel 死代码块

* 提示文字/标签字典/日志保留原文,仅替换实际路径计算

Smoke test:39 fallback key + 14 路径映射 + 14 step 数字 key + 17/17 panel AST 解析 + 17/17 import 全部就位。
2026-06-16 12:54:18 +08:00
DXC
03c788a16c Step6 波长读取:spectral 解析失败时增加 .hdr 文本暴力解析兜底,消灭 band_1 fallback 2026-06-16 11:07:30 +08:00
DXC
0a0ede2e02 Step3 插值:多进程内存雪崩二次补丁(mask copy + workers 上限 6) 2026-06-15 17:10:36 +08:00
DXC
60a9d7d922 Step3 插值算法 OOM 修复 + 多进程加速 + 全链路累积改动(14 文件) 2026-06-15 16:49:17 +08:00
DXC
82e0b92af6 Mega-1.1 全链路路径归一化收尾(18 文件) 2026-06-15 15:20:50 +08:00
DXC
f73a7d8999 添加公式方法 2026-06-12 16:48:20 +08:00
DXC
4c9ca2aa03 全链路路径对齐:注册表重写为字符串格式,10_sampling→4_sampling,water_quality_indices→training_spectra_indices 2026-06-12 09:59:35 +08:00
DXC
d3262ae80d Rename pipeline method names to match step numbers (Step4) 2026-06-11 14:58:39 +08:00
DXC
3c4d4081a4 refactor(gui): 重命名面板序号 step4-11,采样点布设移至 step4,ML 建模移至 step9 2026-06-11 11:13:16 +08:00
DXC
016c895803 feat(qaa): 新增 QAA 算法模块 src/core/algorithms/qaa/ 2026-06-10 17:14:08 +08:00
DXC
320f2f18f2 feat(step8): 新增水色指数反演模块 waterindex_inversion + CSV 公式驱动架构 2026-06-10 17:13:25 +08:00
DXC
cfe4c50c31 feat(step8→step9): 源头透传坐标元数据,打通空间坐标全程流 2026-06-10 09:55:28 +08:00
DXC
7571762e63 fix(step9): 保留原始坐标列至 final_concentrations.csv,防止 Step14 崩溃 2026-06-10 09:54:00 +08:00
DXC
c3cc2ef77e feat(step9): 新增浓度反演模块及 GUI 面板 2026-06-09 17:55:25 +08:00
dxc
4ca90b0e79 fix: get_spectral.py CSV列索引错误 - 跳过测量点ID列正确读取纬度(41.66°)和经度(124.22°)
input.csv列顺序: 时间,测量点,纬度,经度,水质参数...
原代码错误地将测量点ID(col0)当作纬度,纬度(col1)当作经度
修复后: lat=col1(纬度), lon=col2(经度)
修复前导致所有14815个采样点坐标转换后超出影像范围,光谱提取为0
修复后: 14815个采样点全部成功提取有效光谱(314~717)
2026-06-09 15:02:28 +08:00
dxc
2872788cc3 fix(pipeline): 移除STEP_MAP中step8→step11_ml的错误映射,避免resolve_step_id('step8')返回step11_ml 2026-06-09 13:30:52 +08:00
dxc
90ba5a5fe2 fix(pipeline): 移除未使用的WaterQualityIndexCalculator导入和实例化 2026-06-09 13:30:36 +08:00
DXC
47cbb4a013 refactor(pipeline): step8 输出文件命名统一为 training_spectra_indices.csv,produces 增加 trad_indices_dir 2026-06-09 13:18:15 +08:00
DXC
28394f2eda feat(gui): 全流程面板合并 + 一键式运行 GUI 入口集成 2026-06-09 11:30:42 +08:00
DXC
aefc9d5aac feat(pipeline): 一键式运行 - 调度引擎核心 + 预检/免检系统 + 线程桥接 2026-06-09 11:29:11 +08:00
DXC
371e7a2745 fix(PipelineRunner): 接力棒断链修复 + 依赖级联自动唤醒引擎 2026-06-09 09:07:59 +08:00