feat(step9): 新增浓度反演模块及 GUI 面板

This commit is contained in:
DXC
2026-06-09 17:55:25 +08:00
parent 4ca90b0e79
commit c3cc2ef77e
6 changed files with 1098 additions and 92 deletions

View File

@ -119,14 +119,12 @@ from src.gui.panels.step2_panel import Step2Panel
from src.gui.panels.step3_panel import Step3Panel
from src.gui.panels.step4_panel import Step4Panel
from src.gui.panels.step5_panel import Step5Panel
from src.gui.panels.step8_panel import Step8Panel # was step5_5_panel
from src.gui.panels.step6_panel import Step6Panel # was step8_panel
from src.gui.panels.step7_panel import Step7Panel # was step6_panel
from src.gui.panels.step8_non_empirical_panel import Step8NonEmpiricalPanel # was step6_5_panel
from src.gui.panels.step9_panel import Step9Panel # was step6_75_panel
from src.gui.panels.step8_qaa_panel import Step8QAAPanel # QAA 物理反演(非经验模型)
from src.gui.panels.step9_concentration_panel import Step9ConcentrationPanel # 浓度反演
from src.gui.panels.step10_panel import Step10Panel # was step7_panel
from src.gui.panels.step11_ml_panel import Step11MlPanel # ML prediction (step11_ml)
from src.gui.panels.step11_panel import Step11Panel # was step8_5_panel
from src.gui.panels.step12_panel import Step12Panel # was step8_75_panel
from src.gui.panels.step14_panel import Step14Panel # was step9_panel
from src.gui.dialogs import BandConfirmDialog, AISettingsDialog
from src.gui.panels.visualization_panel import VisualizationPanel
@ -1390,7 +1388,7 @@ class WaterQualityGUI(QMainWindow):
'step5': {
'training_spectra': '5_training_spectra/training_spectra.csv'
},
'step8': {
'step6': {
'water_indices': '6_water_quality_indices/water_quality_indices.csv'
},
'step7': {
@ -1438,8 +1436,8 @@ class WaterQualityGUI(QMainWindow):
'boundary_mask_path': ('step1', 'water_mask', 'boundary_mask_file'), # 步骤5可选水体掩膜
'glint_mask_path': ('step2', 'glint_mask', 'glint_mask_file') # 步骤5可选耀斑掩膜
},
'step8': {
'training_csv_path': ('step5', 'training_spectra', 'output_file') # 步骤8需要步骤5输出的训练光谱
'step6': {
'training_csv_path': ('step5', 'training_spectra', 'output_file') # 步骤6需要步骤5输出的训练光谱
},
'step7': {
'csv_path': ('step5', 'training_spectra', 'csv_file') # 步骤7需要训练光谱数据
@ -1850,7 +1848,7 @@ class WaterQualityGUI(QMainWindow):
"阶段二:样本数据准备 ": [
("step4", "4. 数据标准化处理"),
("step5", "5. 光谱特征提取"),
("step8", "6. 水质参数指数计算"),
("step6", "6. 水质参数指数计算"),
],
"阶段三:模型构建与训练": [
("step7", "7. 机器学习模型训练"),
@ -1964,19 +1962,17 @@ class WaterQualityGUI(QMainWindow):
self.step5_panel = Step5Panel()
self.step_stack.addTab(self.create_scroll_area(self.step5_panel), QIcon(self.get_icon_path("5.png")), "特征构建")
self.step8_panel = Step8Panel()
self.step_stack.addTab(self.create_scroll_area(self.step8_panel), QIcon(self.get_icon_path("5.png")), "水质指数")
self.step6_panel = Step6Panel()
self.step_stack.addTab(self.create_scroll_area(self.step6_panel), QIcon(self.get_icon_path("6.png")), "水质光谱指数计算")
self.step7_panel = Step7Panel()
self.step_stack.addTab(self.create_scroll_area(self.step7_panel), QIcon(self.get_icon_path("6.png")), "监督建模")
self.step_stack.addTab(self.create_scroll_area(self.step7_panel), QIcon(self.get_icon_path("7.png")), "监督建模")
self.step8_non_empirical_panel = Step8NonEmpiricalPanel()
self.step_stack.addTab(self.create_scroll_area(self.step8_non_empirical_panel), QIcon(self.get_icon_path("6.png")), "回归建模")
self.step_stack.tabBar().setTabVisible(7, False) # 隐藏回归建模 Tab
self.step8_qaa_panel = Step8QAAPanel()
self.step_stack.addTab(self.create_scroll_area(self.step8_qaa_panel), QIcon(self.get_icon_path("6.png")), "物理推导(非经验模型)")
self.step9_panel = Step9Panel()
self.step_stack.addTab(self.create_scroll_area(self.step9_panel), QIcon(self.get_icon_path("6.png")), "自定义回归建模")
self.step_stack.tabBar().setTabVisible(8, False) # 隐藏自定义回归建模 Tab
self.step9_concentration_panel = Step9ConcentrationPanel()
self.step_stack.addTab(self.create_scroll_area(self.step9_concentration_panel), QIcon(self.get_icon_path("6.png")), "浓度反演")
self.step10_panel = Step10Panel()
self.step_stack.addTab(self.create_scroll_area(self.step10_panel), QIcon(self.get_icon_path("7.png")), "采样点布设")
@ -1984,14 +1980,6 @@ class WaterQualityGUI(QMainWindow):
self.step11_ml_panel = Step11MlPanel() # ML prediction panel (step11_ml)
self.step_stack.addTab(self.create_scroll_area(self.step11_ml_panel), QIcon(self.get_icon_path("8.png")), "监督预测")
self.step11_panel = Step11Panel()
self.step_stack.addTab(self.create_scroll_area(self.step11_panel), QIcon(self.get_icon_path("8.png")), "回归预测")
self.step_stack.tabBar().setTabVisible(11, False) # 隐藏回归预测 Tab
self.step12_panel = Step12Panel()
self.step_stack.addTab(self.create_scroll_area(self.step12_panel), QIcon(self.get_icon_path("8.png")), "自定义回归预测")
self.step_stack.tabBar().setTabVisible(12, False) # 隐藏自定义回归预测 Tab
self.step14_panel = Step14Panel()
self.step_stack.addTab(self.create_scroll_area(self.step14_panel), QIcon(self.get_icon_path("10.png")), "专题图生成")
@ -2143,7 +2131,7 @@ class WaterQualityGUI(QMainWindow):
'step3': 2,
'step4': 3,
'step5': 4,
'step8': 5,
'step6': 5,
'step7': 6,
'step8_non_empirical_modeling': 7,
'step9': 8,
@ -2174,7 +2162,7 @@ class WaterQualityGUI(QMainWindow):
2: 'step3',
3: 'step4',
4: 'step5',
5: 'step8',
5: 'step6',
6: 'step7',
7: 'step8_non_empirical_modeling',
8: 'step9',
@ -2219,44 +2207,36 @@ class WaterQualityGUI(QMainWindow):
elif index == 4:
self.step5_panel.update_from_config(work_dir=self.work_dir, pipeline=self.pipeline)
# Step8(水质指数)切换时自动填充输出路径
# Step6(水质光谱指数)切换时自动填充输出路径
elif index == 5:
self.step8_panel.update_from_config(work_dir=self.work_dir, pipeline=self.pipeline)
self.step6_panel.update_from_config(work_dir=self.work_dir, pipeline=self.pipeline)
# Step7监督建模切换时自动填充训练数据和输出路径
elif index == 6:
self.step7_panel.update_from_config(work_dir=self.work_dir, pipeline=self.pipeline)
# Step8非经验建模切换时自动填充训练数据和模型目录
# Step8 QAA 物理反演切换时自动填充光谱数据和输出路径
elif index == 7:
self.step8_non_empirical_panel.update_from_config(work_dir=self.work_dir, pipeline=self.pipeline)
self.step8_qaa_panel.update_from_config(work_dir=self.work_dir, pipeline=self.pipeline)
# Step9(自定义回归建模)切换时自动填充训练数据和模型目录
# Step9 浓度反演切换时自动填充 QAA 结果和输出路径
elif index == 8:
self.step9_panel.update_from_config(work_dir=self.work_dir, pipeline=self.pipeline)
self.step9_concentration_panel.update_from_config(work_dir=self.work_dir, pipeline=self.pipeline)
# Step10采样点布设切换时自动填充掩膜和输出路径
elif index == 9:
self.step10_panel.update_from_config(work_dir=self.work_dir, pipeline=self.pipeline)
# Step8(机器学习预测)切换时自动填充采样光谱和模型目录
# Step11(机器学习预测)切换时自动填充采样光谱和模型目录
elif index == 10:
self.step11_ml_panel.update_from_config(work_dir=self.work_dir, pipeline=self.pipeline)
# Step11回归预测切换时自动填充采样光谱和回归模型目录
elif index == 11:
self.step11_panel.update_from_config(work_dir=self.work_dir, pipeline=self.pipeline)
# Step12自定义回归预测切换时自动填充采样光谱和自定义回归模型目录
elif index == 12:
self.step12_panel.update_from_config(work_dir=self.work_dir, pipeline=self.pipeline)
# Step14专题图生成切换时自动填充预测结果目录
elif index == 13:
elif index == 11:
self.step14_panel.update_from_config(work_dir=self.work_dir, pipeline=self.pipeline)
# 可视化分析面板切换时自动推断图像目录并加载目录树
elif index == 14:
elif index == 12:
self.viz_panel.update_from_config(work_dir=self.work_dir, pipeline=self.pipeline)
def apply_stylesheet(self):
@ -2300,20 +2280,14 @@ class WaterQualityGUI(QMainWindow):
self.step4_panel.set_config(config['step4'])
if 'step5' in config:
self.step5_panel.set_config(config['step5'])
if 'step8' in config:
self.step8_panel.set_config(config['step8'])
if 'step6' in config:
self.step6_panel.set_config(config['step6'])
if 'step7' in config:
self.step7_panel.set_config(config['step7'])
if 'step8_non_empirical_modeling' in config:
self.step8_non_empirical_panel.set_config(config['step8_non_empirical_modeling'])
if 'step9' in config:
self.step9_panel.set_config(config['step9'])
if 'step10' in config:
self.step10_panel.set_config(config['step10'])
if 'step11_ml' in config:
self.step11_ml_panel.set_config(config['step11_ml'])
if 'step11' in config:
self.step11_panel.set_config(config['step11'])
if 'step14' in config:
self.step14_panel.set_config(config['step14'])
if 'visualization' in config:
@ -2358,13 +2332,10 @@ class WaterQualityGUI(QMainWindow):
'step3': self.step3_panel.get_config(),
'step4': self.step4_panel.get_config(),
'step5': self.step5_panel.get_config(),
'step8': self.step8_panel.get_config(),
'step6': self.step6_panel.get_config(),
'step7': self.step7_panel.get_config(),
'step8_non_empirical_modeling': self.step8_non_empirical_panel.get_config(),
'step9': self.step9_panel.get_config(),
'step10': self.step10_panel.get_config(),
'step11_ml': self.step11_ml_panel.get_config(),
'step11': self.step11_panel.get_config(),
'step14': self.step14_panel.get_config(),
'visualization': self.viz_panel.get_config(),
'report_generation': self.report_panel.get_config(),
@ -2416,14 +2387,10 @@ class WaterQualityGUI(QMainWindow):
'step3': self.step3_panel,
'step4': self.step4_panel,
'step5': self.step5_panel,
'step8': self.step8_panel,
'step6': self.step6_panel,
'step7': self.step7_panel,
'step8_non_empirical_modeling': self.step8_non_empirical_panel,
'step9': self.step9_panel,
'step10': self.step10_panel,
'step11_ml': self.step11_ml_panel,
'step11': self.step11_panel,
'step12': self.step12_panel,
'step14': self.step14_panel,
}
return panel_map.get(step_id)
@ -2518,7 +2485,7 @@ class WaterQualityGUI(QMainWindow):
'3_deglint': 'step3',
'4_processed_data': 'step4',
'5_training_spectra': 'step5',
'6_water_quality_indices': 'step8',
'6_water_quality_indices': 'step6',
'7_Supervised_Model_Training': 'step7',
'8_Regression_Modeling': 'step8_non_empirical_modeling',
'9_Custom_Regression_Modeling': 'step9',
@ -2572,7 +2539,7 @@ class WaterQualityGUI(QMainWindow):
discovered_outputs[step_id]['processed_data'] = str(file_path)
elif 'training_spectra' in file_name and step_id == 'step5':
discovered_outputs[step_id]['training_spectra'] = str(file_path)
elif 'water_quality_indices' in file_name and step_id == 'step8':
elif 'water_quality_indices' in file_name and step_id == 'step6':
discovered_outputs[step_id]['water_indices'] = str(file_path)
elif 'sampling_spectra' in file_name and step_id == 'step10':
discovered_outputs[step_id]['sampling_points'] = str(file_path)
@ -2599,7 +2566,7 @@ class WaterQualityGUI(QMainWindow):
# 首先扫描工作目录发现已有的输出文件
self.scan_work_directory_for_files(work_path)
step_order = ['step2', 'step3', 'step4', 'step5', 'step8', 'step7', 'step8_non_empirical_modeling', 'step9',
step_order = ['step2', 'step3', 'step4', 'step5', 'step6', 'step7', 'step8_non_empirical_modeling', 'step9',
'step10', 'step11_ml', 'step11', 'step12', 'step14']
filled_count = 0
@ -2622,14 +2589,10 @@ class WaterQualityGUI(QMainWindow):
('step2', self.step2_panel),
('step3', self.step3_panel),
('step5', self.step5_panel),
('step8', self.step8_panel),
('step6', self.step6_panel),
('step7', self.step7_panel),
('step8_non_empirical_modeling', self.step8_non_empirical_panel),
('step9', self.step9_panel),
('step10', self.step10_panel),
('step11_ml', self.step11_ml_panel),
('step11', self.step11_panel),
('step12', self.step12_panel),
('step14', self.step14_panel)
]
@ -2926,7 +2889,7 @@ class WaterQualityGUI(QMainWindow):
"step4", # CSV 实测数据清洗
"step5", # 实测点光谱提取(→ training_csv_path
"step7", # ML 监督建模
"step8", # 水质指数计算(辅助训练)
"step6", # 水质指数计算(辅助训练)
"step8_non_empirical_modeling", # 非经验回归建模
"step9", # 自定义回归建模
]
@ -3022,11 +2985,11 @@ class WaterQualityGUI(QMainWindow):
# 准备实际运行配置(排除未启用的步骤)
worker_config = copy.deepcopy(config)
step8_cfg = worker_config.get('step8')
if step8_cfg:
enabled = step8_cfg.pop('enabled', True)
step6_cfg = worker_config.get('step6')
if step6_cfg:
enabled = step6_cfg.pop('enabled', True)
if not enabled:
worker_config.pop('step8', None)
worker_config.pop('step6', None)
# 工作线程内创建 Pipeline避免主线程阻塞及 Qt5Agg 子线程绘图卡死
self.worker = WorkerThread(work_dir, worker_config, mode='full', skip_list=skip_list)
@ -3256,12 +3219,12 @@ class WaterQualityGUI(QMainWindow):
def update_ui_for_training_mode(self):
"""根据训练数据模式更新UI状态"""
# 需要禁用的步骤ID对应无训练数据模式下需要禁用的步骤
disabled_step_ids = ['step4', 'step5', 'step8', 'step7', 'step8_non_empirical_modeling', 'step9']
disabled_step_ids = ['step4', 'step5', 'step6', 'step7', 'step8_non_empirical_modeling', 'step9']
# 更新标签页的启用/禁用状态
step_id_to_tab = {
'step1': 0, 'step2': 1, 'step3': 2, 'step4': 3,
'step5': 4, 'step8': 5, 'step7': 6, 'step8_non_empirical_modeling': 7,
'step5': 4, 'step6': 5, 'step7': 6, 'step8_non_empirical_modeling': 7,
'step9': 8, 'step10': 9, 'step11_ml': 10, 'step11': 11,
'step12': 12, 'step14': 13, 'step9_viz': 14
}