From bd4263d2ca63476fde981c29ece881d9ef0df9b9 Mon Sep 17 00:00:00 2001 From: DXC Date: Tue, 16 Jun 2026 17:53:55 +0800 Subject: [PATCH] =?UTF-8?q?=E6=97=A7=20GUI=20=E5=BC=A0=E5=86=A0=E6=9D=8E?= =?UTF-8?q?=E6=88=B4=E4=BF=AE=E5=A4=8D=EF=BC=9Astep6/step8=20ML=20?= =?UTF-8?q?=E8=AE=AD=E7=BB=83=20CSV=20=E5=BC=BA=E5=88=B6=E8=AF=BB=20Step?= =?UTF-8?q?=206=20=E7=89=B9=E5=BE=81=E7=BB=93=E6=9E=9C=20+=20step3=20?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E7=AE=97=E6=B3=95=E5=88=87=E5=88=B0=20goodma?= =?UTF-8?q?n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gui/panels/step6_feature_panel.py | 40 +++++++++++++++++- src/gui/panels/step8_ml_train_panel.py | 45 ++++++++++----------- src/gui/panels/step8_non_empirical_panel.py | 22 +++++----- src/gui/water_quality_gui.py | 6 ++- 4 files changed, 77 insertions(+), 36 deletions(-) diff --git a/src/gui/panels/step6_feature_panel.py b/src/gui/panels/step6_feature_panel.py index c3e2cfe..5649f8d 100644 --- a/src/gui/panels/step6_feature_panel.py +++ b/src/gui/panels/step6_feature_panel.py @@ -199,7 +199,43 @@ class Step6FeaturePanel(QWidget): glint_path = os.path.join(self.work_dir or '', glint_path).replace('\\', '/') self.glint_mask_file.set_path(glint_path) - # 4. 自动填充输出路径(基于工作目录) + # 4. 自动填充去耀斑影像路径(上游 Step 3 的输出,修复张冠李戴) + deglint_path = None + if pipeline and hasattr(pipeline, 'step_outputs'): + step3_outputs = getattr(pipeline, 'step_outputs', {}).get('step3', {}) + deglint_path = ( + step3_outputs.get('deglint_image') + or step3_outputs.get('output_path') + or step3_outputs.get('output_file') + or step3_outputs.get('deglint_img_path') + ) + # 回退:从 step3 面板 widget 直接读取(可能是相对路径) + if not deglint_path and hasattr(main_window, 'step3_panel'): + step3_widget = getattr(main_window.step3_panel, 'output_file', None) + if step3_widget is not None and hasattr(step3_widget, 'get_path'): + deglint_path = step3_widget.get_path() or "" + # 兜底:扫描 3_deglint 目录下的 .bsq(优先 goodman,兼容 kutser/插值) + if not deglint_path and self.work_dir: + deglint_dir = resolve_subdir(self.work_dir, 'deglint') + if os.path.isdir(deglint_dir): + bsq_files = [ + f for f in os.listdir(deglint_dir) + if f.lower().endswith('.bsq') + ] + # 优先匹配 goodman(默认算法),其次按文件名排序保证稳定 + bsq_files.sort(key=lambda n: (0 if 'goodman' in n.lower() else 1, n)) + if bsq_files: + deglint_path = os.path.join(deglint_dir, bsq_files[0]).replace('\\', '/') + + if deglint_path: + # 若为相对路径,使用 work_dir 合成为绝对路径 + if not os.path.isabs(deglint_path): + deglint_path = os.path.join(self.work_dir or '', deglint_path).replace('\\', '/') + existing_deglint = self.deglint_img_file.get_path() + if not existing_deglint or not existing_deglint.strip(): + self.deglint_img_file.set_path(deglint_path) + + # 5. 自动填充输出路径(基于工作目录) if self.work_dir: output_dir = resolve_subdir(self.work_dir, 'spectral_feature') os.makedirs(output_dir, exist_ok=True) @@ -208,7 +244,7 @@ class Step6FeaturePanel(QWidget): else: self.output_file.set_path("") - # 5. 尝试从 Step5 Clean 界面读取已处理的清洗后 CSV 路径,自动填入本面板 + # 6. 尝试从 Step5 Clean 界面读取已处理的清洗后 CSV 路径,自动填入本面板 main_window = self.window() if main_window and hasattr(main_window, 'step5_clean_panel'): step5_clean_output_path = main_window.step5_clean_panel.output_file.get_path() diff --git a/src/gui/panels/step8_ml_train_panel.py b/src/gui/panels/step8_ml_train_panel.py index fca54b2..2004391 100644 --- a/src/gui/panels/step8_ml_train_panel.py +++ b/src/gui/panels/step8_ml_train_panel.py @@ -137,6 +137,15 @@ class Step8MlTrainPanel(QWidget): self.feature_start.setText("374.285004") params_layout.addRow("特征起始列:", self.feature_start) + # 特征起始列名提示:用记事本打开 training_spectra.csv 确认首个波长的精确表头 + feature_start_hint = QLabel( + "提示:请使用记事本打开 training_spectra.csv 确认首个波长的精确表头名称" + "(如 374.285 或 374.285004)并在此填入,避免因浮点精度差异导致列名匹配失败。" + ) + feature_start_hint.setWordWrap(True) + feature_start_hint.setStyleSheet("color: #666; font-size: 10px;") + params_layout.addRow(feature_start_hint) + self.cv_folds = QSpinBox() self.cv_folds.setRange(2, 10) self.cv_folds.setValue(3) @@ -357,30 +366,20 @@ class Step8MlTrainPanel(QWidget): else: self.work_dir = None - # 1. 尝试从 Step5 界面读取训练数据路径,并确保为绝对路径 - # 修复张冠李戴:原代码 main_window.step5_panel 不存在,正确属性是 step5_clean_panel + # 1. 强制读 Step 6 的 training_spectra.csv(光谱特征提取结果) + # 修复张冠李戴:原链路 STEP_DATA_SOURCE['training_spectra_csv'] → step5_clean_panel + # 错误地指向了 Step 5 的 processed_data.csv(纯清洗数据,不含光谱特征), + # 实际 ML 训练需要的特征数据来自 Step 6 的 6_Spectral_Feature_Extraction/training_spectra.csv main_window = self.window() - step5_output = get_step_output_path( - main_window, 'training_spectra_csv', work_dir=self.work_dir, - widget_attr='output_file', fallback_key='step6_feature', - ) - if step5_output: - self.training_csv_file.set_path(step5_output) - else: - # 回退:从 Step5 的 config 字典中查找可能的键名 - step5_panel = getattr(main_window, 'step5_clean_panel', None) - if step5_panel and hasattr(step5_panel, 'get_config'): - step5_cfg = step5_panel.get_config() - step5_csv = ( - step5_cfg.get('training_csv_path') - or step5_cfg.get('output_file') - or step5_cfg.get('csv_path') - or step5_cfg.get('output_csv') - ) - if step5_csv: - if not os.path.isabs(step5_csv): - step5_csv = os.path.join(self.work_dir or '', step5_csv).replace('\\', '/') - self.training_csv_file.set_path(step5_csv) + existing_training_csv = self.training_csv_file.get_path() + if not existing_training_csv or not existing_training_csv.strip(): + if self.work_dir: + step6_dir = resolve_subdir(self.work_dir, 'spectral_feature') + step6_training_csv = os.path.join( + step6_dir, 'training_spectra.csv' + ).replace('\\', '/') + if step6_training_csv: + self.training_csv_file.set_path(step6_training_csv) # 2. 自动填充输出文件路径(基于工作目录和输入文件名) # 输入是 training_spectra.csv → 输出 {work_dir}/7_Water_Quality_Indices/training_spectra_indices.csv diff --git a/src/gui/panels/step8_non_empirical_panel.py b/src/gui/panels/step8_non_empirical_panel.py index 276199f..2edfd39 100644 --- a/src/gui/panels/step8_non_empirical_panel.py +++ b/src/gui/panels/step8_non_empirical_panel.py @@ -238,15 +238,19 @@ class Step8NonEmpiricalPanel(QWidget): # 借用父组件的 window() 方法,安全绕过当前类的命名冲突 parent_widget = self.parentWidget() main_window = parent_widget.window() if parent_widget else None - # 1. 尝试从 Step5(数据清洗)读取训练光谱 CSV(修复张冠李戴:原 main_window.step5_panel 不存在) - step5_output_path = get_step_output_path( - main_window, 'training_spectra_csv', work_dir=self.work_dir, - widget_attr='output_file', fallback_key='step6_feature', - ) - if step5_output_path: - existing = self.training_csv_file.get_path() - if not existing or not existing.strip(): - self.training_csv_file.set_path(step5_output_path) + # 1. 强制读 Step 6 的 training_spectra.csv(光谱特征提取结果) + # 修复张冠李戴:原链路 STEP_DATA_SOURCE['training_spectra_csv'] → step5_clean_panel + # 错误地指向 Step 5 的 processed_data.csv(纯清洗数据,不含光谱特征), + # 实际非经验建模需要的特征数据来自 Step 6 的 6_Spectral_Feature_Extraction/training_spectra.csv + existing_csv = self.training_csv_file.get_path() + if not existing_csv or not existing_csv.strip(): + if self.work_dir: + step6_dir = resolve_subdir(self.work_dir, 'spectral_feature') + step6_training_csv = os.path.join( + step6_dir, 'training_spectra.csv' + ).replace('\\', '/') + if step6_training_csv: + self.training_csv_file.set_path(step6_training_csv) # 2. 自动填充输出目录(8_Regression_Modeling) if self.work_dir: diff --git a/src/gui/water_quality_gui.py b/src/gui/water_quality_gui.py index bcb6513..955ac89 100644 --- a/src/gui/water_quality_gui.py +++ b/src/gui/water_quality_gui.py @@ -1367,7 +1367,7 @@ class WaterQualityGUI(QMainWindow): self.step_default_outputs = { 'step1': "1_water_mask/water_mask_from_ndwi.dat", 'step2': "2_Glint_Detection/severe_glint_area.dat", - 'step3': "3_deglint/deglint_kutser.bsq", + 'step3': "3_deglint/deglint_goodman.bsq", 'step4_sampling': "4_sampling/sampling_spectra.csv", 'step5_clean': "5_Data_Cleaning/processed_data.csv", 'step6_feature': "6_Spectral_Feature_Extraction/training_spectra.csv", @@ -2361,9 +2361,11 @@ class WaterQualityGUI(QMainWindow): deglint_path = work_path / rel_path if deglint_path.exists(): return str(deglint_path) - # 还要检查插值方法生成的文件 + # 还要检查 Kutser 算法输出与插值方法生成的文件 deglint_dir = work_path / "3_deglint" if deglint_dir.exists(): + for file_path in deglint_dir.glob("deglint_*.bsq"): + return str(file_path) for file_path in deglint_dir.glob("interpolated_*.bsq"): return str(file_path) elif rel_path: