增加模块;增加主调用命令

This commit is contained in:
2026-01-07 16:36:47 +08:00
commit 2d4b170a45
109 changed files with 55763 additions and 0 deletions

View File

@ -0,0 +1,841 @@
import numpy as np
import pandas as pd
import spectral
import cv2
import os
from scipy.io import savemat
from scipy import ndimage
from scipy.ndimage import gaussian_filter, laplace
from typing import Optional, Dict, Any, Tuple, List, Union
from dataclasses import dataclass, field
import warnings
warnings.filterwarnings('ignore')
@dataclass
class EdgeDetectionConfig:
"""边缘检测配置类"""
# 输入文件配置
input_path: Optional[str] = None
band_index: int = 0 # 指定的波段索引从0开始
# 输出配置
output_path: Optional[str] = None
output_dir: Optional[str] = None
# 边缘检测方法配置
method: str = 'canny'
kernel_size: int = 3 # 卷积核大小(必须是奇数)
# 批量处理配置
batch_methods: List[str] = field(default_factory=lambda: ['canny'])
batch_bands: List[int] = field(default_factory=lambda: [0])
# Sobel和Scharr参数
sobel_dx: int = 1 # x方向导数阶数
sobel_dy: int = 0 # y方向导数阶数
sobel_ksize: int = -1 # Sobel核大小-1表示3x3
# Laplacian参数
laplacian_ksize: int = 1 # Laplacian核大小
laplacian_scale: float = 1.0 # Laplacian尺度参数
laplacian_delta: float = 0.0 # Laplacian delta参数
# LoG参数
log_sigma: float = 1.0 # 高斯标准差
log_threshold: float = 0.0 # LoG阈值
# 梯度算法阈值参数
gradient_threshold: float = 0.0 # 梯度阈值0-2550表示不使用阈值
gradient_use_otsu: bool = False # 是否对梯度图使用Otsu自动阈值
log_mode: str = 'reflect' # 边界模式:'reflect', 'constant', 'nearest', 'mirror', 'wrap'
# Canny参数
canny_min_threshold: int = 100
canny_max_threshold: int = 200
canny_aperture_size: int = 3 # Sobel算子孔径大小
canny_l2gradient: bool = False # 是否使用L2范数计算梯度
# 通用参数
normalize_output: bool = False # 是否将输出归一化到0-255
use_blur: bool = False # 是否预先进行高斯模糊
blur_kernel_size: int = 3 # 模糊核大小(必须是奇数)
blur_sigma: float = 1.0 # 模糊标准差
def __post_init__(self):
"""参数校验和默认值设置"""
# 校验必需的文件路径
if not self.input_path:
raise ValueError("必须指定输入文件路径(input_path)")
if not os.path.exists(self.input_path):
raise FileNotFoundError(f"输入文件不存在: {self.input_path}")
# 校验输出路径
if not self.output_path and not self.output_dir:
raise ValueError("必须指定输出路径(output_path)或输出目录(output_dir)")
# 校验边缘检测方法
supported_methods = self._get_supported_methods()
if self.method not in supported_methods:
raise ValueError(f"不支持的边缘检测方法: {self.method}。支持的方法: {list(supported_methods.keys())}")
# 校验批量处理参数
if len(self.batch_methods) != len(self.batch_bands):
# 如果长度不等,使用广播方式:单个波段对应多个方法,或单个方法对应多个波段
if len(self.batch_methods) == 1 and len(self.batch_bands) > 1:
# 一个方法应用到多个波段
self.batch_methods = self.batch_methods * len(self.batch_bands)
elif len(self.batch_bands) == 1 and len(self.batch_methods) > 1:
# 一个波段应用多个方法
self.batch_bands = self.batch_bands * len(self.batch_methods)
else:
raise ValueError("batch_methods和batch_bands长度不匹配请确保其中一个长度为1或两者长度相等")
for method in self.batch_methods:
if method not in supported_methods:
raise ValueError(f"批量处理中包含不支持的方法: {method}")
# 校验参数
self._validate_parameters()
def _validate_parameters(self):
"""参数校验"""
# 校验核大小
if self.kernel_size % 2 == 0 or self.kernel_size < 1:
raise ValueError("kernel_size必须是正奇数")
# 校验Sobel参数
if self.sobel_dx < 0 or self.sobel_dy < 0:
raise ValueError("sobel_dx和sobel_dy必须是非负整数")
if self.sobel_dx + self.sobel_dy != 1:
raise ValueError(f"sobel_dx({self.sobel_dx}) + sobel_dy({self.sobel_dy}) 必须等于1。有效组合: dx=1,dy=0 或 dx=0,dy=1")
if self.sobel_ksize != -1 and (self.sobel_ksize % 2 == 0 or self.sobel_ksize < 1):
raise ValueError("sobel_ksize必须是正奇数或-1")
# 校验Laplacian参数
if self.laplacian_ksize < 1 or self.laplacian_ksize > 31:
raise ValueError("laplacian_ksize必须在1-31之间")
if self.laplacian_scale <= 0:
raise ValueError("laplacian_scale必须大于0")
# 校验LoG参数
if self.log_sigma <= 0:
raise ValueError("log_sigma必须大于0")
if self.log_mode not in ['reflect', 'constant', 'nearest', 'mirror', 'wrap']:
raise ValueError("log_mode必须是'reflect', 'constant', 'nearest', 'mirror', 'wrap'之一")
# 校验Canny参数
if self.canny_min_threshold < 0 or self.canny_max_threshold < 0:
raise ValueError("Canny阈值必须是非负数")
if self.canny_min_threshold >= self.canny_max_threshold:
raise ValueError("canny_min_threshold必须小于canny_max_threshold")
if self.canny_aperture_size not in [3, 5, 7]:
raise ValueError("canny_aperture_size必须是3、5或7")
# 校验梯度阈值参数
if self.gradient_threshold < 0 or self.gradient_threshold > 255:
raise ValueError("gradient_threshold必须在0-255范围内")
# 校验通用参数
if self.blur_kernel_size % 2 == 0 or self.blur_kernel_size < 1:
raise ValueError("blur_kernel_size必须是正奇数")
if self.blur_sigma <= 0:
raise ValueError("blur_sigma必须大于0")
def _get_supported_methods(self) -> Dict[str, str]:
"""获取支持的边缘检测方法列表"""
methods = {
'sobel': 'Sobel算子',
'scharr': 'Scharr算子',
'laplacian': 'Laplacian算子',
'log': 'Laplacian of Gaussian (LoG)',
'canny': 'Canny算子'
}
return methods
class EdgeDetector:
"""边缘检测处理系统"""
def __init__(self, config: EdgeDetectionConfig):
self.config = config
# 初始化数据存储
self.data = None
self.selected_band = None
self.original_shape = None
def load_data(self) -> None:
"""
加载数据文件
"""
print(f"正在加载数据文件: {self.config.input_path}")
file_ext = os.path.splitext(self.config.input_path)[1].lower()
if file_ext in ['.dat', '.img', '.hdr']:
self._load_hyperspectral_data(self.config.input_path)
else:
raise ValueError(f"不支持的文件格式: {file_ext}")
# 提取指定波段
self._extract_band(self.config.band_index)
print("数据加载完成")
def _load_hyperspectral_data(self, file_path):
"""加载高光谱图像数据"""
base_path = os.path.splitext(file_path)[0]
hdr_file = base_path + '.hdr'
# 读取ENVI格式图像
img = spectral.open_image(hdr_file)
self.data = img.load()
self.original_shape = self.data.shape
# 转换为二维数组(像素×波段)
self.data = self.data.reshape(-1, self.data.shape[2])
def _extract_band(self, band_index):
"""提取指定波段"""
if band_index >= self.data.shape[1]:
raise ValueError(f"波段索引超出范围: {band_index}, 总波段数: {self.data.shape[1]}")
self.selected_band = self.data[:, band_index].reshape(self.original_shape[0], self.original_shape[1])
def apply_edge_detection(self) -> Tuple[np.ndarray, Dict[str, Any]]:
"""
应用边缘检测方法
Returns:
Tuple[np.ndarray, Dict[str, Any]]: (边缘检测结果, 附加信息)
"""
print(f"正在应用边缘检测方法: {self.config.method}")
if self.selected_band is None:
raise ValueError("请先加载数据")
# 归一化图像到0-255范围大多数OpenCV函数需要
image_normalized = self._normalize_image(self.selected_band)
# 应用不同的边缘检测方法
if self.config.method == 'sobel':
result, info = self._sobel_detection(image_normalized)
elif self.config.method == 'scharr':
result, info = self._scharr_detection(image_normalized)
elif self.config.method == 'laplacian':
result, info = self._laplacian_detection(image_normalized)
elif self.config.method == 'log':
result, info = self._log_detection(self.selected_band) # LoG使用原始数据
elif self.config.method == 'canny':
result, info = self._canny_detection(image_normalized)
else:
raise ValueError(f"不支持的边缘检测方法: {self.config.method}")
# 归一化输出
if self.config.normalize_output:
result = self._normalize_output(result)
return result.astype(np.uint8), info
def _normalize_image(self, image):
"""将图像归一化到0-255范围"""
image_min, image_max = np.min(image), np.max(image)
if image_max > image_min:
return ((image - image_min) / (image_max - image_min) * 255).astype(np.uint8)
else:
return image.astype(np.uint8)
def _normalize_output(self, image):
"""将输出归一化到0-255范围"""
image_min, image_max = np.min(image), np.max(image)
if image_max > image_min:
return ((image - image_min) / (image_max - image_min) * 255).astype(np.uint8)
else:
return (image * 255).astype(np.uint8)
def _apply_gradient_threshold(self, gradient_image, method_name):
"""对梯度图像应用阈值处理"""
if self.config.gradient_threshold > 0:
# 使用固定阈值
_, thresholded = cv2.threshold(gradient_image, self.config.gradient_threshold, 255, cv2.THRESH_BINARY)
print(f"{method_name} 使用固定阈值: {self.config.gradient_threshold}")
return thresholded
elif self.config.gradient_use_otsu:
# 使用Otsu自动阈值
_, thresholded = cv2.threshold(gradient_image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
print(f"{method_name} 使用Otsu自动阈值")
return thresholded
else:
# 不使用阈值,直接返回梯度图像
return gradient_image
def _sobel_detection(self, image):
"""Sobel边缘检测"""
# 预处理:高斯模糊
if self.config.use_blur:
image = cv2.GaussianBlur(image, (self.config.blur_kernel_size, self.config.blur_kernel_size), self.config.blur_sigma)
# 校验Sobel参数OpenCV要求dx+dy == 1
if self.config.sobel_dx + self.config.sobel_dy != 1:
raise ValueError(f"Sobel参数错误: dx({self.config.sobel_dx}) + dy({self.config.sobel_dy}) 必须等于1。有效组合: dx=1,dy=0 或 dx=0,dy=1")
# 计算梯度
grad = cv2.Sobel(image, cv2.CV_64F, self.config.sobel_dx, self.config.sobel_dy, ksize=self.config.sobel_ksize)
# 计算梯度幅值(如果是混合梯度)
if self.config.sobel_dx == 1 and self.config.sobel_dy == 1:
grad_magnitude = cv2.convertScaleAbs(grad)
else:
# 对于单方向梯度,直接使用绝对值
grad_magnitude = cv2.convertScaleAbs(grad)
# 应用阈值处理(可选)
grad_magnitude = self._apply_gradient_threshold(grad_magnitude, 'Sobel')
info = {
'grad': grad,
'method': 'Sobel',
'parameters': {
'dx': self.config.sobel_dx,
'dy': self.config.sobel_dy,
'ksize': self.config.sobel_ksize,
'use_blur': self.config.use_blur,
'blur_kernel_size': self.config.blur_kernel_size if self.config.use_blur else None,
'blur_sigma': self.config.blur_sigma if self.config.use_blur else None,
'gradient_threshold': self.config.gradient_threshold,
'gradient_use_otsu': self.config.gradient_use_otsu
}
}
return grad_magnitude, info
def _scharr_detection(self, image):
"""Scharr边缘检测"""
# 预处理:高斯模糊
if self.config.use_blur:
image = cv2.GaussianBlur(image, (self.config.blur_kernel_size, self.config.blur_kernel_size), self.config.blur_sigma)
# Scharr算子是特殊的3x3 Sobel算子
grad_x = cv2.Scharr(image, cv2.CV_64F, 1, 0)
grad_y = cv2.Scharr(image, cv2.CV_64F, 0, 1)
# 计算梯度幅值
grad_magnitude = cv2.magnitude(grad_x, grad_y)
# 转换为uint8
grad_magnitude = cv2.convertScaleAbs(grad_magnitude)
# 应用阈值处理(可选)
grad_magnitude = self._apply_gradient_threshold(grad_magnitude, 'Scharr')
info = {
'grad_x': grad_x,
'grad_y': grad_y,
'method': 'Scharr',
'parameters': {
'use_blur': self.config.use_blur,
'blur_kernel_size': self.config.blur_kernel_size if self.config.use_blur else None,
'blur_sigma': self.config.blur_sigma if self.config.use_blur else None,
'gradient_threshold': self.config.gradient_threshold,
'gradient_use_otsu': self.config.gradient_use_otsu
}
}
return grad_magnitude, info
def _laplacian_detection(self, image):
"""Laplacian边缘检测"""
# 预处理:高斯模糊
if self.config.use_blur:
image = cv2.GaussianBlur(image, (self.config.blur_kernel_size, self.config.blur_kernel_size), self.config.blur_sigma)
# 应用Laplacian算子
laplacian = cv2.Laplacian(image, cv2.CV_64F, ksize=self.config.laplacian_ksize,
scale=self.config.laplacian_scale, delta=self.config.laplacian_delta)
# 取绝对值并转换为uint8
laplacian_abs = cv2.convertScaleAbs(laplacian)
# 应用阈值处理(可选)
laplacian_abs = self._apply_gradient_threshold(laplacian_abs, 'Laplacian')
info = {
'laplacian': laplacian,
'method': 'Laplacian',
'parameters': {
'ksize': self.config.laplacian_ksize,
'scale': self.config.laplacian_scale,
'delta': self.config.laplacian_delta,
'use_blur': self.config.use_blur,
'blur_kernel_size': self.config.blur_kernel_size if self.config.use_blur else None,
'blur_sigma': self.config.blur_sigma if self.config.use_blur else None,
'gradient_threshold': self.config.gradient_threshold,
'gradient_use_otsu': self.config.gradient_use_otsu
}
}
return laplacian_abs, info
def _log_detection(self, image):
"""Laplacian of Gaussian (LoG) 边缘检测"""
# 使用指定的边界模式进行高斯滤波
gaussian_filtered = gaussian_filter(image.astype(np.float64),
sigma=self.config.log_sigma,
mode=self.config.log_mode)
# 应用Laplacian算子
log_result = laplace(gaussian_filtered, mode=self.config.log_mode)
# 取绝对值
log_abs = np.abs(log_result)
# 应用阈值
if self.config.log_threshold > 0:
log_abs = (log_abs > self.config.log_threshold).astype(np.uint8) * 255
else:
# 自动阈值使用Otsu方法
# 先归一化到0-255范围然后应用Otsu
log_min, log_max = np.min(log_abs), np.max(log_abs)
if log_max > log_min:
log_normalized = ((log_abs - log_min) / (log_max - log_min) * 255).astype(np.uint8)
else:
log_normalized = log_abs.astype(np.uint8)
_, log_abs = cv2.threshold(log_normalized, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
info = {
'gaussian_filtered': gaussian_filtered,
'log_result': log_result,
'method': 'LoG',
'parameters': {
'sigma': self.config.log_sigma,
'threshold': self.config.log_threshold,
'mode': self.config.log_mode
}
}
return log_abs.astype(np.uint8), info
def _canny_detection(self, image):
"""Canny边缘检测"""
# 预处理:高斯模糊
if self.config.use_blur:
image = cv2.GaussianBlur(image, (self.config.blur_kernel_size, self.config.blur_kernel_size), self.config.blur_sigma)
# 应用Canny算子
edges = cv2.Canny(image,
self.config.canny_min_threshold,
self.config.canny_max_threshold,
apertureSize=self.config.canny_aperture_size,
L2gradient=self.config.canny_l2gradient)
info = {
'method': 'Canny',
'parameters': {
'min_threshold': self.config.canny_min_threshold,
'max_threshold': self.config.canny_max_threshold,
'aperture_size': self.config.canny_aperture_size,
'L2gradient': self.config.canny_l2gradient,
'use_blur': self.config.use_blur,
'blur_kernel_size': self.config.blur_kernel_size if self.config.use_blur else None,
'blur_sigma': self.config.blur_sigma if self.config.use_blur else None
}
}
return edges, info
def save_results(self, edge_data, info, output_path, method):
"""
保存边缘检测结果
参数:
edge_data: 边缘检测结果
info: 附加信息
output_path: 输出路径
method: 使用的边缘检测方法
"""
output_base = os.path.splitext(output_path)[0]
# 保存.dat文件
self._save_dat_file(edge_data, output_path)
# 保存.hdr头文件
hdr_path = output_base + '.hdr'
self._save_hdr_file(hdr_path, edge_data.shape, method, info)
print(f"边缘检测结果已保存: {output_path}")
print(f"头文件已保存: {hdr_path}")
print(f"使用的检测方法: {method}")
def _save_dat_file(self, data, file_path):
"""保存.dat文件二进制格式"""
with open(file_path, 'wb') as f:
data.astype(np.uint8).tofile(f)
def _save_hdr_file(self, hdr_path, data_shape, method, info):
"""保存ENVI头文件"""
header_content = f"""ENVI
description = {{{method} Edge Detection Result}}
samples = {data_shape[1]}
lines = {data_shape[0]}
bands = 1
header offset = 0
file type = ENVI Standard
data type = 1
interleave = bsq
byte order = 0
band names = {{Edge_Detection_Result}}
classes = 2
class names = {{Background, Edges}}
class lookup = {{0,0,0, 255,255,255}}
"""
# 添加方法参数信息
if 'parameters' in info and info['parameters']:
params_str = ', '.join([f'{k}:{v}' for k, v in info['parameters'].items()])
header_content += f"edge_detection_parameters = {{{params_str}}}\n"
header_content += f"edge_detection_method = {method}\n"
with open(hdr_path, 'w', encoding='utf-8') as f:
f.write(header_content)
def batch_process(self, methods, bands, output_dir):
"""
批量处理多个边缘检测方法
参数:
methods: 边缘检测方法列表
bands: 波段索引列表
output_dir: 输出目录
"""
os.makedirs(output_dir, exist_ok=True)
# 显示数据信息
if self.data is not None:
print(f"\n=== 数据信息 ===")
print(f"图像尺寸: {self.original_shape[0]}x{self.original_shape[1]}")
print(f"波段数: {self.original_shape[2]}")
results = {}
for method, band_idx in zip(methods, bands):
print(f"\n正在处理: {method} (波段: {band_idx})")
try:
# 临时修改配置以适应当前方法和波段
original_method = self.config.method
original_band = self.config.band_index
self.config.method = method
self.config.band_index = band_idx
# 重新提取波段
self._extract_band(band_idx)
# 应用边缘检测
edge_data, info = self.apply_edge_detection()
# 恢复原始配置
self.config.method = original_method
self.config.band_index = original_band
# 保存结果
output_path = os.path.join(output_dir, f'edge_{method}_band{band_idx}.dat')
self.save_results(edge_data, info, output_path, method)
results[method] = {
'data': edge_data,
'info': info,
'band': band_idx
}
except Exception as e:
print(f"处理 {method} 时出错: {str(e)}")
return results
@staticmethod
def print_method_info():
"""
打印所有可用边缘检测方法的详细信息
"""
method_info = {
'sobel': {
'name': 'Sobel算子 (Sobel Operator)',
'description': '使用Sobel核计算图像梯度检测边缘',
'advantages': ['计算简单', '对噪声有一定抑制', '可以检测边缘方向'],
'limitations': ['对噪声敏感', '检测到的边缘较粗'],
'best_for': ['一般边缘检测', '需要方向信息的应用'],
'parameters': ['sobel_dx', 'sobel_dy', 'sobel_ksize', 'use_blur', 'blur_kernel_size', 'blur_sigma', 'gradient_threshold', 'gradient_use_otsu']
},
'scharr': {
'name': 'Scharr算子 (Scharr Operator)',
'description': '改进的Sobel算子具有更好的旋转不变性',
'advantages': ['比Sobel算子更精确', '更好的旋转不变性'],
'limitations': ['计算量稍大', '只适用于3x3核'],
'best_for': ['需要高精度边缘检测的应用'],
'parameters': ['use_blur', 'blur_kernel_size', 'blur_sigma', 'gradient_threshold', 'gradient_use_otsu']
},
'laplacian': {
'name': 'Laplacian算子 (Laplacian Operator)',
'description': '基于二阶导数的边缘检测方法,对灰度突变敏感',
'advantages': ['对灰度突变敏感', '计算简单'],
'limitations': ['对噪声非常敏感', '不能提供边缘方向信息'],
'best_for': ['检测灰度突变明显的边缘'],
'parameters': ['laplacian_ksize', 'laplacian_scale', 'laplacian_delta', 'use_blur', 'blur_kernel_size', 'blur_sigma', 'gradient_threshold', 'gradient_use_otsu']
},
'log': {
'name': 'Laplacian of Gaussian (LoG)',
'description': '先进行高斯平滑再应用Laplacian算子',
'advantages': ['减少噪声影响', '检测不同尺度边缘', '理论基础扎实'],
'limitations': ['计算复杂度高', '参数选择重要'],
'best_for': ['需要抑制噪声的边缘检测', '学术研究'],
'parameters': ['log_sigma', 'log_threshold', 'log_mode']
},
'canny': {
'name': 'Canny算子 (Canny Edge Detector)',
'description': '多阶段边缘检测算法,包括平滑、梯度计算、非最大抑制和双阈值处理',
'advantages': ['检测精度高', '抗噪声能力强', '单像素边缘'],
'limitations': ['计算复杂度较高', '参数调节复杂'],
'best_for': ['高质量边缘检测', '计算机视觉应用'],
'parameters': ['canny_min_threshold', 'canny_max_threshold', 'canny_aperture_size', 'canny_l2gradient', 'use_blur', 'blur_kernel_size', 'blur_sigma']
}
}
print("\n=== 边缘检测方法详细说明 ===\n")
for method, info in method_info.items():
print(f"{method} - {info['name']}")
print(f" 描述: {info['description']}")
print(f" 优势: {', '.join(info['advantages'])}")
print(f" 局限性: {', '.join(info['limitations'])}")
print(f" 适用场景: {', '.join(info['best_for'])}")
if 'parameters' in info:
print(f" 可调参数: {', '.join(info['parameters'])}")
print()
def main():
"""主函数:命令行接口"""
import argparse
parser = argparse.ArgumentParser(
description='高光谱图像边缘检测工具',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
使用示例:
1. 使用Canny算子检测边缘:
python edge_detect.py input.hdr -m canny -b 50 -o edge_result.dat
2. 批量应用多种边缘检测方法:
python edge_detect.py input.hdr -m sobel scharr laplacian log canny -B 25 25 25 25 25 -d results/
3. 使用自定义参数的Sobel检测:
python edge_detect.py input.hdr -m sobel -b 30 --sobel-dx 1 --sobel-dy 0 --use-blur --blur-kernel-size 5
支持的边缘检测方法:
sobel: Sobel算子
scharr: Scharr算子
laplacian: Laplacian算子
log: Laplacian of Gaussian (LoG)
canny: Canny算子
批量处理:
-m 指定多个方法,-B 指定对应波段索引
-d 指定输出目录
"""
)
parser.add_argument('input_path', help='输入高光谱图像文件路径 (.hdr)')
parser.add_argument('-m', '--methods', nargs='+', required=True,
choices=['sobel', 'scharr', 'laplacian', 'log', 'canny'],
help='边缘检测方法 (可指定多个)')
parser.add_argument('-b', '--band-index', type=int, default=0,
help='波段索引 (默认: 0)')
parser.add_argument('-B', '--batch-bands', nargs='+', type=int,
help='批量处理的波段索引列表 (与methods一一对应)')
parser.add_argument('-o', '--output', help='单个方法输出文件路径')
parser.add_argument('-d', '--output-dir', default='edge_detection_results',
help='批量处理输出目录 (默认: edge_detection_results)')
# Sobel和Scharr参数
parser.add_argument('--sobel-dx', type=int, default=1, choices=[0, 1],
help='Sobel x方向导数阶数必须与sobel-dy之和等于1 (默认: 1)')
parser.add_argument('--sobel-dy', type=int, default=0, choices=[0, 1],
help='Sobel y方向导数阶数必须与sobel-dx之和等于1 (默认: 0)')
parser.add_argument('--sobel-ksize', type=int, default=-1,
help='Sobel核大小-1表示3x3 (默认: -1)')
# Laplacian参数
parser.add_argument('--laplacian-ksize', type=int, default=1,
help='Laplacian核大小 (默认: 1)')
parser.add_argument('--laplacian-scale', type=float, default=1.0,
help='Laplacian尺度参数 (默认: 1.0)')
parser.add_argument('--laplacian-delta', type=float, default=0.0,
help='Laplacian delta参数 (默认: 0.0)')
# LoG参数
parser.add_argument('--log-sigma', type=float, default=1.0,
help='LoG高斯标准差 (默认: 1.0)')
parser.add_argument('--log-threshold', type=float, default=0.0,
help='LoG阈值0表示自动阈值 (默认: 0.0)')
parser.add_argument('--log-mode', default='reflect',
choices=['reflect', 'constant', 'nearest', 'mirror', 'wrap'],
help='LoG边界模式 (默认: reflect)')
# 梯度算法阈值参数
parser.add_argument('--gradient-threshold', type=float, default=0.0,
help='梯度阈值 (0-255)0表示不使用阈值 (默认: 0.0)')
parser.add_argument('--gradient-use-otsu', action='store_true',
help='对梯度图使用Otsu自动阈值')
# Canny参数
parser.add_argument('--canny-min-threshold', type=int, default=100,
help='Canny最小阈值 (默认: 100)')
parser.add_argument('--canny-max-threshold', type=int, default=200,
help='Canny最大阈值 (默认: 200)')
parser.add_argument('--canny-aperture-size', type=int, default=3, choices=[3, 5, 7],
help='Canny Sobel算子孔径大小 (默认: 3)')
parser.add_argument('--canny-l2gradient', action='store_true',
help='Canny使用L2范数计算梯度')
# 通用参数
parser.add_argument('--normalize-output', action='store_true',
help='将输出归一化到0-255范围')
parser.add_argument('--use-blur', action='store_true',
help='预先进行高斯模糊')
parser.add_argument('--blur-kernel-size', type=int, default=3,
help='模糊核大小,必须是奇数 (默认: 3)')
parser.add_argument('--blur-sigma', type=float, default=1.0,
help='模糊标准差 (默认: 1.0)')
# 其他选项
parser.add_argument('--show-methods', action='store_true',
help='显示所有可用方法的详细信息')
args = parser.parse_args()
# 显示方法信息
if args.show_methods:
EdgeDetector.print_method_info()
return 0
try:
print("=" * 60)
print("高光谱图像边缘检测工具")
print("=" * 60)
print(f"输入文件: {args.input_path}")
print(f"检测方法: {', '.join(args.methods)}")
print(f"波段索引: {args.band_index}")
print()
# 确定是单方法还是批量处理
if len(args.methods) == 1:
# 单方法处理
print("执行单方法边缘检测...")
config = EdgeDetectionConfig(
input_path=args.input_path,
band_index=args.band_index,
method=args.methods[0],
output_path=args.output,
# 参数设置
sobel_dx=args.sobel_dx,
sobel_dy=args.sobel_dy,
sobel_ksize=args.sobel_ksize,
laplacian_ksize=args.laplacian_ksize,
laplacian_scale=args.laplacian_scale,
laplacian_delta=args.laplacian_delta,
log_sigma=args.log_sigma,
log_threshold=args.log_threshold,
log_mode=args.log_mode,
gradient_threshold=args.gradient_threshold,
gradient_use_otsu=args.gradient_use_otsu,
canny_min_threshold=args.canny_min_threshold,
canny_max_threshold=args.canny_max_threshold,
canny_aperture_size=args.canny_aperture_size,
canny_l2gradient=args.canny_l2gradient,
normalize_output=args.normalize_output,
use_blur=args.use_blur,
blur_kernel_size=args.blur_kernel_size,
blur_sigma=args.blur_sigma
)
detector = EdgeDetector(config)
detector.load_data()
edge_data, info = detector.apply_edge_detection()
output_path = args.output or f"edge_{args.methods[0]}_band{args.band_index}.dat"
detector.save_results(edge_data, info, output_path, args.methods[0])
else:
# 批量处理
print("执行批量边缘检测...")
# 确定波段列表
if args.batch_bands:
if len(args.batch_bands) != len(args.methods):
raise ValueError(f"波段数量 ({len(args.batch_bands)}) 必须与方法数量 ({len(args.methods)}) 相等")
bands = args.batch_bands
else:
# 如果没有指定波段,使用默认波段
bands = [args.band_index] * len(args.methods)
# 创建基础配置
config = EdgeDetectionConfig(
input_path=args.input_path,
band_index=args.band_index, # 这个会被batch_process覆盖
method=args.methods[0], # 这个会被batch_process覆盖
output_dir=args.output_dir,
# 参数设置
sobel_dx=args.sobel_dx,
sobel_dy=args.sobel_dy,
sobel_ksize=args.sobel_ksize,
laplacian_ksize=args.laplacian_ksize,
laplacian_scale=args.laplacian_scale,
laplacian_delta=args.laplacian_delta,
log_sigma=args.log_sigma,
log_threshold=args.log_threshold,
log_mode=args.log_mode,
gradient_threshold=args.gradient_threshold,
gradient_use_otsu=args.gradient_use_otsu,
canny_min_threshold=args.canny_min_threshold,
canny_max_threshold=args.canny_max_threshold,
canny_aperture_size=args.canny_aperture_size,
canny_l2gradient=args.canny_l2gradient,
normalize_output=args.normalize_output,
use_blur=args.use_blur,
blur_kernel_size=args.blur_kernel_size,
blur_sigma=args.blur_sigma
)
detector = EdgeDetector(config)
detector.load_data()
results = detector.batch_process(args.methods, bands, args.output_dir)
print("\n" + "=" * 60)
print("边缘检测完成!")
print("=" * 60)
except Exception as e:
print(f"✗ 处理失败: {e}")
import traceback
traceback.print_exc()
return 1
return 0
if __name__ == "__main__":
main()