自动填写路径
This commit is contained in:
@ -2284,11 +2284,15 @@ class WaterQualityInversionPipeline:
|
||||
else:
|
||||
raise ValueError("请先执行步骤6: 训练机器学习模型,或提供models_dir参数")
|
||||
|
||||
# 检查prediction_dir中是否已有预测结果文件
|
||||
# 设置机器学习预测输出子目录
|
||||
ml_prediction_dir = self.prediction_dir / "Machine_Learning_Prediction"
|
||||
ml_prediction_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# 检查Machine_Learning_Prediction子目录中是否已有预测结果文件
|
||||
prediction_files = {}
|
||||
if self.prediction_dir.exists():
|
||||
if ml_prediction_dir.exists():
|
||||
# 查找所有CSV预测结果文件
|
||||
csv_files = list(self.prediction_dir.glob('*.csv'))
|
||||
csv_files = list(ml_prediction_dir.glob('*.csv'))
|
||||
if csv_files:
|
||||
# 从文件名提取目标参数名(假设文件名为"target_name_prediction.csv")
|
||||
for csv_file in csv_files:
|
||||
@ -2312,11 +2316,11 @@ class WaterQualityInversionPipeline:
|
||||
# 检查是否所有目标参数都有预测文件
|
||||
missing_targets = [t for t in target_folders if t not in prediction_files]
|
||||
if not missing_targets:
|
||||
print(f"检测到已存在的预测结果文件,直接使用: {self.prediction_dir}")
|
||||
print(f"检测到已存在的预测结果文件,直接使用: {ml_prediction_dir}")
|
||||
print(f"找到 {len(prediction_files)} 个预测结果文件")
|
||||
step_end_time = time.time()
|
||||
self._record_step_time("步骤8: 预测水质参数", step_start_time, step_end_time, status="skipped")
|
||||
print(f"预测结果已设置: {self.prediction_dir}")
|
||||
print(f"预测结果已设置: {ml_prediction_dir}")
|
||||
return prediction_files
|
||||
else:
|
||||
print(f"检测到部分预测结果文件,缺少以下目标参数: {missing_targets}")
|
||||
@ -2329,7 +2333,7 @@ class WaterQualityInversionPipeline:
|
||||
all_results = inferencer.batch_inference_multi_models(
|
||||
models_root_dir=models_path,
|
||||
sampling_csv_path=sampling_csv_path,
|
||||
output_dir=str(self.prediction_dir),
|
||||
output_dir=str(ml_prediction_dir),
|
||||
metric=metric,
|
||||
prediction_column=prediction_column,
|
||||
output_format='csv'
|
||||
@ -2342,7 +2346,7 @@ class WaterQualityInversionPipeline:
|
||||
|
||||
step_end_time = time.time()
|
||||
self._record_step_time("步骤8: 预测水质参数", step_start_time, step_end_time)
|
||||
print(f"预测完成,结果保存在: {self.prediction_dir}")
|
||||
print(f"预测完成,结果保存在: {ml_prediction_dir}")
|
||||
|
||||
# 生成预测结果报告
|
||||
try:
|
||||
@ -3731,15 +3735,17 @@ class WaterQualityInversionPipeline:
|
||||
else:
|
||||
raise ValueError("请先执行步骤6.5: 非经验模型训练,或提供non_empirical_models_dir参数")
|
||||
|
||||
# 检查预测目录中是否已有预测结果文件
|
||||
prediction_files = {}
|
||||
# 设置非经验模型预测输出子目录
|
||||
if output_path is not None:
|
||||
non_empirical_prediction_dir = Path(output_path)
|
||||
else:
|
||||
# 使用和步骤8相同的prediction_dir目录,但文件名添加non_empirical_前缀
|
||||
non_empirical_prediction_dir = self.prediction_dir
|
||||
# 使用Non_Empirical_Prediction子目录
|
||||
non_empirical_prediction_dir = self.prediction_dir / "Non_Empirical_Prediction"
|
||||
non_empirical_prediction_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# 检查预测目录中是否已有预测结果文件
|
||||
prediction_files = {}
|
||||
|
||||
# 查找汇总CSV文件
|
||||
summary_path = Path(final_models_dir) / "non_empirical_models_summary.csv"
|
||||
if not summary_path.exists():
|
||||
@ -3876,9 +3882,11 @@ class WaterQualityInversionPipeline:
|
||||
else:
|
||||
raise ValueError("请先执行步骤6.75: 自定义回归分析,或提供custom_regression_dir参数")
|
||||
|
||||
# 确定输出目录
|
||||
# 设置自定义回归预测输出子目录
|
||||
if output_dir is None:
|
||||
prediction_output_dir = str(self.prediction_dir)
|
||||
custom_regression_prediction_dir = self.prediction_dir / "Custom_Regression_Prediction"
|
||||
custom_regression_prediction_dir.mkdir(parents=True, exist_ok=True)
|
||||
prediction_output_dir = str(custom_regression_prediction_dir)
|
||||
else:
|
||||
prediction_output_dir = output_dir
|
||||
|
||||
|
||||
@ -5397,10 +5397,124 @@ class WaterQualityGUI(QMainWindow):
|
||||
# 训练数据模式状态
|
||||
self.has_training_data = True # 默认有训练数据
|
||||
|
||||
# 步骤输出路径记录
|
||||
self.step_outputs = {} # 记录每个步骤的输出路径
|
||||
|
||||
# 定义步骤依赖关系和标准输出路径
|
||||
self._init_step_dependencies()
|
||||
|
||||
self.init_ui()
|
||||
self.apply_stylesheet()
|
||||
self._disable_wheel_for_all_spinboxes()
|
||||
|
||||
def _init_step_dependencies(self):
|
||||
"""初始化步骤依赖关系和标准输出路径"""
|
||||
# 定义每个步骤的标准输出路径模式(相对于工作目录)
|
||||
self.step_default_outputs = {
|
||||
'step1': {
|
||||
'water_mask_ndwi': '1_water_mask/water_mask_from_ndwi.dat',
|
||||
'water_mask_shp': '1_water_mask/water_mask_from_shp.dat',
|
||||
'hsi_preview': '1_water_mask/hsi_preview.png',
|
||||
'water_mask_overlay': '1_water_mask/water_mask_overlay.png'
|
||||
},
|
||||
'step2': {
|
||||
'glint_mask': '2_glint/severe_glint_area.dat'
|
||||
},
|
||||
'step3': {
|
||||
'deglint_kutser': '3_deglint/deglint_kutser.bsq',
|
||||
'deglint_goodman': '3_deglint/deglint_goodman.bsq',
|
||||
'deglint_hedley': '3_deglint/deglint_hedley.bsq',
|
||||
'deglint_sugar': '3_deglint/deglint_sugar.bsq',
|
||||
'deglint_interpolated': '3_deglint/interpolated_*.bsq' # * = interpolation_method
|
||||
},
|
||||
'step4': {
|
||||
'processed_data': '4_processed_data/processed_data.csv'
|
||||
},
|
||||
'step5': {
|
||||
'training_spectra': '5_training_spectra/training_spectra.csv'
|
||||
},
|
||||
'step5_5': {
|
||||
'water_indices': '6_water_quality_indices/water_quality_indices.csv'
|
||||
},
|
||||
'step6': {
|
||||
'models': '7_Supervised_Model_Training/' # 目录,包含各参数子目录
|
||||
},
|
||||
'step6_5': {
|
||||
'regression_models': '8_Regression_Modeling/' # 目录,包含各参数子目录
|
||||
},
|
||||
'step6_75': {
|
||||
'custom_regression_models': '9_Custom_Regression_Modeling/' # 目录
|
||||
},
|
||||
'step7': {
|
||||
'sampling_points': '10_sampling/sampling_spectra.csv'
|
||||
},
|
||||
'step8': {
|
||||
'predictions': '11_12_13_predictions/Machine_Learning_Prediction/' # 目录,包含机器学习预测结果
|
||||
},
|
||||
'step8_5': {
|
||||
'regression_predictions': '11_12_13_predictions/Non_Empirical_Prediction/' # 目录,包含非经验模型预测结果
|
||||
},
|
||||
'step8_75': {
|
||||
'custom_predictions': '11_12_13_predictions/Custom_Regression_Prediction/' # 目录,包含自定义回归预测结果
|
||||
},
|
||||
'step9': {
|
||||
'distribution_maps': '14_visualization/' # 目录,包含专题图
|
||||
}
|
||||
}
|
||||
|
||||
# 定义步骤间的依赖关系:{当前步骤: {输入字段: (依赖步骤, 输出类型, 面板属性名)}}
|
||||
self.step_dependencies = {
|
||||
'step2': {
|
||||
'img_path': ('step1', 'reference_img', 'img_file'), # 步骤2需要参考影像
|
||||
'water_mask_path': ('step1', 'water_mask', 'water_mask_file') # 步骤2可选水域掩膜
|
||||
},
|
||||
'step3': {
|
||||
'img_path': ('step1', 'reference_img', 'img_file'), # 步骤3需要参考影像
|
||||
'water_mask': ('step1', 'water_mask', 'water_mask_file'), # 步骤3需要水域掩膜
|
||||
},
|
||||
'step4': {
|
||||
# 步骤4主要处理CSV文件,一般不依赖前面步骤的输出
|
||||
},
|
||||
'step5': {
|
||||
'deglint_img_path': ('step3', 'deglint_image', 'deglint_img_file'), # 步骤5需要去耀斑影像
|
||||
'csv_path': ('step4', 'processed_data', 'csv_file'), # 步骤5需要处理后的CSV
|
||||
'boundary_mask_path': ('step1', 'water_mask', 'boundary_mask_file'), # 步骤5可选水体掩膜
|
||||
'glint_mask_path': ('step2', 'glint_mask', 'glint_mask_file') # 步骤5可选耀斑掩膜
|
||||
},
|
||||
'step5_5': {
|
||||
'csv_path': ('step4', 'processed_data', 'csv_file') # 步骤5.5需要处理后的CSV
|
||||
},
|
||||
'step6': {
|
||||
'csv_path': ('step5', 'training_spectra', 'csv_file') # 步骤6需要训练光谱数据
|
||||
},
|
||||
'step6_5': {
|
||||
'csv_path': ('step5', 'training_spectra', 'csv_file') # 步骤6.5需要训练光谱数据
|
||||
},
|
||||
'step6_75': {
|
||||
'csv_path': ('step5', 'training_spectra', 'csv_file') # 步骤6.75需要训练光谱数据
|
||||
},
|
||||
'step7': {
|
||||
'deglint_img_path': ('step3', 'deglint_image', 'deglint_img_file'), # 步骤7需要去耀斑影像
|
||||
'water_mask_path': ('step1', 'water_mask', 'water_mask_file'), # 步骤7需要水域掩膜
|
||||
'glint_mask_path': ('step2', 'glint_mask', 'glint_mask_file') # 步骤7可选耀斑掩膜
|
||||
},
|
||||
'step8': {
|
||||
'sampling_csv_path': ('step7', 'sampling_points', 'sampling_csv_file'), # 步骤8需要采样点
|
||||
'models_dir': ('step6', 'models', 'models_dir_file') # 步骤8需要训练好的模型
|
||||
},
|
||||
'step8_5': {
|
||||
'sampling_csv_path': ('step7', 'sampling_points', 'sampling_csv_file'), # 步骤8.5需要采样点
|
||||
'models_dir': ('step6_5', 'regression_models', 'models_dir') # 步骤8.5需要回归模型
|
||||
},
|
||||
'step8_75': {
|
||||
'sampling_csv_path': ('step7', 'sampling_points', 'sampling_csv_file'), # 步骤8.75需要采样点
|
||||
'models_dir': ('step6_75', 'custom_regression_models', 'models_dir') # 步骤8.75需要自定义回归模型
|
||||
},
|
||||
'step9': {
|
||||
'prediction_csv_path': ('step8', 'predictions', 'prediction_csv_file') # 步骤9需要预测结果CSV
|
||||
}
|
||||
}
|
||||
|
||||
def get_icon_path(self, icon_filename):
|
||||
"""
|
||||
获取图标文件的完整路径
|
||||
@ -5580,6 +5694,13 @@ class WaterQualityGUI(QMainWindow):
|
||||
open_dir_action = tools_menu.addAction("打开工作目录")
|
||||
open_dir_action.triggered.connect(self.open_work_directory)
|
||||
|
||||
tools_menu.addSeparator()
|
||||
|
||||
# 添加自动填充功能
|
||||
auto_fill_action = tools_menu.addAction("自动填充所有输入路径")
|
||||
auto_fill_action.triggered.connect(self.auto_populate_all_steps)
|
||||
auto_fill_action.setToolTip("根据工作目录中的文件自动填充各步骤的输入路径")
|
||||
|
||||
# 在工具菜单中添加训练数据模式切换按钮
|
||||
self.training_mode_action = tools_menu.addAction("有训练数据模式")
|
||||
self.training_mode_action.setCheckable(True)
|
||||
@ -5719,7 +5840,7 @@ class WaterQualityGUI(QMainWindow):
|
||||
],
|
||||
"阶段四:预测与成果输出 ": [
|
||||
("step7", "10. 采样点布设"),
|
||||
("step8", "11. 机器学习学习预测"),
|
||||
("step8", "11. 机器学习预测"),
|
||||
("step8_5", "12. 回归预测"),
|
||||
("step8_75", "13. 自定义回归预测"),
|
||||
("step9", "14. 专题图生成"),
|
||||
@ -5958,6 +6079,9 @@ class WaterQualityGUI(QMainWindow):
|
||||
# 初始化训练数据模式UI状态
|
||||
self.update_ui_for_training_mode()
|
||||
|
||||
# 为步骤面板添加自动填充功能
|
||||
self.add_auto_fill_buttons_to_panels()
|
||||
|
||||
# 显示pipeline状态
|
||||
self.show_pipeline_status_on_startup()
|
||||
|
||||
@ -6007,6 +6131,8 @@ class WaterQualityGUI(QMainWindow):
|
||||
if item_data in step_id_to_tab:
|
||||
tab_index = step_id_to_tab[item_data]
|
||||
self.step_stack.setCurrentIndex(tab_index)
|
||||
# 切换到步骤时自动填充输入路径
|
||||
self.auto_populate_step_inputs(item_data)
|
||||
|
||||
def on_tab_changed(self, index):
|
||||
"""Tab页面切换时同步更新左侧步骤列表"""
|
||||
@ -6162,6 +6288,289 @@ class WaterQualityGUI(QMainWindow):
|
||||
}
|
||||
return config
|
||||
|
||||
def auto_populate_step_inputs(self, step_id):
|
||||
"""自动填充指定步骤的输入路径,返回填充的字段数量"""
|
||||
if step_id not in self.step_dependencies:
|
||||
return 0 # 该步骤没有依赖关系
|
||||
|
||||
# 获取对应的面板
|
||||
panel = self.get_step_panel(step_id)
|
||||
if not panel:
|
||||
return 0
|
||||
|
||||
work_dir = getattr(self, 'work_dir', './work_dir')
|
||||
work_path = Path(work_dir)
|
||||
|
||||
dependencies = self.step_dependencies[step_id]
|
||||
filled_count = 0
|
||||
|
||||
for input_field, (dep_step, output_type, panel_attr) in dependencies.items():
|
||||
# 检查面板是否有对应的属性
|
||||
if not hasattr(panel, panel_attr):
|
||||
continue
|
||||
|
||||
file_widget = getattr(panel, panel_attr)
|
||||
|
||||
# 如果输入框已经有内容,跳过自动填充
|
||||
if file_widget.get_path().strip():
|
||||
continue
|
||||
|
||||
# 查找依赖步骤的输出文件
|
||||
output_path = self.find_step_output(work_path, dep_step, output_type)
|
||||
|
||||
if output_path and Path(output_path).exists():
|
||||
file_widget.set_path(output_path)
|
||||
self.log_message(f"自动填充 {step_id}.{input_field}: {output_path}", "info")
|
||||
filled_count += 1
|
||||
|
||||
return filled_count
|
||||
|
||||
def get_step_panel(self, step_id):
|
||||
"""根据步骤ID获取对应的面板对象"""
|
||||
panel_map = {
|
||||
'step1': self.step1_panel,
|
||||
'step2': self.step2_panel,
|
||||
'step3': self.step3_panel,
|
||||
'step4': self.step4_panel,
|
||||
'step5': self.step5_panel,
|
||||
'step5_5': self.step5_5_panel,
|
||||
'step6': self.step6_panel,
|
||||
'step6_5': self.step6_5_panel,
|
||||
'step6_75': self.step6_75_panel,
|
||||
'step7': self.step7_panel,
|
||||
'step8': self.step8_panel,
|
||||
'step8_5': self.step8_5_panel,
|
||||
'step8_75': self.step8_75_panel,
|
||||
'step9': self.step9_panel,
|
||||
}
|
||||
return panel_map.get(step_id)
|
||||
|
||||
def find_step_output(self, work_path, step_id, output_type):
|
||||
"""查找指定步骤的输出文件"""
|
||||
if step_id not in self.step_default_outputs:
|
||||
return None
|
||||
|
||||
step_outputs = self.step_default_outputs[step_id]
|
||||
|
||||
# 特殊处理:从step_outputs记录中查找实际输出路径
|
||||
if step_id in self.step_outputs:
|
||||
actual_outputs = self.step_outputs[step_id]
|
||||
if output_type in actual_outputs:
|
||||
return actual_outputs[output_type]
|
||||
|
||||
# 根据输出类型查找对应的文件
|
||||
if output_type == 'water_mask':
|
||||
# 水域掩膜:优先查找NDWI生成的,其次是shp生成的
|
||||
for mask_type in ['water_mask_ndwi', 'water_mask_shp']:
|
||||
if mask_type in step_outputs:
|
||||
mask_path = work_path / step_outputs[mask_type]
|
||||
if mask_path.exists():
|
||||
return str(mask_path)
|
||||
elif output_type == 'reference_img':
|
||||
# 参考影像:从step1的配置中获取用户输入的影像路径
|
||||
if hasattr(self, 'step1_panel'):
|
||||
img_path = self.step1_panel.img_file.get_path()
|
||||
if img_path and Path(img_path).exists():
|
||||
return img_path
|
||||
elif output_type == 'deglint_image':
|
||||
# 去耀斑影像:查找step3的各种去耀斑方法输出
|
||||
deglint_types = ['deglint_kutser', 'deglint_goodman', 'deglint_hedley', 'deglint_sugar']
|
||||
for deglint_type in deglint_types:
|
||||
if deglint_type in step_outputs:
|
||||
deglint_path = work_path / step_outputs[deglint_type]
|
||||
if deglint_path.exists():
|
||||
return str(deglint_path)
|
||||
# 还要检查插值方法生成的文件
|
||||
deglint_dir = work_path / "3_deglint"
|
||||
if deglint_dir.exists():
|
||||
for file_path in deglint_dir.glob("interpolated_*.bsq"):
|
||||
return str(file_path)
|
||||
elif output_type in step_outputs:
|
||||
# 直接匹配的输出类型
|
||||
relative_path = step_outputs[output_type]
|
||||
if relative_path.endswith('/'):
|
||||
# 是目录
|
||||
output_path = work_path / relative_path.rstrip('/')
|
||||
if output_path.exists() and output_path.is_dir():
|
||||
return str(output_path)
|
||||
else:
|
||||
# 是文件
|
||||
output_path = work_path / relative_path
|
||||
if output_path.exists():
|
||||
return str(output_path)
|
||||
|
||||
return None
|
||||
|
||||
def scan_work_directory_for_files(self, work_path):
|
||||
"""扫描工作目录,自动发现各步骤的输出文件"""
|
||||
discovered_outputs = {}
|
||||
|
||||
# 扫描各个子目录
|
||||
subdirs = {
|
||||
'1_water_mask': 'step1',
|
||||
'2_glint': 'step2',
|
||||
'3_deglint': 'step3',
|
||||
'4_processed_data': 'step4',
|
||||
'5_training_spectra': 'step5',
|
||||
'6_water_quality_indices': 'step5_5',
|
||||
'7_Supervised_Model_Training': 'step6',
|
||||
'8_Regression_Modeling': 'step6_5',
|
||||
'9_Custom_Regression_Modeling': 'step6_75',
|
||||
'10_sampling': 'step7',
|
||||
'11_12_13_predictions/Machine_Learning_Prediction': 'step8',
|
||||
'11_12_13_predictions/Non_Empirical_Prediction': 'step8_5',
|
||||
'11_12_13_predictions/Custom_Regression_Prediction': 'step8_75',
|
||||
'14_visualization': 'step9'
|
||||
}
|
||||
|
||||
for subdir, step_ids in subdirs.items():
|
||||
subdir_path = work_path / subdir
|
||||
if not subdir_path.exists():
|
||||
continue
|
||||
|
||||
if isinstance(step_ids, str):
|
||||
step_ids = [step_ids]
|
||||
|
||||
# 扫描该目录下的文件
|
||||
for file_path in subdir_path.rglob('*'):
|
||||
if file_path.is_file():
|
||||
file_name = file_path.name.lower()
|
||||
|
||||
# 根据文件名模式判断输出类型
|
||||
for step_id in step_ids:
|
||||
if step_id not in discovered_outputs:
|
||||
discovered_outputs[step_id] = {}
|
||||
|
||||
# 匹配不同的文件类型
|
||||
if 'water_mask' in file_name and step_id == 'step1':
|
||||
discovered_outputs[step_id]['water_mask'] = str(file_path)
|
||||
elif 'glint' in file_name and 'mask' in file_name and step_id == 'step2':
|
||||
discovered_outputs[step_id]['glint_mask'] = str(file_path)
|
||||
elif 'deglint' in file_name and step_id == 'step3':
|
||||
discovered_outputs[step_id]['deglint_image'] = str(file_path)
|
||||
elif 'processed_data' in file_name and step_id == 'step4':
|
||||
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 == 'step5_5':
|
||||
discovered_outputs[step_id]['water_indices'] = str(file_path)
|
||||
elif 'sampling_spectra' in file_name and step_id == 'step7':
|
||||
discovered_outputs[step_id]['sampling_points'] = str(file_path)
|
||||
elif file_name.endswith('.csv') and step_id in ['step8', 'step8_5', 'step8_75']:
|
||||
discovered_outputs[step_id]['predictions'] = str(file_path)
|
||||
|
||||
# 更新内部记录
|
||||
for step_id, outputs in discovered_outputs.items():
|
||||
if step_id not in self.step_outputs:
|
||||
self.step_outputs[step_id] = {}
|
||||
self.step_outputs[step_id].update(outputs)
|
||||
|
||||
return discovered_outputs
|
||||
|
||||
def auto_populate_all_steps(self):
|
||||
"""自动填充所有步骤的输入路径"""
|
||||
work_dir = getattr(self, 'work_dir', './work_dir')
|
||||
work_path = Path(work_dir)
|
||||
|
||||
if not work_path.exists():
|
||||
QMessageBox.warning(self, "警告", f"工作目录不存在: {work_dir}\n请先设置正确的工作目录。")
|
||||
return
|
||||
|
||||
# 首先扫描工作目录发现已有的输出文件
|
||||
self.scan_work_directory_for_files(work_path)
|
||||
|
||||
step_order = ['step2', 'step3', 'step4', 'step5', 'step5_5', 'step6', 'step6_5', 'step6_75',
|
||||
'step7', 'step8', 'step8_5', 'step8_75', 'step9']
|
||||
|
||||
filled_count = 0
|
||||
for step_id in step_order:
|
||||
old_count = filled_count
|
||||
filled_count += self.auto_populate_step_inputs(step_id)
|
||||
|
||||
if filled_count > 0:
|
||||
self.log_message(f"已完成所有步骤的自动路径填充,共填充 {filled_count} 个输入字段", "info")
|
||||
QMessageBox.information(self, "完成", f"自动填充完成!\n共填充了 {filled_count} 个输入字段。")
|
||||
else:
|
||||
self.log_message("未发现可自动填充的路径", "info")
|
||||
QMessageBox.information(self, "完成", "未发现可自动填充的路径。\n请确保工作目录中有相关的输出文件。")
|
||||
|
||||
def add_auto_fill_buttons_to_panels(self):
|
||||
"""为各个步骤面板添加自动填充按钮"""
|
||||
# 这个方法会在UI初始化完成后调用
|
||||
# 为每个有依赖关系的步骤面板添加自动填充功能
|
||||
panels_with_dependencies = [
|
||||
('step2', self.step2_panel),
|
||||
('step3', self.step3_panel),
|
||||
('step5', self.step5_panel),
|
||||
('step5_5', self.step5_5_panel),
|
||||
('step6', self.step6_panel),
|
||||
('step6_5', self.step6_5_panel),
|
||||
('step6_75', self.step6_75_panel),
|
||||
('step7', self.step7_panel),
|
||||
('step8', self.step8_panel),
|
||||
('step8_5', self.step8_5_panel),
|
||||
('step8_75', self.step8_75_panel),
|
||||
('step9', self.step9_panel)
|
||||
]
|
||||
|
||||
for step_id, panel in panels_with_dependencies:
|
||||
if panel:
|
||||
# 为面板添加自动填充方法
|
||||
def create_auto_fill_method(sid):
|
||||
def auto_fill_inputs():
|
||||
self.auto_populate_step_inputs(sid)
|
||||
return auto_fill_inputs
|
||||
|
||||
panel.auto_fill_inputs = create_auto_fill_method(step_id)
|
||||
|
||||
# 尝试添加自动填充按钮到面板(如果面板支持的话)
|
||||
self.try_add_auto_fill_button(panel)
|
||||
|
||||
def try_add_auto_fill_button(self, panel):
|
||||
"""尝试为面板添加自动填充按钮"""
|
||||
try:
|
||||
# 查找面板中的运行按钮,在其旁边添加自动填充按钮
|
||||
if hasattr(panel, 'run_btn') and hasattr(panel, 'auto_fill_inputs'):
|
||||
run_btn = panel.run_btn
|
||||
|
||||
# 检查是否已经有自动填充按钮了
|
||||
if hasattr(panel, 'auto_fill_btn'):
|
||||
return
|
||||
|
||||
# 创建自动填充按钮
|
||||
auto_fill_btn = QPushButton("🔄 自动填充")
|
||||
auto_fill_btn.setStyleSheet(ModernStylesheet.get_button_stylesheet('normal'))
|
||||
auto_fill_btn.setToolTip("从工作目录自动填充输入路径")
|
||||
auto_fill_btn.clicked.connect(panel.auto_fill_inputs)
|
||||
auto_fill_btn.setMaximumWidth(120)
|
||||
|
||||
# 获取运行按钮的父布局
|
||||
parent_layout = run_btn.parent().layout()
|
||||
if parent_layout:
|
||||
# 找到运行按钮在布局中的位置
|
||||
for i in range(parent_layout.count()):
|
||||
if parent_layout.itemAt(i).widget() == run_btn:
|
||||
# 创建水平布局容器
|
||||
btn_container = QWidget()
|
||||
btn_layout = QHBoxLayout(btn_container)
|
||||
btn_layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
# 从原布局中移除运行按钮
|
||||
parent_layout.removeWidget(run_btn)
|
||||
|
||||
# 添加按钮到新的水平布局
|
||||
btn_layout.addWidget(auto_fill_btn)
|
||||
btn_layout.addWidget(run_btn)
|
||||
|
||||
# 将按钮容器添加到原位置
|
||||
parent_layout.insertWidget(i, btn_container)
|
||||
|
||||
panel.auto_fill_btn = auto_fill_btn
|
||||
break
|
||||
except Exception as e:
|
||||
# 如果添加失败,静默忽略
|
||||
pass
|
||||
|
||||
def set_work_directory(self):
|
||||
"""设置工作目录"""
|
||||
dir_path = QFileDialog.getExistingDirectory(self, "选择工作目录")
|
||||
@ -6313,6 +6722,7 @@ class WaterQualityGUI(QMainWindow):
|
||||
self.worker = WorkerThread(work_dir, worker_config, mode='full')
|
||||
self.worker.log_message.connect(self.log_message, Qt.QueuedConnection)
|
||||
self.worker.progress_update.connect(self.update_progress, Qt.QueuedConnection)
|
||||
self.worker.step_completed.connect(self.on_step_completed, Qt.QueuedConnection)
|
||||
self.worker.finished.connect(self.on_pipeline_finished, Qt.QueuedConnection)
|
||||
|
||||
# 更新UI状态
|
||||
@ -6357,6 +6767,64 @@ class WaterQualityGUI(QMainWindow):
|
||||
self.log_message("="*50, "error")
|
||||
QMessageBox.critical(self, "失败", f"流程执行失败:\n\n{message[:200]}")
|
||||
|
||||
def on_step_completed(self, step_name, success, message):
|
||||
"""步骤完成回调:记录输出路径并更新后续步骤"""
|
||||
if not success:
|
||||
return
|
||||
|
||||
# 记录步骤输出路径到内存
|
||||
work_dir = getattr(self, 'work_dir', './work_dir')
|
||||
work_path = Path(work_dir)
|
||||
|
||||
# 根据步骤名称和约定路径,记录实际输出
|
||||
if step_name not in self.step_outputs:
|
||||
self.step_outputs[step_name] = {}
|
||||
|
||||
# 扫描工作目录,更新该步骤的输出路径
|
||||
self.update_step_outputs(step_name, work_path)
|
||||
|
||||
# 自动填充依赖该步骤输出的后续步骤
|
||||
self.auto_populate_dependent_steps(step_name)
|
||||
|
||||
def update_step_outputs(self, step_name, work_path):
|
||||
"""更新指定步骤的输出路径记录"""
|
||||
if step_name not in self.step_default_outputs:
|
||||
return
|
||||
|
||||
step_outputs = self.step_default_outputs[step_name]
|
||||
|
||||
for output_type, relative_path in step_outputs.items():
|
||||
if '*' in relative_path:
|
||||
# 处理通配符路径
|
||||
pattern_path = work_path / relative_path.replace('*', '*')
|
||||
matching_files = list(pattern_path.parent.glob(pattern_path.name))
|
||||
if matching_files:
|
||||
# 选择最新的文件
|
||||
latest_file = max(matching_files, key=lambda p: p.stat().st_mtime)
|
||||
self.step_outputs[step_name][output_type] = str(latest_file)
|
||||
else:
|
||||
output_path = work_path / relative_path
|
||||
if output_path.exists():
|
||||
self.step_outputs[step_name][output_type] = str(output_path)
|
||||
|
||||
def auto_populate_dependent_steps(self, completed_step):
|
||||
"""自动填充依赖于已完成步骤的后续步骤"""
|
||||
for step_id, dependencies in self.step_dependencies.items():
|
||||
for input_field, (dep_step, output_type, panel_attr) in dependencies.items():
|
||||
if dep_step == completed_step:
|
||||
# 找到依赖于刚完成步骤的后续步骤,尝试自动填充
|
||||
panel = self.get_step_panel(step_id)
|
||||
if panel and hasattr(panel, panel_attr):
|
||||
file_widget = getattr(panel, panel_attr)
|
||||
# 如果输入框为空,则自动填充
|
||||
if not file_widget.get_path().strip():
|
||||
work_dir = getattr(self, 'work_dir', './work_dir')
|
||||
work_path = Path(work_dir)
|
||||
output_path = self.find_step_output(work_path, dep_step, output_type)
|
||||
if output_path and Path(output_path).exists():
|
||||
file_widget.set_path(output_path)
|
||||
self.log_message(f"步骤完成后自动填充 {step_id}.{input_field}: {output_path}", "info")
|
||||
|
||||
def run_single_step(self, step_name, config):
|
||||
"""运行单个步骤"""
|
||||
if not PIPELINE_AVAILABLE:
|
||||
@ -6373,6 +6841,7 @@ class WaterQualityGUI(QMainWindow):
|
||||
self.worker = WorkerThread(work_dir, config, mode='single_step', step_name=step_name)
|
||||
self.worker.log_message.connect(self.log_message, Qt.QueuedConnection)
|
||||
self.worker.progress_update.connect(self.update_progress, Qt.QueuedConnection)
|
||||
self.worker.step_completed.connect(self.on_step_completed, Qt.QueuedConnection)
|
||||
self.worker.finished.connect(self.on_pipeline_finished, Qt.QueuedConnection)
|
||||
|
||||
# 更新UI状态
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -1,15 +0,0 @@
|
||||
ENVI
|
||||
description = {
|
||||
work_dir\10_sampling\sampling_spectra_valid_area.bsq}
|
||||
samples = 11363
|
||||
lines = 10408
|
||||
bands = 1
|
||||
header offset = 0
|
||||
file type = ENVI Standard
|
||||
data type = 4
|
||||
interleave = bsq
|
||||
byte order = 0
|
||||
map info = {UTM, 1, 1, 600742.055, 4613386.65, 0.2, 0.2, 51, North,WGS-84}
|
||||
coordinate system string = {PROJCS["unnamed",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",123.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]]}
|
||||
band names = {
|
||||
Band 1}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 MiB |
Binary file not shown.
@ -1,15 +0,0 @@
|
||||
ENVI
|
||||
description = {
|
||||
work_dir\1_water_mask\water_mask_from_shp.dat}
|
||||
samples = 11363
|
||||
lines = 10408
|
||||
bands = 1
|
||||
header offset = 0
|
||||
file type = ENVI Standard
|
||||
data type = 4
|
||||
interleave = bsq
|
||||
byte order = 0
|
||||
map info = {UTM, 1, 1, 600742.055, 4613386.65, 0.2, 0.2, 51, North,WGS-84}
|
||||
coordinate system string = {PROJCS["unnamed",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",123.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]]}
|
||||
band names = {
|
||||
Band 1}
|
||||
@ -1,15 +0,0 @@
|
||||
ENVI
|
||||
description = {
|
||||
work_dir\1_water_mask\water_mask_from_shp__tmp_delete.dat}
|
||||
samples = 7411
|
||||
lines = 5368
|
||||
bands = 1
|
||||
header offset = 0
|
||||
file type = ENVI Standard
|
||||
data type = 1
|
||||
interleave = bsq
|
||||
byte order = 0
|
||||
map info = {UTM, 1, 1, 600947.955, 4612951.75, 0.2, 0.2, 51, North,WGS-84}
|
||||
coordinate system string = {PROJCS["WGS_1984_UTM_Zone_51N",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",123.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]]}
|
||||
band names = {
|
||||
Band 1}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 MiB |
@ -150,7 +150,7 @@ def Preprocessing(method, input_spectrum, save_path=None):
|
||||
# SS预处理模型保存到工作目录的7_Supervised_Model_Training/scaler_params.pkl
|
||||
# 如果调用者没有提供save_path,则使用默认路径
|
||||
if not save_path:
|
||||
save_path = r'E:\code\WQ\models\scaler_params.pkl'
|
||||
save_path = r'.\scaler_params.pkl'
|
||||
output_spectrum = SS(input_spectrum.values, save_path)
|
||||
elif method == 'CT':
|
||||
output_spectrum = CT(input_spectrum.values)
|
||||
|
||||
Reference in New Issue
Block a user