WQ_GUI 水质遥感分析系统 — 架构文档
生成日期:2026-06-30 | 分支:Mega2.2 | 步骤数:13
一、项目总览
二、核心架构机制
2.1 事件总线 (EventBus)
全局单例 global_event_bus,解耦面板之间及面板与调度器的通信:
| 事件名 |
发布者 |
订阅者 |
用途 |
RequestRunSingleStep |
各面板 run_btn |
PipelineExecutor |
单步执行 |
OutputUpdated |
面板输出变化时 |
依赖订阅者 |
自动传播输出路径 |
PipelineStarted/Finished/Stopped |
PipelineExecutor |
全局 |
流水线生命周期 |
StepCompleted |
WorkerThread |
日志/UI |
单步完成通知 |
LogMessage |
各处 |
LogManager |
日志写入 |
ProgressUpdate |
WorkerThread |
进度条 |
进度更新 |
NavigateToTab |
各处 |
QTabWidget |
标签切换 |
WorkspaceChanged |
WorkspaceManager |
全局面板 |
工作目录变更 |
2.2 面板工厂 (PanelFactory)
惰性加载机制:启动时仅创建占位 Tab,首次切换到某 Tab 时才实例化对应 Panel。
核心方法:
get_panel(step_id) → 返回面板实例(已缓存则直接返回)
_ensure_loaded(tab_index) → 实例化、包装 QScrollArea、替换占位 Tab
_replay_state_to_panel(panel) → 新加载的面板回放上游已产生的输出状态
2.3 依赖注入系统
PANEL_REGISTRY 中每个步骤定义 dependencies:
DependencySubscriber 监听 OutputUpdated 事件,自动将上游输出路径填入下游面板的对应输入控件。
_step_path_resolver.py 则通过文件系统扫描 + 目录映射表实现回退路径发现。
2.4 执行流程
三、13 个步骤详解
模块一:影像预处理(Steps 1-3)
Step 1 — 水域掩膜生成
| 项目 |
详情 |
| 面板文件 |
src/gui/panels/step1_panel.py |
| 面板类 |
Step1Panel(QWidget) |
| 后端处理器 |
src/core/handlers/step1_water_mask.py — Step1WaterMaskHandler |
| 后端算法 |
src/core/steps/water_mask_step.py — WaterMaskStep |
| UI 输入 |
mask_file(FileSelectWidget) / NDWI 阈值模式:ndwi_threshold(QLineEdit, 0.0-1.0), img_file(FileSelectWidget) |
| UI 输出 |
output_file(FileSelectWidget, mode=save), run_btn |
| 上游依赖 |
无 |
| 产出类型 |
reference_img, water_mask |
| 关键方法 |
init_ui() → update_ui_state() 切换掩膜/NDWI 策略;get_config() 返回 {mask_path, use_ndwi, ndwi_threshold, img_path, output_path} |
| 目录映射 |
→ 1_water_mask |
Step 2 — 耀斑检测
| 项目 |
详情 |
| 面板文件 |
src/gui/panels/step2_panel.py |
| 面板类 |
Step2Panel(QWidget) |
| 后端处理器 |
src/core/handlers/step2_glint_detection.py — Step2GlintDetectionHandler |
| 后端算法 |
src/core/steps/glint_detection_step.py — GlintDetectionStep |
| UI 输入 |
img_file(FileSelectWidget), water_mask_file(FileSelectWidget) |
| UI 参数 |
glint_wave(QDoubleSpinBox, 300-1000nm), method(QComboBox: Otsu/Z-Score/百分位数/IQR/自适应/多波段综合), max_area(QSpinBox), buffer_size(QSpinBox) |
| UI 输出 |
output_file(FileSelectWidget, mode=save), run_btn |
| 上游依赖 |
img_file ← step1.reference_img; water_mask_file ← step1.water_mask |
| 产出类型 |
glint_mask |
| 目录映射 |
→ 2_Glint_Detection |
Step 3 — 去耀斑
| 项目 |
详情 |
| 面板文件 |
src/gui/panels/step3_panel.py |
| 面板类 |
Step3Panel(QWidget) |
| 后端处理器 |
src/core/handlers/step3_glint_removal.py — Step3GlintRemovalHandler |
| 后端算法 |
src/core/steps/glint_removal_step.py — GlintRemovalStep |
| UI 输入 |
img_file(FileSelectWidget), water_mask_file(FileSelectWidget) |
| UI 参数 |
method(QComboBox: Goodman/Kutser/Hedley/SUGAR), 4 个 StackedWidget 参数页 + interpolate_zeros(QCheckBox), interp_method(QComboBox) |
| UI 输出 |
output_file(FileSelectWidget), run_btn |
| 上游依赖 |
img_file ← step1.reference_img; water_mask_file ← step1.water_mask |
| 产出类型 |
deglint_image |
| 特殊机制 |
img_file.textChanged → 自动调用 _update_band_ranges() 检测波段范围;method.currentIndexChanged → 切换参数 StackedWidget 页面 |
| 目录映射 |
→ 3_deglint |
模块二:特征工程与数据(Steps 4-7)
Step 4 — 采样点布局与交互式探索
| 项目 |
详情 |
| 面板文件 |
src/gui/panels/step4_sampling_panel.py |
| 面板类 |
Step4SamplingPanel(QWidget) |
| 后端处理器 |
src/core/handlers/step4_sampling.py — Step4SamplingHandler |
| UI 输入 |
deglint_img_file(FileSelectWidget), water_mask_file(FileSelectWidget) |
| UI 参数 |
interval(QSpinBox, 10-500px), sample_radius(QSpinBox, 1-50px), chunk_size(QSpinBox, 100-10000px), use_adaptive_sampling(QCheckBox) |
| UI 输出 |
output_file(FileSelectWidget), refresh_btn, run_btn |
| 可视化 |
Matplotlib 嵌入:FigureCanvasQTAgg + 隐藏 NavigationToolbar2QT,左右分栏(散点图 + 光谱曲线),自定义工具栏按钮 |
| 交互 |
_on_hover() 鼠标变小手 + 悬停标注;_on_click() 点击高亮 + 光谱绘制 + 再次点击取消选中;三按钮互斥:👆 点选探针 / ✋ 拖拽漫游 / 🔍 框选放大 |
| 上游依赖 |
deglint_img_file ← step3.deglint_image; water_mask_file ← step1.water_mask |
| 产出类型 |
sampling_points |
| 特殊机制 |
_status_timer (5000ms) 自动检测 CSV 并重渲染;draw_idle() 防 UI 卡死;rcParams 中文字体双重保障 |
| 目录映射 |
→ 4_sampling |
Step 5 — 数据清洗
| 项目 |
详情 |
| 面板文件 |
src/gui/panels/step5_clean_panel.py |
| 面板类 |
Step5CleanPanel(QWidget) |
| 后端处理器 |
src/core/handlers/step5_process_csv.py — Step5ProcessCsvHandler |
| UI 输入 |
csv_file(FileSelectWidget) |
| UI 参数 |
preview_rows_spin(QSpinBox), preview_table(QTableView + PandasTableModel), preview_status_label(QLabel) |
| UI 输出 |
output_file(FileSelectWidget, mode=save), run_btn |
| 上游依赖 |
无(独立输入源) |
| 产出类型 |
processed_data |
| 目录映射 |
→ 5_Data_Cleaning |
Step 6 — 光谱特征提取
| 项目 |
详情 |
| 面板文件 |
src/gui/panels/step6_feature_panel.py |
| 面板类 |
Step6FeaturePanel(QWidget) |
| 后端处理器 |
src/core/handlers/step6_extract_spectra.py — Step6ExtractSpectraHandler |
| UI 输入 |
deglint_img_file(FileSelectWidget), csv_file(FileSelectWidget), water_mask_file(FileSelectWidget), glint_mask_file(FileSelectWidget) |
| UI 参数 |
radius(QSpinBox, 1-50px), source_epsg(QSpinBox, default 4326) |
| UI 输出 |
output_file(FileSelectWidget), run_btn |
| 上游依赖 |
deglint_img_file ← step3; csv_file ← step5; water_mask_file ← step1; glint_mask_file ← step2 |
| 产出类型 |
output_file |
| 目录映射 |
→ 6_Spectral_Feature_Extraction |
Step 7 — 水质指数计算
| 项目 |
详情 |
| 面板文件 |
src/gui/panels/step7_inversion_panel.py |
| 面板类 |
Step7InversionPanel(QWidget) |
| 后端处理器 |
src/core/handlers/step7_calc_indices.py — Step7CalcIndicesHandler |
| UI 输入 |
formula_file(FileSelectWidget, 只读), training_data_widget(FileSelectWidget) |
| UI 参数 |
category_combo(QComboBox 按类别筛选), formula_list(NoScrollPassListWidget, checkable), 选择按钮:全选/清空/比值/浓度/重载 |
| UI 输出 |
output_file(FileSelectWidget), run_btn |
| 上游依赖 |
training_data_widget ← step6_feature.output_file |
| 产出类型 |
training_spectra_indices |
| 特殊机制 |
_load_formulas_from_csv() 从内置公式库加载;_update_formula_count() 统计选中数 |
| 目录映射 |
→ 7_Water_Quality_Indices |
模块三:模型训练与反演(Steps 8-10)
Step 8 — 机器学习建模
| 项目 |
详情 |
| 面板文件 |
src/gui/panels/step8_ml_train_panel.py |
| 面板类 |
Step8MlTrainPanel(QWidget) |
| 后端处理器 |
src/core/handlers/step8_ml_train.py — Step8MlTrainHandler |
| 后端算法 |
src/core/steps/modeling_step.py — ModelingStep |
| UI 输入 |
training_csv_file(FileSelectWidget) |
| UI 参数 |
feature_start(QComboBox), cv_folds(QSpinBox 2-10), 预处理 11 项 CheckBox(None/MMS/SS/SNV/MA/SG/MSC/D1/D2/DT/CT), 模型 15 项 CheckBox(LR/Ridge/Lasso/ElasticNet/PLS/DT/RF/ExtraTrees/XGBoost/LightGBM/CatBoost/GBDT/AdaBoost/SVR/KNN/MLP), 数据划分 3 项 CheckBox(SPXY/KS/Random) |
| UI 输出 |
output_path(FileSelectWidget, 目录模式), run_btn |
| 上游依赖 |
training_csv_file ← step7_index.training_spectra_indices |
| 产出类型 |
output_path |
| 目录映射 |
→ 8_Supervised_Model_Training |
Step 9 — 机器学习预测
| 项目 |
详情 |
| 面板文件 |
src/gui/panels/step9_ml_predict_panel.py |
| 面板类 |
Step9MlPredictPanel(QWidget) |
| 后端处理器 |
src/core/handlers/step9_ml_predict.py — Step9MlPredictHandler |
| 后端算法 |
src/core/steps/prediction_step.py — PredictionStep |
| UI 输入 |
sampling_csv_file(FileSelectWidget), models_dir_file(FileSelectWidget, 目录) |
| UI 参数 |
模型来源:use_trained_model/use_external_model(QRadioButton), 外部模型 model_list(QListWidget, checkable), metric(QComboBox: R²/RMSE/MAE), prediction_column(QLineEdit) |
| UI 输出 |
output_file(FileSelectWidget, 目录), run_btn |
| 上游依赖 |
models_dir_file ← step8_ml_train.output_path |
| 产出类型 |
output_file |
| 目录映射 |
→ 9_ML_Prediction |
Step 10 — 水色指数反演
| 项目 |
详情 |
| 面板文件 |
src/gui/panels/step10_watercolor_panel.py |
| 面板类 |
Step10WatercolorPanel(QWidget) |
| 后端处理器 |
src/core/handlers/step10_qaa_inversion.py — Step10QaaInversionHandler |
| 后端算法 |
src/core/algorithms/waterindex_inversion.py — WaterIndexCsvProcessor |
| UI 输入 |
formula_file(FileSelectWidget, 只读), sampling_csv_file(FileSelectWidget) |
| UI 参数 |
category_combo(QComboBox 按水质类别筛选), formula_list(NoScrollPassListWidget, checkable), 全选/清空/比值/浓度按钮 |
| UI 输出 |
output_dir(FileSelectWidget, 目录), progress_bar(QProgressBar), progress_label(QLabel), run_btn |
| 上游依赖 |
sampling_csv_file ← step4_sampling.sampling_points |
| 产出类型 |
output_dir |
| 特殊机制 |
内嵌 WaterIndexWorker(QThread) 后台处理 CSV |
| 目录映射 |
→ 10_WaterIndex_CSV |
模块四:制图与成果汇编(Steps 11-13)
Step 11 — 专题图生成
| 项目 |
详情 |
| 面板文件 |
src/gui/panels/step11_map_panel.py |
| 面板类 |
Step11MapPanel(QWidget) |
| 后端处理器 |
src/core/handlers/step11_concentration.py — Step11ConcentrationHandler |
| 后端算法 |
CSV 模式: src/core/steps/mapping_step.py — MappingStep.generate_distribution_map();GeoTIFF 模式: src/postprocessing/map.py — ContentMapper.visualize_raster() |
| UI 输入 |
render_mode_combo(QComboBox: CSV插值/GeoTIFF栅格), batch_mode_combo(QComboBox: 单个文件/文件夹批量), prediction_csv_file(FileSelectWidget), geotiff_file(FileSelectWidget), boundary_file(FileSelectWidget: *.shp) |
| UI 参数 |
resolution(QDoubleSpinBox, 1-1000), input_crs/output_crs(QLineEdit, EPSG:32651), show_points(QCheckBox), use_diffusion(QCheckBox) |
| UI 输出 |
output_dir(FileSelectWidget), progress_bar(QProgressBar), run_button |
| 上游依赖 |
prediction_csv_dir_edit ← step9; geotiff_dir_edit ← step10; boundary_file ← step1.water_mask |
| 特殊机制 |
两个后台线程:Step11MapBatchThread(CSV) / Step11GeoTIFFBatchThread(GeoTIFF) |
| 目录映射 |
→ 14_visualization |
Step 12 — 可视化
| 项目 |
详情 |
| 面板文件 |
src/gui/panels/step12_viz_panel.py |
| 面板类 |
Step12VizPanel(QWidget) |
| 后端算法 |
src/postprocessing/visualization_reports.py — WaterQualityVisualization; src/core/visualization/scatter_plot.py; src/postprocessing/point_map.py — SamplingPointMap |
| UI 输入 |
work_dir_edit(QLineEdit), img_dir_edit(QLineEdit) |
| UI 参数 |
6 个 QCheckBox: gen_scatter(模型评估散点图), gen_spectrum(光谱曲线), gen_boxplots(统计图), gen_mask_glint(掩膜缩略图), gen_sampling_map(采样点地图), gen_distribution_map(空间分布图) |
| UI 输出 |
gen_all_btn(QPushButton), scan_btn(QPushButton), ImageCategoryTree(QTreeWidget), ImageViewerWidget(带缩放/平移/保存), 筛选: view_mode_cb + chart_filter_cb |
| 上游依赖 |
无(文件系统自动扫描) |
| 产出类型 |
多种图表 PNG |
| 特殊机制 |
VisualizationWorkerThread(QThread) 后台批量生成;ImageCategoryTree 三视图模式(按水质参数/图表类型/物理文件夹) |
Step 13 — 报告生成
| 项目 |
详情 |
| 面板文件 |
src/gui/panels/step13_report_panel.py |
| 面板类 |
Step13ReportPanel(QWidget) |
| 后端算法 |
src/postprocessing/report_word.py — WaterQualityReportGenerator + ReportGenerationConfig |
| UI 输入 |
work_dir_edit(QLineEdit, 只读), output_dir_edit(QLineEdit + 浏览) |
| UI 参数 |
report_title_edit(QLineEdit), enable_ai_cb(QCheckBox), AI 设置按钮 → AISettingsDialog |
| UI 输出 |
progress_label(QLabel), progress_bar(QProgressBar), generate_btn(QPushButton) |
| 上游依赖 |
无(但需要 main_window 在构造时注入) |
| 产出类型 |
Word 报告 (.docx) |
| 特殊机制 |
ReportWorkerThread(QThread) 后台生成;AI 分析可选(需配置 API Key) |
| 目录映射 |
→ reports |
四、步骤间数据流转图
五、自定义组件
5.1 文件选择控件
FileSelectWidget (src/gui/components/custom_widgets.py)
| 模式 |
行为 |
mode="open" |
QFileDialog.getOpenFileName() — 选择已存在文件 |
mode="save" |
QFileDialog.getSaveFileName() — 选择保存路径 |
mode="dir" |
QFileDialog.getExistingDirectory() — 选择目录 |
关键方法:get_path(), set_path(path), set_read_only(bool), line_edit.textChanged 信号
5.2 路径解析器
_step_path_resolver.py — 所有 13 个 Panel 统一通过 from src.gui.panels._step_path_resolver import ... 导入
| 函数 |
用途 |
resolve_subdir(work_dir, subdir_key) |
步骤名 → 实际子目录路径 |
scan_work_dir_for_input(work_dir, output_type) |
文件系统扫描发现上游输出 |
resolve_step_widget(main_window, step_key, widget_attr) |
通过 panel_factory 定位上游控件 |
get_step_output_path(main_window, step_key, work_dir, widget_attr, fallback_key) |
获取上游输出路径(含回退) |
5.3 全局样式
ModernStylesheet (src/gui/styles.py) — 提供 get_button_stylesheet('normal'|'primary')
六、关键设计模式
| 模式 |
位置 |
说明 |
| 惰性加载 |
PanelFactory |
Tab 切换时才实例化 Panel,降低启动时间 |
| 事件总线 |
EventBus |
Panel ↔ PipelineExecutor 解耦通信 |
| 依赖注入 |
DependencySubscriber + PANEL_REGISTRY |
上游输出自动填入下游输入 |
| 文件系统回退 |
_step_path_resolver |
当依赖注入失败时,扫描实际文件系统 |
| 独立运行 |
每个 Panel 的 run_btn |
不依赖全流水线,可单独执行 |
| 后台线程 |
WorkerThread / 各 Panel 内嵌 QThread |
长时间计算不阻塞 GUI |
| 交互模式 |
Step4 三按钮互斥 |
点选探针 / 拖拽漫游 / 框选放大 |
七、文件清单
前端面板(13 个)
| 文件 |
类 |
Step ID |
step1_panel.py |
Step1Panel |
step1 |
step2_panel.py |
Step2Panel |
step2 |
step3_panel.py |
Step3Panel |
step3 |
step4_sampling_panel.py |
Step4SamplingPanel |
step4_sampling |
step5_clean_panel.py |
Step5CleanPanel |
step5_clean |
step6_feature_panel.py |
Step6FeaturePanel |
step6_feature |
step7_inversion_panel.py |
Step7InversionPanel |
step7_index |
step8_ml_train_panel.py |
Step8MlTrainPanel |
step8_ml_train |
step9_ml_predict_panel.py |
Step9MlPredictPanel |
step9_ml_predict |
step10_watercolor_panel.py |
Step10WatercolorPanel |
step10_watercolor |
step11_map_panel.py |
Step11MapPanel |
step11_map |
step12_viz_panel.py |
Step12VizPanel |
step12_viz |
step13_report_panel.py |
Step13ReportPanel |
step13_report |
后端核心(14 个 Handler)
| 文件 |
类 |
Step Key |
handlers/step1_water_mask.py |
Step1WaterMaskHandler |
step1 |
handlers/step2_glint_detection.py |
Step2GlintDetectionHandler |
step2 |
handlers/step3_glint_removal.py |
Step3GlintRemovalHandler |
step3 |
handlers/step4_sampling.py |
Step4SamplingHandler |
step4_sampling |
handlers/step5_process_csv.py |
Step5ProcessCsvHandler |
step5_clean |
handlers/step6_extract_spectra.py |
Step6ExtractSpectraHandler |
step6_feature |
handlers/step7_calc_indices.py |
Step7CalcIndicesHandler |
step7_index |
handlers/step8_ml_train.py |
Step8MlTrainHandler |
step8_ml_train |
handlers/step9_ml_predict.py |
Step9MlPredictHandler |
step9_ml_predict |
handlers/step10_qaa_inversion.py |
Step10QaaInversionHandler |
step10_qaa_inversion |
handlers/step11_concentration.py |
Step11ConcentrationHandler |
step11_concentration |
handlers/step12_kriging.py |
Step12KrigingHandler |
step12_kriging |
handlers/step13_visualization.py |
Step13VisualizationHandler |
step13_visualization |
handlers/step14_report.py |
Step14ReportHandler |
step14_report |
注:Handler 注册有 14 个(step1-14),对应 Panel 有 13 个(step1-13)。Step12 的 Handler 处理克里金插值,Step13 的 Handler 处理可视化,Step14 的 Handler 处理报告。
八、审计修复记录(2026-06-30)
本轮已修复的全部问题:
| # |
严重度 |
文件 |
问题 |
修复 |
| 1 |
🔴 |
step11_map_panel.py:652 |
mapper 在 import 之前引用 |
移动 import 至引用上方 |
| 2 |
🟡 |
step12_viz_panel.py:1719 |
get_panel('step1_mask') key 不存在 |
改为 'step1' |
| 3 |
🟡 |
step3_panel.py:384 |
currentData() 返回 None |
改为 currentText() |
| 4 |
🟡 |
step5_clean_panel.py:228/253 |
PandasTableModel 从 v1 入口导入 |
改为 src.gui.components.data_models |
| 5 |
🟡 |
step3_panel.py:271 |
InteractiveViewerDialog 同上 |
改为 src.gui.components.chart_dialogs |
| 6 |
🟢 |
step7_inversion_panel.py:9 |
import csv 未使用 |
移除 |
| 7 |
🟢 |
step5_clean_panel.py:167 |
死方法 _add_row_with_fixed_label |
标注废弃 |
| 8 |
🟢 |
全部 12 个 Panel |
_step_path_resolver 导入风格不一致 |
统一为 from src.gui.panels._step_path_resolver import ...,移除 _HERE/sys.path hack |