Initial commit of WQ_GUI

This commit is contained in:
2026-04-08 15:25:08 +08:00
commit 91e36407ae
302 changed files with 40872 additions and 0 deletions

1
src/__init__.py Normal file
View File

@ -0,0 +1 @@
# -*- coding: utf-8 -*-

1
src/core/__init__.py Normal file
View File

@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View File

@ -0,0 +1,367 @@
import numpy as np
# import preprocessing
try:
from osgeo import gdal
GDAL_AVAILABLE = True
except ImportError:
GDAL_AVAILABLE = False
print("警告: GDAL未安装将使用numpy处理模式")
try:
from tqdm import tqdm
TQDM_AVAILABLE = True
except ImportError:
TQDM_AVAILABLE = False
# 如果tqdm不可用定义一个简单的包装器
def tqdm(iterable, desc=None, total=None):
return iterable
class Goodman:
def __init__(self, im_aligned, NIR_lower = 25, NIR_upper = 37, A = 0.000019, B = 0.1,
use_gdal=True, chunk_size=None, water_mask=None, output_path=None):
"""
:param im_aligned (np.ndarray or str): band aligned and calibrated & corrected reflectance image
可以是numpy数组或GDAL可读取的文件路径
:param NIR_lower (int): band index which corresponds to 641.93nm, closest band to 640nm
:param NIR_upper (int): band index which corresponds to 751.49nm, closest band to 750nm
:param A (float): the values in Goodman et al's paper, using AVIRIS reflectance (rather than radiance) data
:param B (float): the values in Goodman et al's paper, using AVIRIS reflectance (rather than radiance) data
see Goodman et al, which corrects each pixel independently. The NIR radiance is subtracted from the radiance at each wavelength,
but a wavelength-independent offset is also added.
it is not clear how A and B were chosen, but an optimization for a case where in situ data is
available would enable values to be found
:param use_gdal (bool): 是否使用GDAL加速处理需要GDAL可用且输入为文件路径或大数组
:param chunk_size (int): 已废弃,不再使用分块处理,改为逐波段处理
:param water_mask (np.ndarray or str or None): 水域掩膜1表示水域0表示非水域
可以是numpy数组、栅格文件路径(.dat/.tif)或shapefile路径(.shp)
如果为None则处理全图
:param output_path (str or None): 输出文件路径,如果提供则保存校正后的图像
如果为None则不保存
"""
self.im_aligned = im_aligned
self.NIR_lower = NIR_lower
self.NIR_upper = NIR_upper
self.A = A
self.B = B
self.use_gdal = use_gdal and GDAL_AVAILABLE
self.chunk_size = chunk_size
self.is_file_path = isinstance(im_aligned, str)
self.output_path = output_path
# 获取图像信息(需要在加载掩膜之前获取尺寸)
if self.is_file_path:
if not self.use_gdal:
raise ValueError("输入为文件路径时必须安装GDAL")
self.dataset = gdal.Open(im_aligned, gdal.GA_ReadOnly)
if self.dataset is None:
raise ValueError(f"无法打开影像文件: {im_aligned}")
self.height = self.dataset.RasterYSize
self.width = self.dataset.RasterXSize
self.n_bands = self.dataset.RasterCount
else:
self.dataset = None
self.height = im_aligned.shape[0]
self.width = im_aligned.shape[1]
self.n_bands = im_aligned.shape[-1]
# 加载水域掩膜(在获取图像尺寸之后)
self.water_mask = self._load_water_mask(water_mask)
def _load_water_mask(self, water_mask):
"""
加载水域掩膜
:param water_mask: 可以是None、numpy数组、文件路径(.dat/.tif)或shapefile路径(.shp)
:return: numpy数组或None1表示水域0表示非水域
"""
if water_mask is None:
return None
# 如果已经是numpy数组
if isinstance(water_mask, np.ndarray):
if water_mask.shape[:2] != (self.height, self.width):
raise ValueError(f"掩膜尺寸 {water_mask.shape[:2]} 与图像尺寸 {(self.height, self.width)} 不匹配")
return (water_mask > 0).astype(np.uint8) # 确保是0/1掩膜
# 如果是文件路径
if isinstance(water_mask, str):
if not GDAL_AVAILABLE:
raise ValueError("使用文件路径作为掩膜时必须安装GDAL")
# 检查是否为shapefile
if water_mask.lower().endswith('.shp'):
# 从shp文件创建掩膜
if self.is_file_path:
ref_path = self.im_aligned
else:
raise ValueError("输入为numpy数组时无法从shp文件创建掩膜需要参考栅格")
try:
from osgeo import ogr
ref_dataset = gdal.Open(ref_path, gdal.GA_ReadOnly)
if ref_dataset is None:
raise ValueError(f"无法打开参考栅格文件: {ref_path}")
geotransform = ref_dataset.GetGeoTransform()
projection = ref_dataset.GetProjection()
width = ref_dataset.RasterXSize
height = ref_dataset.RasterYSize
# 创建内存中的栅格数据集
mem_driver = gdal.GetDriverByName('MEM')
mask_dataset = mem_driver.Create('', width, height, 1, gdal.GDT_Byte)
mask_dataset.SetGeoTransform(geotransform)
mask_dataset.SetProjection(projection)
mask_band = mask_dataset.GetRasterBand(1)
mask_band.Fill(0)
# 打开shp文件
shp_dataset = ogr.Open(water_mask)
if shp_dataset is None:
raise ValueError(f"无法打开shp文件: {water_mask}")
layer = shp_dataset.GetLayer()
gdal.RasterizeLayer(mask_dataset, [1], layer, burn_values=[1])
water_mask_array = mask_band.ReadAsArray()
ref_dataset = None
mask_dataset = None
shp_dataset = None
return (water_mask_array > 0).astype(np.uint8)
except Exception as e:
raise ValueError(f"从shp文件创建掩膜时出错: {e}")
else:
# 栅格文件
mask_dataset = gdal.Open(water_mask, gdal.GA_ReadOnly)
if mask_dataset is None:
raise ValueError(f"无法打开掩膜文件: {water_mask}")
mask_array = mask_dataset.GetRasterBand(1).ReadAsArray()
mask_dataset = None
if mask_array.shape != (self.height, self.width):
raise ValueError(f"掩膜尺寸 {mask_array.shape} 与图像尺寸 {(self.height, self.width)} 不匹配")
return (mask_array > 0).astype(np.uint8)
raise ValueError(f"不支持的掩膜类型: {type(water_mask)}")
def _get_corrected_bands_numpy(self):
"""
使用numpy处理用于小图像或GDAL不可用时
注意由于输入已经是numpy数组数据已在内存中。
此方法通过逐波段处理,避免同时创建多个校正后的波段数组。
内存峰值 = 原始数组 + NIR波段(2个) + 当前处理的波段(1个)
"""
# 预提取重复使用的NIR波段避免在循环中重复访问
# 这些波段会一直保存在内存中,因为它们需要用于所有波段的校正
R_640 = self.im_aligned[:,:,self.NIR_lower]
R_750 = self.im_aligned[:,:,self.NIR_upper]
# 预计算常量部分
diff_640_750 = R_640 - R_750
corrected_bands = []
# 获取水域掩膜(如果存在)
water_mask_bool = self.water_mask.astype(bool) if self.water_mask is not None else None
# 逐波段处理:每次只处理一个波段,处理完后立即添加到结果列表
for i in tqdm(range(self.n_bands), desc="处理波段 (numpy)", total=self.n_bands):
# 获取当前波段(这是数组视图,不是复制)
R = self.im_aligned[:,:,i]
# 优化计算:减少中间数组创建
corrected_band = R - R_750 + self.A + self.B * diff_640_750
# 使用np.maximum原地操作将负值设为0
np.maximum(corrected_band, 0, out=corrected_band)
# 如果存在水域掩膜,只对水域区域应用校正
if water_mask_bool is not None:
corrected_band = np.where(water_mask_bool, corrected_band, R)
# 立即添加到结果列表corrected_band会保留在列表中
corrected_bands.append(corrected_band)
return corrected_bands
def _get_corrected_bands_gdal(self):
"""
使用GDAL逐波段处理直接处理整个波段不分块
内存峰值 = NIR波段(2个) + 当前处理的波段(1个) + 已处理的波段(累积在列表中)
"""
corrected_bands = []
# 获取NIR波段对象用于所有波段的校正
band_640 = self.dataset.GetRasterBand(self.NIR_lower + 1) # GDAL波段从1开始
band_750 = self.dataset.GetRasterBand(self.NIR_upper + 1)
# 先读取NIR波段用于所有波段的校正会一直保存在内存中
R_640 = band_640.ReadAsArray().astype(np.float32)
R_750 = band_750.ReadAsArray().astype(np.float32)
diff_640_750 = R_640 - R_750
# 获取水域掩膜
water_mask_bool = self.water_mask.astype(bool) if self.water_mask is not None else None
# 逐波段处理:每次只读取和处理一个波段
for i in tqdm(range(self.n_bands), desc="处理波段 (GDAL)", total=self.n_bands):
# 读取当前波段(只加载一个波段到内存)
current_band = self.dataset.GetRasterBand(i + 1)
R = current_band.ReadAsArray().astype(np.float32)
# 校正计算
corrected_band = R - R_750 + self.A + self.B * diff_640_750
np.maximum(corrected_band, 0, out=corrected_band)
# 如果存在水域掩膜,只对水域区域应用校正
if water_mask_bool is not None:
corrected_band = np.where(water_mask_bool, corrected_band, R)
# 添加到结果列表corrected_band会保留在列表中
corrected_bands.append(corrected_band)
# 释放当前波段数据(显式删除有助于及时释放内存)
del R
return corrected_bands
def _get_corrected_bands_gdal_mem(self):
"""使用GDAL内存驱动处理numpy数组逐波段处理"""
# 创建内存数据集
driver = gdal.GetDriverByName('MEM')
mem_dataset = driver.Create('', self.width, self.height, self.n_bands, gdal.GDT_Float32)
# 将numpy数组写入内存数据集显示进度
for i in tqdm(range(self.n_bands), desc="加载波段到内存", total=self.n_bands):
band = mem_dataset.GetRasterBand(i + 1)
band.WriteArray(self.im_aligned[:,:,i])
band.FlushCache()
# 临时保存原始dataset引用
original_dataset = self.dataset
self.dataset = mem_dataset
try:
# 使用逐波段处理方法
result = self._get_corrected_bands_gdal()
finally:
# 恢复原始dataset
self.dataset = original_dataset
mem_dataset = None
return result
def _save_corrected_bands(self, corrected_bands):
"""
保存校正后的波段到文件BSQ格式ENVI格式
注意:为了节省内存,直接逐波段写入,不先堆叠成完整数组
:param corrected_bands: 校正后的波段列表
"""
if not GDAL_AVAILABLE:
raise ImportError("GDAL未安装无法保存影像文件")
if self.output_path is None:
return
import os
# 确保输出目录存在
output_dir = os.path.dirname(self.output_path)
if output_dir and not os.path.exists(output_dir):
os.makedirs(output_dir, exist_ok=True)
# 从第一个波段获取尺寸信息(避免堆叠所有波段)
if not corrected_bands:
raise ValueError("校正后的波段列表为空")
first_band = corrected_bands[0]
height, width = first_band.shape
n_bands = len(corrected_bands)
# 获取地理变换和投影信息
if self.is_file_path and self.dataset is not None:
geotransform = self.dataset.GetGeoTransform()
projection = self.dataset.GetProjection()
else:
# 如果没有地理信息,使用默认值
geotransform = (0, 1, 0, 0, 0, -1)
projection = ""
# 强制使用ENVI格式BSQ格式确保文件扩展名为.bsq
base_path, ext = os.path.splitext(self.output_path)
# 如果扩展名不是.bsq使用基础路径添加.bsq
if ext.lower() != '.bsq':
bsq_path = base_path + '.bsq'
else:
bsq_path = self.output_path
# 使用ENVI驱动默认就是BSQ格式
driver = gdal.GetDriverByName('ENVI')
if driver is None:
raise ValueError("无法创建ENVI格式文件ENVI驱动不可用")
# 创建ENVI格式数据集会自动生成.hdr文件
dataset = driver.Create(bsq_path, width, height, n_bands, gdal.GDT_Float32)
if dataset is None:
raise ValueError(f"无法创建输出文件: {bsq_path}")
try:
# 设置地理变换和投影
if geotransform:
dataset.SetGeoTransform(geotransform)
if projection:
dataset.SetProjection(projection)
# 直接逐波段写入(不先堆叠,节省内存)
for i in tqdm(range(n_bands), desc="保存波段", total=n_bands):
band = dataset.GetRasterBand(i + 1)
# 直接从列表中获取波段并写入,避免创建完整数组
band.WriteArray(corrected_bands[i])
band.FlushCache()
finally:
dataset = None
# 检查.hdr文件是否已创建
hdr_path = bsq_path + '.hdr'
if os.path.exists(hdr_path):
print(f"校正后的图像已保存至: {bsq_path} (BSQ格式)")
print(f"头文件已保存至: {hdr_path}")
else:
print(f"校正后的图像已保存至: {bsq_path} (BSQ格式)")
print(f"警告: 未检测到.hdr文件但GDAL应该已自动创建")
def get_corrected_bands(self):
"""
获取校正后的波段
根据输入类型和大小自动选择最优处理方法
:return: 校正后的波段列表
"""
# 如果输入是文件路径使用GDAL直接读取
if self.is_file_path:
if self.use_gdal:
corrected_bands = self._get_corrected_bands_gdal()
else:
raise ValueError("输入为文件路径时必须安装GDAL")
else:
# 如果输入是numpy数组
if self.use_gdal and self.height * self.width * self.n_bands > 100000000:
# 大图像使用GDAL内存驱动逐波段处理
corrected_bands = self._get_corrected_bands_gdal_mem()
else:
# 小图像使用numpy直接处理
corrected_bands = self._get_corrected_bands_numpy()
# 如果提供了输出路径,保存结果
if self.output_path is not None:
self._save_corrected_bands(corrected_bands)
return corrected_bands
def __del__(self):
"""清理资源"""
if self.dataset is not None and self.is_file_path:
self.dataset = None

View File

@ -0,0 +1,290 @@
import numpy as np
# import preprocessing
import os
try:
from osgeo import gdal
GDAL_AVAILABLE = True
except ImportError:
GDAL_AVAILABLE = False
class Hedley:
def __init__(self, im_aligned, shp_path=None, NIR_band = 47, water_mask=None, output_path=None):
"""
:param im_aligned (np.ndarray): band aligned and calibrated & corrected reflectance image
:param shp_path (str, optional): path to shapefile (.shp) defining the region containing the glint region in deep water.
If None, uses the entire image. The shapefile can use pixel coordinates or geographic coordinates.
:param NIR_band (int): band index for NIR band which corresponds to 842.36nm, which corresponds closely to the NIR band in Micasense
:param water_mask (np.ndarray or str or None): 水域掩膜1表示水域0表示非水域
可以是numpy数组、栅格文件路径(.dat/.tif)或shapefile路径(.shp)
如果为None则处理全图
:param output_path (str or None): 输出文件路径,如果提供则保存校正后的图像
如果为None则不保存
"""
self.im_aligned = im_aligned
self.bbox = self._read_shp_to_bbox(shp_path) if shp_path else None
self.NIR_band = NIR_band
self.n_bands = im_aligned.shape[-1]
self.height = im_aligned.shape[0]
self.width = im_aligned.shape[1]
self.output_path = output_path
# 加载水域掩膜
self.water_mask = self._load_water_mask(water_mask)
# 使用ravel()而不是flatten(),避免不必要的复制
# 如果存在水域掩膜只在掩膜内计算R_min
if self.water_mask is not None:
nir_band_masked = self.im_aligned[:,:,self.NIR_band][self.water_mask.astype(bool)]
self.R_min = np.percentile(nir_band_masked, 5, interpolation='nearest') if nir_band_masked.size > 0 else 0
else:
self.R_min = np.percentile(self.im_aligned[:,:,self.NIR_band].ravel(), 5, interpolation='nearest')
def _read_shp_to_bbox(self, shp_path):
"""
读取shapefile并提取边界框
:param shp_path (str): shapefile文件路径
:return: tuple: ((x1,y1),(x2,y2)), where x1,y1 is the upper left corner, x2,y2 is the lower right corner
"""
if not os.path.exists(shp_path):
raise FileNotFoundError(f"Shapefile not found: {shp_path}")
try:
try:
import geopandas as gpd
gdf = gpd.read_file(shp_path)
# 获取所有几何体的总边界框
bounds = gdf.total_bounds # [minx, miny, maxx, maxy]
min_x, min_y, max_x, max_y = bounds
except ImportError:
# 如果geopandas不可用尝试使用fiona
import fiona
from shapely.geometry import shape
min_x = float('inf')
min_y = float('inf')
max_x = float('-inf')
max_y = float('-inf')
with fiona.open(shp_path) as shp:
for feature in shp:
geom = shape(feature['geometry'])
if geom:
bounds = geom.bounds
min_x = min(min_x, bounds[0])
min_y = min(min_y, bounds[1])
max_x = max(max_x, bounds[2])
max_y = max(max_y, bounds[3])
# 转换为整数像素坐标
x1 = max(0, int(min_x))
y1 = max(0, int(min_y))
x2 = min(self.im_aligned.shape[1], int(max_x) + 1)
y2 = min(self.im_aligned.shape[0], int(max_y) + 1)
return ((x1, y1), (x2, y2))
except Exception as e:
raise ValueError(f"Error reading shapefile {shp_path}: {e}")
def _load_water_mask(self, water_mask):
"""
加载水域掩膜
:param water_mask: 可以是None、numpy数组、文件路径(.dat/.tif)或shapefile路径(.shp)
:return: numpy数组或None1表示水域0表示非水域
"""
if water_mask is None:
return None
# 如果已经是numpy数组
if isinstance(water_mask, np.ndarray):
if water_mask.shape[:2] != (self.height, self.width):
raise ValueError(f"掩膜尺寸 {water_mask.shape[:2]} 与图像尺寸 {(self.height, self.width)} 不匹配")
return (water_mask > 0).astype(np.uint8) # 确保是0/1掩膜
# 如果是文件路径
if isinstance(water_mask, str):
try:
from osgeo import gdal, ogr
except ImportError:
raise ValueError("使用文件路径作为掩膜时必须安装GDAL")
# 检查是否为shapefile
if water_mask.lower().endswith('.shp'):
# 从shp文件创建掩膜需要参考图像这里假设使用im_aligned的尺寸
# 注意如果输入是numpy数组无法从shp创建掩膜需要提供栅格参考
raise ValueError("Hedley类输入为numpy数组时无法从shp文件创建掩膜。请先栅格化shp文件或提供numpy数组掩膜")
else:
# 栅格文件
mask_dataset = gdal.Open(water_mask, gdal.GA_ReadOnly)
if mask_dataset is None:
raise ValueError(f"无法打开掩膜文件: {water_mask}")
mask_array = mask_dataset.GetRasterBand(1).ReadAsArray()
mask_dataset = None
if mask_array.shape != (self.height, self.width):
raise ValueError(f"掩膜尺寸 {mask_array.shape} 与图像尺寸 {(self.height, self.width)} 不匹配")
return (mask_array > 0).astype(np.uint8)
raise ValueError(f"不支持的掩膜类型: {type(water_mask)}")
def covariance_NIR(self,NIR,b):
"""
NIR & b are vectors
reflectance for band i
"""
n = len(NIR)
# 优化减少重复计算使用更高效的numpy操作
nir_mean = np.mean(NIR)
b_mean = np.mean(b)
# 使用更高效的协方差计算
pij = np.mean((NIR - nir_mean) * (b - b_mean))
pjj = np.mean((NIR - nir_mean) ** 2)
# 避免除零错误
return pij / pjj if pjj != 0 else 0.0
def correlation_bands_reflectance(self):
"""
calculate correlation between NIR and other bands for reflectance
NIR_band is 750 nm
"""
# If bbox is None, use the entire image
if self.bbox is None:
# 使用ravel()而不是flatten(),避免不必要的复制
# 直接使用视图,只在需要时创建扁平数组
im_region = self.im_aligned
mask_region = self.water_mask
else:
((x1,y1),(x2,y2)) = self.bbox
im_region = self.im_aligned[y1:y2,x1:x2,:]
mask_region = self.water_mask[y1:y2,x1:x2] if self.water_mask is not None else None
# 如果存在水域掩膜,只在掩膜内计算相关性
if mask_region is not None:
mask_bool = mask_region.astype(bool)
if mask_bool.any():
# 只在掩膜内提取数据
NIR_reflectance = im_region[:,:,self.NIR_band][mask_bool]
else:
# 如果掩膜内没有有效像素,使用全区域
NIR_reflectance = im_region[:,:,self.NIR_band].ravel()
mask_bool = None
else:
NIR_reflectance = im_region[:,:,self.NIR_band].ravel()
mask_bool = None
# 优化:一次性计算所有波段的相关性,减少循环开销
corr_list = []
for v in range(self.n_bands):
if mask_bool is not None and mask_bool.any():
band_reflectance = im_region[:,:,v][mask_bool]
else:
band_reflectance = im_region[:,:,v].ravel()
corr = self.covariance_NIR(NIR_reflectance, band_reflectance)
corr_list.append(corr)
return corr_list
def _save_corrected_bands(self, corrected_bands):
"""
保存校正后的波段到文件BSQ格式ENVI格式
:param corrected_bands: 校正后的波段列表
"""
if not GDAL_AVAILABLE:
raise ImportError("GDAL未安装无法保存影像文件")
if self.output_path is None:
return
# 确保输出目录存在
output_dir = os.path.dirname(self.output_path)
if output_dir and not os.path.exists(output_dir):
os.makedirs(output_dir, exist_ok=True)
# 将波段列表转换为数组
corrected_array = np.stack(corrected_bands, axis=2)
# 如果没有地理信息,使用默认值
geotransform = (0, 1, 0, 0, 0, -1)
projection = ""
# 强制使用ENVI格式BSQ格式确保文件扩展名为.bsq
base_path, ext = os.path.splitext(self.output_path)
# 如果扩展名不是.bsq使用基础路径添加.bsq
if ext.lower() != '.bsq':
bsq_path = base_path + '.bsq'
else:
bsq_path = self.output_path
# 使用ENVI驱动默认就是BSQ格式
driver = gdal.GetDriverByName('ENVI')
if driver is None:
raise ValueError("无法创建ENVI格式文件ENVI驱动不可用")
height, width, n_bands = corrected_array.shape
# 创建ENVI格式数据集会自动生成.hdr文件
dataset = driver.Create(bsq_path, width, height, n_bands, gdal.GDT_Float32)
if dataset is None:
raise ValueError(f"无法创建输出文件: {bsq_path}")
try:
# 设置地理变换和投影
if geotransform:
dataset.SetGeoTransform(geotransform)
if projection:
dataset.SetProjection(projection)
# 写入每个波段BSQ格式按波段顺序存储
for i in range(n_bands):
band = dataset.GetRasterBand(i + 1)
band.WriteArray(corrected_array[:, :, i])
band.FlushCache()
finally:
dataset = None
# 检查.hdr文件是否已创建
hdr_path = bsq_path + '.hdr'
if os.path.exists(hdr_path):
print(f"校正后的图像已保存至: {bsq_path} (BSQ格式)")
print(f"头文件已保存至: {hdr_path}")
else:
print(f"校正后的图像已保存至: {bsq_path} (BSQ格式)")
print(f"警告: 未检测到.hdr文件但GDAL应该已自动创建")
def get_corrected_bands(self):
"""
correction is done in reflectance
:return: 校正后的波段列表
"""
corr = self.correlation_bands_reflectance()
NIR_reflectance = self.im_aligned[:,:,self.NIR_band]
# 预计算NIR-R_min避免在循环中重复计算
NIR_diff = NIR_reflectance - self.R_min
# 获取水域掩膜(如果存在)
water_mask_bool = self.water_mask.astype(bool) if self.water_mask is not None else None
corrected_bands = []
for band_number in range(self.n_bands): #iterate across bands
b = corr[band_number]
R = self.im_aligned[:,:,band_number]
# 优化:减少中间数组创建
corrected_band = R - b * NIR_diff
# 如果存在水域掩膜,只对水域区域应用校正
if water_mask_bool is not None:
corrected_band = np.where(water_mask_bool, corrected_band, R)
corrected_bands.append(corrected_band)
# 如果提供了输出路径,保存结果
if self.output_path is not None:
self._save_corrected_bands(corrected_bands)
return corrected_bands

View File

@ -0,0 +1,313 @@
import numpy as np
# import preprocessing
import os
try:
from osgeo import gdal
GDAL_AVAILABLE = True
except ImportError:
GDAL_AVAILABLE = False
class Kutser:
def __init__(self, im_aligned, shp_path=None, oxy_band = 38,lower_oxy = 36, upper_oxy = 49, NIR_band = 47, water_mask=None, output_path=None):
"""
:param im_aligned (np.ndarray): band aligned and calibrated & corrected reflectance image
:param shp_path (str, optional): path to shapefile (.shp) defining the region containing the glint region in deep water.
If None, uses the entire image. The shapefile can use pixel coordinates or geographic coordinates.
:param oxy_band (int): band index for oxygen absorption band, which corresponds to 760.6nm
:param lower_oxy (int): band index for outside oxygen absorption band, which corresponds to 742.39nm
:param upper_oxy (int): band index for outside oxygen absorption band, which corresponds to 860.48nm
see Kutser, Vahtmäe and Praks
:param water_mask (np.ndarray or str or None): 水域掩膜1表示水域0表示非水域
可以是numpy数组、栅格文件路径(.dat/.tif)或shapefile路径(.shp)
如果为None则处理全图
:param output_path (str or None): 输出文件路径,如果提供则保存校正后的图像
如果为None则不保存
"""
self.im_aligned = im_aligned
self.bbox = self._read_shp_to_bbox(shp_path) if shp_path else None
self.oxy_band = oxy_band
self.lower_oxy = lower_oxy
self.upper_oxy = upper_oxy
self.NIR_band = NIR_band
self.n_bands = im_aligned.shape[-1]
self.height = im_aligned.shape[0]
self.width = im_aligned.shape[1]
self.output_path = output_path
# 加载水域掩膜
self.water_mask = self._load_water_mask(water_mask)
# 使用ravel()而不是flatten(),避免不必要的复制
# 如果存在水域掩膜只在掩膜内计算R_min
if self.water_mask is not None:
nir_band_masked = self.im_aligned[:,:,self.NIR_band][self.water_mask.astype(bool)]
self.R_min = np.percentile(nir_band_masked, 5, interpolation='nearest') if nir_band_masked.size > 0 else 0
else:
self.R_min = np.percentile(self.im_aligned[:,:,self.NIR_band].ravel(), 5, interpolation='nearest')
def _read_shp_to_bbox(self, shp_path):
"""
读取shapefile并提取边界框
:param shp_path (str): shapefile文件路径
:return: tuple: ((x1,y1),(x2,y2)), where x1,y1 is the upper left corner, x2,y2 is the lower right corner
"""
if not os.path.exists(shp_path):
raise FileNotFoundError(f"Shapefile not found: {shp_path}")
try:
try:
import geopandas as gpd
gdf = gpd.read_file(shp_path)
# 获取所有几何体的总边界框
bounds = gdf.total_bounds # [minx, miny, maxx, maxy]
min_x, min_y, max_x, max_y = bounds
except ImportError:
# 如果geopandas不可用尝试使用fiona
import fiona
from shapely.geometry import shape
min_x = float('inf')
min_y = float('inf')
max_x = float('-inf')
max_y = float('-inf')
with fiona.open(shp_path) as shp:
for feature in shp:
geom = shape(feature['geometry'])
if geom:
bounds = geom.bounds
min_x = min(min_x, bounds[0])
min_y = min(min_y, bounds[1])
max_x = max(max_x, bounds[2])
max_y = max(max_y, bounds[3])
# 转换为整数像素坐标
x1 = max(0, int(min_x))
y1 = max(0, int(min_y))
x2 = min(self.im_aligned.shape[1], int(max_x) + 1)
y2 = min(self.im_aligned.shape[0], int(max_y) + 1)
return ((x1, y1), (x2, y2))
except Exception as e:
raise ValueError(f"Error reading shapefile {shp_path}: {e}")
def _load_water_mask(self, water_mask):
"""
加载水域掩膜
:param water_mask: 可以是None、numpy数组、文件路径(.dat/.tif)或shapefile路径(.shp)
:return: numpy数组或None1表示水域0表示非水域
"""
if water_mask is None:
return None
# 如果已经是numpy数组
if isinstance(water_mask, np.ndarray):
if water_mask.shape[:2] != (self.height, self.width):
raise ValueError(f"掩膜尺寸 {water_mask.shape[:2]} 与图像尺寸 {(self.height, self.width)} 不匹配")
return (water_mask > 0).astype(np.uint8) # 确保是0/1掩膜
# 如果是文件路径
if isinstance(water_mask, str):
try:
from osgeo import gdal, ogr
except ImportError:
raise ValueError("使用文件路径作为掩膜时必须安装GDAL")
# 检查是否为shapefile
if water_mask.lower().endswith('.shp'):
# 从shp文件创建掩膜需要参考图像这里假设使用im_aligned的尺寸
# 注意如果输入是numpy数组无法从shp创建掩膜需要提供栅格参考
raise ValueError("Kutser类输入为numpy数组时无法从shp文件创建掩膜。请先栅格化shp文件或提供numpy数组掩膜")
else:
# 栅格文件
mask_dataset = gdal.Open(water_mask, gdal.GA_ReadOnly)
if mask_dataset is None:
raise ValueError(f"无法打开掩膜文件: {water_mask}")
mask_array = mask_dataset.GetRasterBand(1).ReadAsArray()
mask_dataset = None
if mask_array.shape != (self.height, self.width):
raise ValueError(f"掩膜尺寸 {mask_array.shape} 与图像尺寸 {(self.height, self.width)} 不匹配")
return (mask_array > 0).astype(np.uint8)
raise ValueError(f"不支持的掩膜类型: {type(water_mask)}")
def get_depth_D(self):
"""
Assume the amount of glint is proportional to the depth of the oxygen absorption feature, D
returns the normalised D by dividing it by the maximum D found in a deep water region
"""
# 优化:减少中间数组创建,使用更高效的计算
lower_oxy_band = self.im_aligned[:,:,self.lower_oxy]
upper_oxy_band = self.im_aligned[:,:,self.upper_oxy]
oxy_band = self.im_aligned[:,:,self.oxy_band]
D = (lower_oxy_band + upper_oxy_band) * 0.5 - oxy_band
# 确定用于计算D_max的区域
if self.bbox is None:
search_region = D
else:
((x1,y1),(x2,y2)) = self.bbox
search_region = D[y1:y2,x1:x2]
# 如果存在水域掩膜,只在掩膜内搜索最大值
if self.water_mask is not None:
if self.bbox is None:
mask_region = self.water_mask.astype(bool)
else:
((x1,y1),(x2,y2)) = self.bbox
mask_region = self.water_mask[y1:y2,x1:x2].astype(bool)
if mask_region.any():
D_max = search_region[mask_region].max()
else:
D_max = search_region.max()
else:
D_max = search_region.max() # assumed to be the maximum glint value
# 避免除零错误
if D_max == 0:
return np.zeros_like(D)
return D / D_max
def get_glint_G(self):
"""
The spectral variation of glint G is found by subtracting the spectrum at the darkest (ie. lowest D) NIR deep-water pixel from the brightest
returns G as a function of wavelength
"""
# If bbox is None, use the entire image
if self.bbox is None:
im_region = self.im_aligned
mask_region = self.water_mask
else:
((x1,y1),(x2,y2)) = self.bbox
im_region = self.im_aligned[y1:y2,x1:x2,:]
mask_region = self.water_mask[y1:y2,x1:x2] if self.water_mask is not None else None
# 如果存在水域掩膜,只在掩膜内计算最大最小值
if mask_region is not None:
mask_bool = mask_region.astype(bool)
if mask_bool.any():
# 对每个波段,只在掩膜内计算最大最小值
G_list = []
for i in range(self.n_bands):
band_data = im_region[:,:,i]
G_max = band_data[mask_bool].max()
G_min = band_data[mask_bool].min()
G_list.append(G_max - G_min)
else:
# 如果掩膜内没有有效像素,使用全区域
G_max = np.amax(im_region, axis=(0, 1))
G_min = np.amin(im_region, axis=(0, 1))
G_list = (G_max - G_min).tolist()
else:
# 优化:一次性计算所有波段的最大最小值,减少循环开销
# 使用numpy的amax和amin沿最后一个轴计算
G_max = np.amax(im_region, axis=(0, 1)) # 沿空间维度计算最大值
G_min = np.amin(im_region, axis=(0, 1)) # 沿空间维度计算最小值
G_list = (G_max - G_min).tolist()
return G_list
def _save_corrected_bands(self, corrected_bands):
"""
保存校正后的波段到文件BSQ格式ENVI格式
:param corrected_bands: 校正后的波段列表
"""
if not GDAL_AVAILABLE:
raise ImportError("GDAL未安装无法保存影像文件")
if self.output_path is None:
return
# 确保输出目录存在
output_dir = os.path.dirname(self.output_path)
if output_dir and not os.path.exists(output_dir):
os.makedirs(output_dir, exist_ok=True)
# 将波段列表转换为数组
corrected_array = np.stack(corrected_bands, axis=2)
# 如果没有地理信息,使用默认值
geotransform = (0, 1, 0, 0, 0, -1)
projection = ""
# 强制使用ENVI格式BSQ格式确保文件扩展名为.bsq
base_path, ext = os.path.splitext(self.output_path)
# 如果扩展名不是.bsq使用基础路径添加.bsq
if ext.lower() != '.bsq':
bsq_path = base_path + '.bsq'
else:
bsq_path = self.output_path
# 使用ENVI驱动默认就是BSQ格式
driver = gdal.GetDriverByName('ENVI')
if driver is None:
raise ValueError("无法创建ENVI格式文件ENVI驱动不可用")
height, width, n_bands = corrected_array.shape
# 创建ENVI格式数据集会自动生成.hdr文件
dataset = driver.Create(bsq_path, width, height, n_bands, gdal.GDT_Float32)
if dataset is None:
raise ValueError(f"无法创建输出文件: {bsq_path}")
try:
# 设置地理变换和投影
if geotransform:
dataset.SetGeoTransform(geotransform)
if projection:
dataset.SetProjection(projection)
# 写入每个波段BSQ格式按波段顺序存储
for i in range(n_bands):
band = dataset.GetRasterBand(i + 1)
band.WriteArray(corrected_array[:, :, i])
band.FlushCache()
finally:
dataset = None
# 检查.hdr文件是否已创建
hdr_path = bsq_path + '.hdr'
if os.path.exists(hdr_path):
print(f"校正后的图像已保存至: {bsq_path} (BSQ格式)")
print(f"头文件已保存至: {hdr_path}")
else:
print(f"校正后的图像已保存至: {bsq_path} (BSQ格式)")
print(f"警告: 未检测到.hdr文件但GDAL应该已自动创建")
def get_corrected_bands(self):
"""
correction is done in reflectance
:return: 校正后的波段列表
"""
g_list = self.get_glint_G()
D = self.get_depth_D()
# 获取水域掩膜(如果存在)
water_mask_bool = self.water_mask.astype(bool) if self.water_mask is not None else None
corrected_bands = []
for band_number in range(self.n_bands): #iterate across bands
G = g_list[band_number]
R = self.im_aligned[:,:,band_number]
# 优化:减少中间数组创建,直接计算
corrected_band = R - G * D
# 如果存在水域掩膜,只对水域区域应用校正
if water_mask_bool is not None:
corrected_band = np.where(water_mask_bool, corrected_band, R)
corrected_bands.append(corrected_band)
# 如果提供了输出路径,保存结果
if self.output_path is not None:
self._save_corrected_bands(corrected_bands)
return corrected_bands

View File

@ -0,0 +1,572 @@
import cv2
import os
import numpy as np
from scipy import ndimage
from scipy.optimize import minimize_scalar
try:
from osgeo import gdal
GDAL_AVAILABLE = True
except ImportError:
GDAL_AVAILABLE = False
# SUn-Glint-Aware Restoration (SUGAR):A sweet and simple algorithm for correcting sunglint
class SUGAR:
def __init__(self, im_aligned,bounds=[(1,2)],sigma=1,estimate_background=True, glint_mask_method="cdf", water_mask=None, output_path=None):
"""
:param im_aligned (np.ndarray): band aligned and calibrated & corrected reflectance image
:param bounds (a list of tuple): lower and upper bound for optimisation of b for each band
:param sigma (float): smoothing sigma for LoG
:param estimate_background (bool): whether to estimate background spectra using median filtering
:param glint_mask_method (str): choose either "cdf" or "otsu", "cdf" is set as the default
:param water_mask (np.ndarray or str or None): 水域掩膜1表示水域0表示非水域
可以是numpy数组、栅格文件路径(.dat/.tif)或shapefile路径(.shp)
如果为None则处理全图
:param output_path (str or None): 输出文件路径,如果提供则保存校正后的图像
如果为None则不保存
"""
self.im_aligned = im_aligned
self.sigma = sigma
self.estimate_background = estimate_background
self.n_bands = im_aligned.shape[-1]
self.bounds = bounds*self.n_bands
self.glint_mask_method = glint_mask_method
self.height = im_aligned.shape[0]
self.width = im_aligned.shape[1]
self.output_path = output_path
# 加载水域掩膜
self.water_mask = self._load_water_mask(water_mask)
def _load_water_mask(self, water_mask):
"""
加载水域掩膜
:param water_mask: 可以是None、numpy数组、文件路径(.dat/.tif)或shapefile路径(.shp)
:return: numpy数组或None1表示水域0表示非水域
"""
if water_mask is None:
return None
# 如果已经是numpy数组
if isinstance(water_mask, np.ndarray):
if water_mask.shape[:2] != (self.height, self.width):
raise ValueError(f"掩膜尺寸 {water_mask.shape[:2]} 与图像尺寸 {(self.height, self.width)} 不匹配")
return (water_mask > 0).astype(np.uint8) # 确保是0/1掩膜
# 如果是文件路径
if isinstance(water_mask, str):
try:
from osgeo import gdal, ogr
except ImportError:
raise ValueError("使用文件路径作为掩膜时必须安装GDAL")
# 检查是否为shapefile
if water_mask.lower().endswith('.shp'):
# 从shp文件创建掩膜需要参考图像这里假设使用im_aligned的尺寸
# 注意如果输入是numpy数组无法从shp创建掩膜需要提供栅格参考
raise ValueError("SUGAR类输入为numpy数组时无法从shp文件创建掩膜。请先栅格化shp文件或提供numpy数组掩膜")
else:
# 栅格文件
mask_dataset = gdal.Open(water_mask, gdal.GA_ReadOnly)
if mask_dataset is None:
raise ValueError(f"无法打开掩膜文件: {water_mask}")
mask_array = mask_dataset.GetRasterBand(1).ReadAsArray()
mask_dataset = None
if mask_array.shape != (self.height, self.width):
raise ValueError(f"掩膜尺寸 {mask_array.shape} 与图像尺寸 {(self.height, self.width)} 不匹配")
return (mask_array > 0).astype(np.uint8)
raise ValueError(f"不支持的掩膜类型: {type(water_mask)}")
def otsu_thresholding(self,im):
"""
:param im (np.ndarray) of shape mxn. Note that it is the LoG of image
otsu thresholding with Brent's minimisation of a univariate function
returns the value of the threshold for input
"""
auto_bins = int(0.005*im.shape[0]*im.shape[1])
# 使用ravel()而不是flatten(),避免不必要的复制(如果可能)
# 如果存在无效值如NaN或极大值过滤掉它们
im_flat = im.ravel()
# 过滤掉NaN和无穷大值
valid_mask = np.isfinite(im_flat)
if not valid_mask.all():
im_flat = im_flat[valid_mask]
count, bin_edges = np.histogram(im_flat, bins=auto_bins)
bin = (bin_edges[:-1] + bin_edges[1:]) * 0.5 # bin centers使用乘法替代除法
count_sum = count.sum()
hist_norm = count / count_sum # normalised histogram
Q = hist_norm.cumsum() # CDF function ranges from 0 to 1
N = count.shape[0]
N_negative = np.sum(bin < 0)
bins = np.arange(N, dtype=np.float32) # 使用float32减少内存
def otsu_thresh(x):
x = int(x)
# 使用切片而不是hsplit避免创建新数组
p1 = hist_norm[:x]
p2 = hist_norm[x:]
q1 = Q[x]
q2 = Q[N-1] - Q[x]
b1 = bins[:x]
b2 = bins[x:]
# finding means and variances
m1 = np.sum(p1 * b1) / q1 if q1 > 0 else 0
m2 = np.sum(p2 * b2) / q2 if q2 > 0 else 0
v1 = np.sum(((b1 - m1) ** 2) * p1) / q1 if q1 > 0 else 0
v2 = np.sum(((b2 - m2) ** 2) * p2) / q2 if q2 > 0 else 0
# calculates the minimization function
fn = v1 * q1 + v2 * q2
return fn
# brent method is used to minimise an univariate function
# bounded minimisation
# we can just limit the search to negative values since we know thresh should be negative as L<0 for glint pixels
if N_negative <= 1:
# 如果没有足够的负值,使用默认阈值
return bin[np.argmax(count)]
res = minimize_scalar(otsu_thresh, bounds=(1, N_negative), method='bounded')
thresh = bin[int(res.x)]
return thresh
# def cdf_thresholding(self,im, percentile=0.05):
# """
# :param im (np.ndarray) of shape mxn
# :param percentile (float): lower and upper percentile values are potential glint pixels
# """
# lower_perc = percentile
# upper_perc = 1-percentile
# im_flatten = im.flatten()
# H,X1 = np.histogram(im_flatten, bins = int(0.005*im.shape[0]*im.shape[1]), density=True )
# dx = X1[1] - X1[0]
# F1 = np.cumsum(H)*dx
# F_lower = X1[1:][F1<lower_perc]
# F_upper = X1[1:][F1>upper_perc]
# while((F_lower.size == 0) or (F_upper.size == 0)):
# if (F_lower.size == 0):
# lower_perc += 0.01
# F_lower = X1[1:][F1<lower_perc]
# if (F_upper.size == 0):
# upper_perc -= 0.01
# F_upper = X1[1:][F1>upper_perc]
# lower_thresh = F_lower[-1]
# upper_thresh = F_upper[0]
# return lower_thresh,upper_thresh
def cdf_thresholding(self,im,auto_bins=10):
"""
:param im (np.ndarray) of shape mxn. Note that it is the LoG of image
:param percentile (float): lower and upper percentile values are potential glint pixels
"""
# 使用ravel()而不是flatten(),避免不必要的复制
im_flat = im.ravel()
# 过滤掉NaN和无穷大值
valid_mask = np.isfinite(im_flat)
if not valid_mask.all():
im_flat = im_flat[valid_mask]
count, bin_edges = np.histogram(im_flat, bins=auto_bins)
bin = (bin_edges[:-1] + bin_edges[1:]) * 0.5 # bin centers使用乘法替代除法
thresh = bin[np.argmax(count)]
return thresh
def glint_list(self):
"""
returns a list of np.ndarray, where each item is an extracted glint for each band based on get_glint_mask
"""
glint_mask = self.glint_mask_list()
extracted_glint_list = []
for i in range(self.im_aligned.shape[-1]):
gm = glint_mask[i]
extracted_glint = gm*self.im_aligned[:,:,i]
extracted_glint_list.append(extracted_glint)
return extracted_glint_list
def glint_mask_list(self):
"""
get glint mask using laplacian of gaussian image.
returns a list of np.ndarray
"""
glint_mask_list = []
for i in range(self.im_aligned.shape[-1]):
glint_mask = self.get_glint_mask(self.im_aligned[:,:,i])
glint_mask_list.append(glint_mask)
return glint_mask_list
def log_image_list(self):
"""
get Laplacian of Gaussian (LoG) images for all bands.
returns a list of np.ndarray
"""
log_image_list = []
for i in range(self.im_aligned.shape[-1]):
log_im = self.get_log_image(self.im_aligned[:,:,i])
log_image_list.append(log_im)
return log_image_list
def get_log_image(self, im):
"""
get Laplacian of Gaussian (LoG) image for a single band.
returns a np.ndarray
"""
LoG_im = ndimage.gaussian_laplace(im, sigma=self.sigma)
return LoG_im
def get_glint_mask(self,im):
"""
get glint mask using laplacian of gaussian image.
We assume that water constituents and features follow a smooth continuum,
but glint pixels vary a lot spatially and in intensities
Note that for very extensive glint, this method may not work as well <--:TODO use U-net to identify glint mask
returns a np.ndarray
"""
LoG_im = ndimage.gaussian_laplace(im,sigma=self.sigma)
# 如果存在水域掩膜,只在掩膜内计算阈值
if self.water_mask is not None:
mask_bool = self.water_mask.astype(bool)
if mask_bool.any():
# 只在掩膜内提取LoG值用于阈值计算
LoG_masked = LoG_im[mask_bool]
# 将非掩膜区域设为极大值,确保不影响阈值计算
LoG_for_thresh = LoG_im.copy()
LoG_for_thresh[~mask_bool] = LoG_masked.max() + 1
else:
LoG_for_thresh = LoG_im
else:
LoG_for_thresh = LoG_im
#threshold mask
if (self.glint_mask_method == "otsu"):
thresh = self.otsu_thresholding(LoG_for_thresh)
elif (self.glint_mask_method == "cdf"):
thresh = self.cdf_thresholding(LoG_for_thresh)
else:
raise ValueError('Enter only cdf or otsu as glint_mask_method')
# 使用更高效的方式创建mask避免np.where的开销
glint_mask = (LoG_im < thresh).astype(np.uint8)
# 如果存在水域掩膜将非水域区域设为0
if self.water_mask is not None:
glint_mask = glint_mask * self.water_mask
return glint_mask
def get_est_background(self, im,k_size=5):
"""
:param im (np.ndarray): image of a band
estimate background spectra
returns a np.ndarray
"""
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(k_size,k_size))
dst = cv2.erode(im, kernel)
return dst
def optimise_correction_by_band(self,im,glint_mask,R_BG,bounds):
"""
:param im (np.ndarray): image of a band
:param glint_mask (np.ndarray): glint mask, where glint area is 1 and non-glint area is 0
use brent method to get the optimimum b which minimises the variation (i.e. variance) in the entire image
returns regression slope b
"""
# 预计算常量,避免在优化函数中重复计算
glint_mask_bool = glint_mask.astype(bool)
R_BG_flat = R_BG if isinstance(R_BG, (int, float)) else R_BG[glint_mask_bool]
def optimise_b(b):
# 优化计算只在glint区域计算校正
if isinstance(R_BG, (int, float)):
im_corrected = im.copy()
im_corrected[glint_mask_bool] = im[glint_mask_bool] - glint_mask[glint_mask_bool] * (im[glint_mask_bool] / b - R_BG)
else:
im_corrected = im.copy()
im_corrected[glint_mask_bool] = im[glint_mask_bool] - glint_mask[glint_mask_bool] * (im[glint_mask_bool] / b - R_BG[glint_mask_bool])
return np.var(im_corrected)
res = minimize_scalar(optimise_b, bounds=bounds, method='bounded')
return res.x
def divide_and_conquer(self):
"""
instead of computing b_list for each window, use the previous b_list to narrow the bounds,
because of the strong spatial autocorrelation, we know that the b (correction magnitude) cannot diff too much
this can optimise the run time
"""
def optimise_correction(self):
"""
returns a list of slope in band order i.e. 0,1,2,3,4,5,6,7,8,9 through optimisation
"""
b_list = []
glint_mask_list = []
est_background_list = []
for i in range(self.n_bands):
glint_mask = self.get_glint_mask(self.im_aligned[:,:,i])
glint_mask_list.append(glint_mask)
if self.estimate_background is True:
est_background = self.get_est_background(self.im_aligned[:,:,i])
est_background_list.append(est_background)
else:
est_background = np.percentile(self.im_aligned[:,:,i], 5, interpolation='nearest')
est_background_list.append(est_background)
bounds = self.bounds[i]
b = self.optimise_correction_by_band(self.im_aligned[:,:,i],glint_mask,est_background,bounds)
b_list.append(b)
# add attributes
self.b_list = b_list
self.glint_mask = glint_mask_list
self.est_background = est_background_list
return b_list, glint_mask_list, est_background_list
def _save_corrected_bands(self, corrected_bands):
"""
保存校正后的波段到文件BSQ格式ENVI格式
:param corrected_bands: 校正后的波段列表
"""
if not GDAL_AVAILABLE:
raise ImportError("GDAL未安装无法保存影像文件")
if self.output_path is None:
return
# 确保输出目录存在
output_dir = os.path.dirname(self.output_path)
if output_dir and not os.path.exists(output_dir):
os.makedirs(output_dir, exist_ok=True)
# 将波段列表转换为数组
corrected_array = np.stack(corrected_bands, axis=2)
# 如果没有地理信息,使用默认值
geotransform = (0, 1, 0, 0, 0, -1)
projection = ""
# 强制使用ENVI格式BSQ格式确保文件扩展名为.bsq
base_path, ext = os.path.splitext(self.output_path)
# 如果扩展名不是.bsq使用基础路径添加.bsq
if ext.lower() != '.bsq':
bsq_path = base_path + '.bsq'
else:
bsq_path = self.output_path
# 使用ENVI驱动默认就是BSQ格式
driver = gdal.GetDriverByName('ENVI')
if driver is None:
raise ValueError("无法创建ENVI格式文件ENVI驱动不可用")
height, width, n_bands = corrected_array.shape
# 创建ENVI格式数据集会自动生成.hdr文件
dataset = driver.Create(bsq_path, width, height, n_bands, gdal.GDT_Float32)
if dataset is None:
raise ValueError(f"无法创建输出文件: {bsq_path}")
try:
# 设置地理变换和投影
if geotransform:
dataset.SetGeoTransform(geotransform)
if projection:
dataset.SetProjection(projection)
# 写入每个波段BSQ格式按波段顺序存储
for i in range(n_bands):
band = dataset.GetRasterBand(i + 1)
band.WriteArray(corrected_array[:, :, i])
band.FlushCache()
finally:
dataset = None
# 检查.hdr文件是否已创建
hdr_path = bsq_path + '.hdr'
if os.path.exists(hdr_path):
print(f"校正后的图像已保存至: {bsq_path} (BSQ格式)")
print(f"头文件已保存至: {hdr_path}")
else:
print(f"校正后的图像已保存至: {bsq_path} (BSQ格式)")
print(f"警告: 未检测到.hdr文件但GDAL应该已自动创建")
def get_corrected_bands(self):
"""
获取校正后的波段
:return: 校正后的波段列表
"""
corrected_bands = []
# 获取水域掩膜(如果存在)
water_mask_bool = self.water_mask.astype(bool) if self.water_mask is not None else None
for i in range(self.n_bands):
im_band = self.im_aligned[:,:,i]
# 一次性计算mask和background避免重复计算
glint_mask = self.get_glint_mask(im_band)
background = self.get_est_background(im_band, k_size=5)
# 使用视图和原地操作减少内存
im_corrected = im_band.copy()
glint_mask_bool = glint_mask.astype(bool)
im_corrected[glint_mask_bool] = background[glint_mask_bool]
# 如果存在水域掩膜,确保只在水域内应用校正
if water_mask_bool is not None:
# 只在水域掩膜内应用校正
correction_mask = glint_mask_bool & water_mask_bool
im_corrected = np.where(correction_mask, background, im_band)
# 非水域区域保持原值
im_corrected = np.where(water_mask_bool, im_corrected, im_band)
corrected_bands.append(im_corrected)
# 如果提供了输出路径,保存结果
if self.output_path is not None:
self._save_corrected_bands(corrected_bands)
return corrected_bands
def correction_iterative(im_aligned,iter=3,bounds = [(1,2)],estimate_background=True,glint_mask_method="cdf",get_glint_mask=False,termination_thresh = 20, water_mask=None, output_path=None):
"""
:param im_aligned (np.ndarray): band aligned and calibrated & corrected reflectance image
:param iter (int or None): number of iterations to run the sugar algorithm. If None, termination conditions are automatically applied
:param bounds (list of tuples): to limit correction magnitude
:param get_glint_mask (np.ndarray):
:param water_mask (np.ndarray or str or None): 水域掩膜1表示水域0表示非水域
可以是numpy数组、栅格文件路径(.dat/.tif)或shapefile路径(.shp)
如果为None则处理全图
:param output_path (str or None): 输出文件路径,如果提供则保存最后一次迭代的校正结果
如果为None则不保存
conducts iterative correction using SUGAR
"""
glint_image = im_aligned.copy()
corrected_images = []
if iter is None:
# termination conditions
relative_difference = lambda sd0,sd1: sd1/sd0*100
marginal_difference = lambda sd1,sd2: (sd1-sd2)/sd1*100
relative_diff_thresh = marginal_difference_thresh = termination_thresh
sd_og = np.var(im_aligned)
iter_count = 0
sd_next = sd_og # 不需要copy直接使用值
max_iter = 100 # 添加最大迭代次数限制,防止无限循环
while ((relative_difference(sd_og,sd_next) > relative_diff_thresh) and iter_count < max_iter):
# do all the processing here
HM = SUGAR(glint_image,bounds,estimate_background=estimate_background, glint_mask_method=glint_mask_method, water_mask=water_mask)
corrected_bands = HM.get_corrected_bands()
glint_image = np.stack(corrected_bands,axis=2)
sd_temp = np.var(glint_image)
# 只在需要时保存中间结果,减少内存占用
if get_glint_mask or iter_count == 0:
corrected_images.append(glint_image.copy())
else:
corrected_images.append(glint_image) # 最后一次迭代的结果
# save glint_mask
# if iter_count == 0 and get_glint_mask is True:
# glint_mask = np.stack(HM.glint_mask,axis=2)
if (marginal_difference(sd_next,sd_temp)<marginal_difference_thresh):
break
else:
sd_next = sd_temp
#increase count
iter_count += 1
# 如果提供了输出路径,保存最后一次迭代的结果
if output_path is not None and len(corrected_images) > 0:
_save_corrected_image(corrected_images[-1], output_path)
else:
for i in range(iter):
HM = SUGAR(glint_image,bounds,estimate_background=estimate_background, glint_mask_method=glint_mask_method, water_mask=water_mask)
corrected_bands = HM.get_corrected_bands()
glint_image = np.stack(corrected_bands,axis=2)
# 只在最后一次迭代或需要时保存所有结果
if i == iter - 1 or get_glint_mask:
corrected_images.append(glint_image.copy())
else:
# 对于中间迭代,可以只保存引用(但要注意内存管理)
corrected_images.append(glint_image)
# save glint_mask
# if i == 0 and get_glint_mask is True:
# glint_mask = np.stack(HM.glint_mask,axis=2)
# 如果提供了输出路径,保存最后一次迭代的结果
if output_path is not None and len(corrected_images) > 0:
_save_corrected_image(corrected_images[-1], output_path)
return corrected_images
def _save_corrected_image(corrected_image, output_path):
"""
保存校正后的图像到文件用于correction_iterative函数BSQ格式ENVI格式
:param corrected_image: 校正后的图像数组,形状为(height, width, bands)
:param output_path: 输出文件路径
"""
if not GDAL_AVAILABLE:
raise ImportError("GDAL未安装无法保存影像文件")
if output_path is None:
return
# 确保输出目录存在
output_dir = os.path.dirname(output_path)
if output_dir and not os.path.exists(output_dir):
os.makedirs(output_dir, exist_ok=True)
# 如果没有地理信息,使用默认值
geotransform = (0, 1, 0, 0, 0, -1)
projection = ""
# 强制使用ENVI格式BSQ格式确保文件扩展名为.bsq
base_path, ext = os.path.splitext(output_path)
# 如果扩展名不是.bsq使用基础路径添加.bsq
if ext.lower() != '.bsq':
bsq_path = base_path + '.bsq'
else:
bsq_path = output_path
# 使用ENVI驱动默认就是BSQ格式
driver = gdal.GetDriverByName('ENVI')
if driver is None:
raise ValueError("无法创建ENVI格式文件ENVI驱动不可用")
height, width, n_bands = corrected_image.shape
# 创建ENVI格式数据集会自动生成.hdr文件
dataset = driver.Create(bsq_path, width, height, n_bands, gdal.GDT_Float32)
if dataset is None:
raise ValueError(f"无法创建输出文件: {bsq_path}")
try:
# 设置地理变换和投影
if geotransform:
dataset.SetGeoTransform(geotransform)
if projection:
dataset.SetProjection(projection)
# 写入每个波段BSQ格式按波段顺序存储
for i in range(n_bands):
band = dataset.GetRasterBand(i + 1)
band.WriteArray(corrected_image[:, :, i])
band.FlushCache()
finally:
dataset = None
# 检查.hdr文件是否已创建
hdr_path = bsq_path + '.hdr'
if os.path.exists(hdr_path):
print(f"校正后的图像已保存至: {bsq_path} (BSQ格式)")
print(f"头文件已保存至: {hdr_path}")
else:
print(f"校正后的图像已保存至: {bsq_path} (BSQ格式)")
print(f"警告: 未检测到.hdr文件但GDAL应该已自动创建")

View File

@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View File

@ -0,0 +1,926 @@
from osgeo import gdal, osr
import numpy as np
import pandas as pd
import os
import spectral
from math import sin, cos, tan, sqrt, radians
try:
from scipy.ndimage import distance_transform_edt
from scipy.spatial import cKDTree
SCIPY_AVAILABLE = True
except ImportError:
SCIPY_AVAILABLE = False
# 启用GDAL异常处理
osr.UseExceptions()
# WGS84椭球参数
WGS84_A = 6378137.0 # 长半轴(米)
WGS84_F = 1 / 298.257223563 # 扁率
WGS84_E2 = WGS84_F * (2 - WGS84_F) # 第一偏心率平方
WGS84_EP2 = WGS84_E2 / (1 - WGS84_E2) # 第二偏心率平方
UTM_K0 = 0.9996 # UTM比例因子
def pixel_to_geo(pixel_x, pixel_y, geotransform):
"""
像素坐标转换为地图坐标
"""
geo_x = geotransform[0] + pixel_x * geotransform[1] + pixel_y * geotransform[2]
geo_y = geotransform[3] + pixel_x * geotransform[4] + pixel_y * geotransform[5]
return geo_x, geo_y
def prepare_boundary_adjuster(boundary_mask):
"""
为边界掩膜构建辅助结构,用于根据半径调整采样中心
"""
if not SCIPY_AVAILABLE:
print("警告: 未安装SciPy无法根据水体边界自动调整采样点位置。")
return None
if boundary_mask is None:
return None
boundary_bool = boundary_mask > 0
if not np.any(boundary_bool):
print("警告: 边界掩膜中未检测到有效水域,无法调整采样点。")
return None
distance_map = distance_transform_edt(boundary_bool.astype(np.uint8))
return {
'mask': boundary_bool,
'distance_map': distance_map,
'trees': {}
}
def _get_boundary_tree(adjuster, radius):
"""
根据半径获取或构建适用的KDTree
"""
radius_key = float(radius)
if radius_key in adjuster['trees']:
return adjuster['trees'][radius_key]
distance_map = adjuster['distance_map']
valid_positions = np.column_stack(np.where(distance_map >= radius_key))
if valid_positions.size == 0:
adjuster['trees'][radius_key] = None
return None
tree = cKDTree(valid_positions)
adjuster['trees'][radius_key] = (tree, valid_positions)
return adjuster['trees'][radius_key]
def adjust_sampling_center(pixel_x, pixel_y, radius, adjuster):
"""
如果采样半径范围超出水体边界,则将像素向内移动
直至采样区域完全位于水体内部(与边界相切)
"""
if adjuster is None or radius <= 0:
return pixel_x, pixel_y, False
distance_map = adjuster['distance_map']
mask = adjuster['mask']
if pixel_y < 0 or pixel_y >= distance_map.shape[0] or pixel_x < 0 or pixel_x >= distance_map.shape[1]:
return pixel_x, pixel_y, False
if not mask[pixel_y, pixel_x]:
# 当前像素不在水域内,需要移动到最近的合法位置
tree_info = _get_boundary_tree(adjuster, max(radius, 1))
if tree_info is None:
return pixel_x, pixel_y, False
else:
if distance_map[pixel_y, pixel_x] >= radius:
return pixel_x, pixel_y, False
tree_info = _get_boundary_tree(adjuster, radius)
if tree_info is None:
# 没有任何可以容纳该半径的像素,直接返回原位置
return pixel_x, pixel_y, False
tree, valid_positions = tree_info
if tree is None or valid_positions.size == 0:
return pixel_x, pixel_y, False
# 查询附近潜在位置
max_candidates = min(64, len(valid_positions))
distances, indices = tree.query([pixel_y, pixel_x], k=max_candidates)
if np.isscalar(indices):
indices = [int(indices)]
else:
indices = np.atleast_1d(indices).astype(int)
best_candidate = None
best_delta = None
for idx in indices:
cy, cx = valid_positions[idx]
if distance_map[cy, cx] < radius:
continue
delta = distance_map[cy, cx] - radius
center_shift = (cx - pixel_x) ** 2 + (cy - pixel_y) ** 2
score = (abs(delta), center_shift)
if best_candidate is None or score < best_delta:
best_candidate = (cx, cy)
best_delta = score
if best_candidate is None:
# 没有找到满足条件的候选点
return pixel_x, pixel_y, False
return int(best_candidate[0]), int(best_candidate[1]), True
def transform_coordinates(lon, lat, source_srs, target_srs):
"""
坐标系转换
Args:
lon: 经度
lat: 纬度
source_srs: 源坐标系
target_srs: 目标坐标系
Returns:
transformed_lon, transformed_lat: 转换后的坐标
"""
# 创建坐标转换对象
transform = osr.CoordinateTransformation(source_srs, target_srs)
# 执行坐标转换
point = transform.TransformPoint(lon, lat)
return point[0], point[1]
def geo_to_pixel(lon, lat, geotransform, dataset_srs=None):
"""
地理坐标转换为像素坐标
Args:
lon: 经度
lat: 纬度
geotransform: 仿射变换参数
dataset_srs: 数据集的空间参考系统(可选)
Returns:
pixel_x, pixel_y: 像素坐标
"""
# 使用仿射变换的逆变换将地理坐标转换为像素坐标
x_origin = geotransform[0]
y_origin = geotransform[3]
pixel_width = geotransform[1]
pixel_height = geotransform[5]
pixel_x = int((lon - x_origin) / pixel_width)
pixel_y = int((lat - y_origin) / pixel_height)
return pixel_x, pixel_y
def get_pixel_spectrum_batch(dataset, pixel_x_array, pixel_y_array):
"""
批量获取多个像素点的光谱数据(优化版本)
Args:
dataset: GDAL数据集
pixel_x_array: 像素X坐标数组
pixel_y_array: 像素Y坐标数组
Returns:
spectrum_array: 光谱数据数组 (n_points, n_bands)
"""
n_points = len(pixel_x_array)
n_bands = dataset.RasterCount
# 初始化输出数组
spectrum_array = np.zeros((n_points, n_bands), dtype=np.float32)
# 按波段批量读取(更高效)
for band_idx in range(n_bands):
band = dataset.GetRasterBand(band_idx + 1) # GDAL波段索引从1开始
band_data = band.ReadAsArray() # 读取整个波段
# 批量提取像素值
for i in range(n_points):
px, py = int(pixel_x_array[i]), int(pixel_y_array[i])
if 0 <= px < band_data.shape[1] and 0 <= py < band_data.shape[0]:
spectrum_array[i, band_idx] = band_data[py, px]
else:
spectrum_array[i, band_idx] = np.nan
return spectrum_array
def get_average_spectral_in_radius(dataset, center_x, center_y, radius, flare_mask=None, boundary_mask=None):
"""
获取指定半径内的平均光谱,避开耀斑和边界区域
Args:
dataset: GDAL数据集
center_x, center_y: 中心像素坐标
radius: 半径(像素)
flare_mask: 耀斑掩膜数组(可选)
boundary_mask: 边界掩膜数组(可选)
Returns:
平均光谱值数组
"""
num_bands = dataset.RasterCount
# 计算采样区域边界
x_start = max(0, center_x - radius)
x_end = min(dataset.RasterXSize, center_x + radius + 1)
y_start = max(0, center_y - radius)
y_end = min(dataset.RasterYSize, center_y + radius + 1)
# 读取区域数据
width = x_end - x_start
height = y_end - y_start
if width <= 0 or height <= 0:
return np.zeros(num_bands)
# 读取所有波段数据
spectral_data = dataset.ReadAsArray(x_start, y_start, width, height)
if spectral_data is None:
return np.zeros(num_bands)
# 确保数据是3维的 (bands, height, width)
if len(spectral_data.shape) == 2:
spectral_data = spectral_data.reshape(1, spectral_data.shape[0], spectral_data.shape[1])
# 创建圆形掩膜
y_indices, x_indices = np.ogrid[:height, :width]
center_x_local = center_x - x_start
center_y_local = center_y - y_start
# 计算距离掩膜
distance_mask = ((x_indices - center_x_local) ** 2 + (y_indices - center_y_local) ** 2) <= radius ** 2
# 应用耀斑掩膜(如果提供)
if flare_mask is not None:
flare_region = flare_mask[y_start:y_end, x_start:x_end]
if flare_region.shape == distance_mask.shape:
distance_mask = distance_mask & (flare_region == 0) # 假设0表示无耀斑
# 应用边界掩膜(如果提供)
if boundary_mask is not None:
boundary_region = boundary_mask[y_start:y_end, x_start:x_end]
if boundary_region.shape == distance_mask.shape:
distance_mask = distance_mask & (boundary_region == 1) # 假设0表示无边界
# 计算平均光谱
average_spectrum = np.zeros(num_bands)
valid_pixels = np.sum(distance_mask)
if valid_pixels > 0:
for band in range(num_bands):
band_data = spectral_data[band, :, :]
# 排除无效值
valid_data = band_data[distance_mask & (band_data != 0) & np.isfinite(band_data)]
if len(valid_data) > 0:
average_spectrum[band] = np.mean(valid_data)
return average_spectrum
def load_mask_file(mask_path):
"""
加载掩膜文件
Args:
mask_path: 掩膜文件路径(支持栅格文件如.dat/.tif等
Returns:
掩膜数组
"""
if mask_path is None or not os.path.exists(mask_path):
return None
try:
# 使用gdal.OpenEx打开文件明确指定为栅格文件
# 如果文件是矢量格式会返回None避免"多图层"错误
dataset = gdal.OpenEx(mask_path, gdal.OF_RASTER)
if dataset is None:
# 如果OpenEx失败尝试使用Open向后兼容
dataset = gdal.Open(mask_path, gdal.GA_ReadOnly)
if dataset is None:
print(f"警告: 无法打开掩膜文件 {mask_path},可能不是有效的栅格文件")
return None
# 检查是否为栅格数据集有RasterCount属性
if not hasattr(dataset, 'RasterCount') or dataset.RasterCount == 0:
print(f"警告: {mask_path} 不是有效的栅格文件")
del dataset
return None
mask_data = dataset.GetRasterBand(1).ReadAsArray()
del dataset
return mask_data
except Exception as e:
print(f"警告: 加载掩膜文件 {mask_path} 时出错: {str(e)}")
return None
def get_hdr_file_path(file_path):
"""
获取HDR文件路径
Args:
file_path: 影像文件路径
Returns:
HDR文件路径
"""
return os.path.splitext(file_path)[0] + ".hdr"
def calculate_utm_zone(longitude):
"""
根据经度计算UTM分区号
Args:
longitude: 经度
Returns:
utm_zone: UTM分区号1-60
"""
# UTM分区从180度开始每个分区6度
utm_zone = int((longitude + 180) / 6) + 1
# 确保分区号在有效范围内
utm_zone = max(1, min(60, utm_zone))
return utm_zone
def latlon_to_utm_math(lat_deg, lon_deg, zone=None):
"""
使用数学公式将WGS84经纬度转换为UTM坐标
Args:
lat_deg: 纬度(度)
lon_deg: 经度(度)
zone: UTM分区号如果为None则根据经度自动计算
Returns:
easting, northing: UTM坐标
"""
# 如果未指定分区,根据经度计算
if zone is None:
zone = calculate_utm_zone(lon_deg)
# 计算中央经线(度)
lon0 = (zone * 6 - 183)
lam0 = radians(lon0)
# 转换为弧度
phi = radians(lat_deg)
lam = radians(lon_deg)
# 计算中间变量
sinphi = sin(phi)
cosphi = cos(phi)
tanphi = tan(phi)
# 计算卯酉圈曲率半径
N = WGS84_A / sqrt(1 - WGS84_E2 * sinphi * sinphi)
T = tanphi * tanphi
C = WGS84_EP2 * cosphi * cosphi
A = cosphi * (lam - lam0)
# 计算子午圈弧长使用Snyder公式
M = (WGS84_A * ((1 - WGS84_E2/4 - 3*WGS84_E2**2/64 - 5*WGS84_E2**3/256) * phi
- (3*WGS84_E2/8 + 3*WGS84_E2**2/32 + 45*WGS84_E2**3/1024) * sin(2*phi)
+ (15*WGS84_E2**2/256 + 45*WGS84_E2**3/1024) * sin(4*phi)
- (35*WGS84_E2**3/3072) * sin(6*phi)))
# 计算东坐标Easting
E = (UTM_K0 * N * (A + (1 - T + C) * A**3 / 6
+ (5 - 18*T + T*T + 72*C - 58*WGS84_EP2) * A**5 / 120)
+ 500000.0)
# 计算北坐标Northing
# 对于南半球需要添加10000000米偏移
if lat_deg < 0:
Nn = (UTM_K0 * (M + N * tanphi * (A**2 / 2
+ (5 - T + 9*C + 4*C*C) * A**4 / 24
+ (61 - 58*T + T*T + 600*C - 330*WGS84_EP2) * A**6 / 720))
+ 10000000.0)
else:
Nn = (UTM_K0 * (M + N * tanphi * (A**2 / 2
+ (5 - T + 9*C + 4*C*C) * A**4 / 24
+ (61 - 58*T + T*T + 600*C - 330*WGS84_EP2) * A**6 / 720)))
return E, Nn
def convert_to_utm(lon, lat, source_epsg=4326, target_epsg=None):
"""
将坐标转换为UTM格式使用数学公式根据经度自动计算UTM分区
Args:
lon: 经度数组
lat: 纬度数组
source_epsg: 源坐标系EPSG代码默认为4326 (WGS84地理坐标系)
target_epsg: 目标坐标系EPSG代码如果为None则根据经度自动计算如果指定则从EPSG代码提取分区号
Returns:
utm_x, utm_y: 转换后的UTM坐标
"""
try:
# 检查源坐标系是否为WGS84
if source_epsg != 4326:
print(f"警告: 数学公式转换仅支持WGS84 (EPSG:4326)当前源坐标系为EPSG:{source_epsg}")
print("将尝试使用数学公式进行转换,但可能不准确")
# 批量转换坐标
utm_x = np.zeros_like(lon)
utm_y = np.zeros_like(lat)
# 如果指定了目标EPSG提取分区号
fixed_zone = None
if target_epsg is not None:
# 从EPSG代码提取分区号
# EPSG:32651 -> 51, EPSG:32751 -> 51
if 32601 <= target_epsg <= 32660:
fixed_zone = target_epsg - 32600
elif 32701 <= target_epsg <= 32760:
fixed_zone = target_epsg - 32700
else:
print(f"警告: 无法从EPSG代码 {target_epsg} 提取UTM分区号将根据经度自动计算")
# 向量化处理:标记无效坐标
invalid_mask = (np.isnan(lon) | np.isnan(lat) |
(lon < -180) | (lon > 180) |
(lat < -90) | (lat > 90))
# 统计无效坐标
invalid_count = np.sum(invalid_mask)
if invalid_count > 0:
invalid_indices = np.where(invalid_mask)[0]
print(f"警告: 发现 {invalid_count} 个无效坐标点,将跳过")
for idx in invalid_indices[:10]: # 只打印前10个
print(f" 坐标点 {idx + 1}: 经度={lon[idx]}, 纬度={lat[idx]}")
if invalid_count > 10:
print(f" ... 还有 {invalid_count - 10} 个无效坐标点")
# 对有效坐标进行转换
valid_mask = ~invalid_mask
if np.any(valid_mask):
valid_lon = lon[valid_mask]
valid_lat = lat[valid_mask]
valid_indices = np.where(valid_mask)[0]
# 计算UTM分区向量化
if fixed_zone is not None:
zones = np.full(len(valid_lon), fixed_zone)
else:
zones = np.array([calculate_utm_zone(lon_val) for lon_val in valid_lon])
# 批量转换(仍需要循环,但减少了开销)
for i, (lat_val, lon_val, zone) in enumerate(zip(valid_lat, valid_lon, zones)):
try:
E, Nn = latlon_to_utm_math(lat_val, lon_val, zone)
if not (np.isnan(E) or np.isnan(Nn) or np.isinf(E) or np.isinf(Nn)):
utm_x[valid_indices[i]] = E
utm_y[valid_indices[i]] = Nn
else:
utm_x[valid_indices[i]] = np.nan
utm_y[valid_indices[i]] = np.nan
except Exception as e:
utm_x[valid_indices[i]] = np.nan
utm_y[valid_indices[i]] = np.nan
# 设置无效坐标为NaN
utm_x[invalid_mask] = np.nan
utm_y[invalid_mask] = np.nan
return utm_x, utm_y
except Exception as e:
print(f"坐标转换初始化失败: {str(e)}")
return np.full_like(lon, np.nan), np.full_like(lat, np.nan)
def convert_to_utm51n(lon, lat, source_epsg=4326):
"""
将坐标转换为WGS84 UTM 51N格式保留向后兼容性
Args:
lon: 经度数组
lat: 纬度数组
source_epsg: 源坐标系EPSG代码默认为4326 (WGS84地理坐标系)
Returns:
utm_x, utm_y: 转换后的UTM坐标
"""
# 使用新的转换函数但强制使用UTM 51N
return convert_to_utm(lon, lat, source_epsg, target_epsg=32651)
def get_spectral_in_coor(imgpath, coorpath, outpath, radius=0, flare_path=None, boundary_path=None, source_epsg=4326):
"""
获取给定坐标的光谱曲线并将坐标转换为UTM格式根据经度自动计算UTM分区
Args:
imgpath: 影像文件路径BIL格式
coorpath: 坐标文件路径CSV格式第1、2列为纬度和经度
outpath: 输出文件路径CSV格式
radius: 采样半径(像素)
flare_path: 耀斑文件路径(可选)
boundary_path: 边界文件路径(可选)
source_epsg: 源坐标系EPSG代码默认为4326 (WGS84地理坐标系)
"""
# 读取原始坐标文件CSV格式
coor_df = None
coor_data = None
# 尝试不同的编码方式读取CSV文件
encodings = ['utf-8', 'gbk', 'gb2312', 'latin1', 'cp1252']
for encoding in encodings:
try:
# 尝试读取CSV文件
coor_df = pd.read_csv(coorpath, encoding=encoding)
# 只提取数值数据,跳过表头
coor_data = coor_df.select_dtypes(include=[np.number]).values
# 如果没有数值列,尝试转换所有列(跳过第一行表头)
if coor_data.shape[1] == 0:
# 尝试从第二行开始读取,第一行作为表头
coor_df = pd.read_csv(coorpath, encoding=encoding, header=0)
# 尝试将所有列转换为数值
numeric_df = coor_df.apply(pd.to_numeric, errors='coerce')
# 删除全为NaN的行通常是表头转换失败的行
numeric_df = numeric_df.dropna(how='all')
coor_data = numeric_df.values
print(f"成功使用 {encoding} 编码读取文件")
break
except Exception as e:
print(f"使用 {encoding} 编码读取失败: {str(e)}")
continue
# 如果所有编码都失败尝试numpy读取
if coor_data is None:
try:
print("尝试使用numpy读取数值数据...")
# 跳过第一行(表头),只读取数值
coor_data = np.loadtxt(coorpath, delimiter=",", skiprows=1)
except:
try:
coor_data = np.loadtxt(coorpath, delimiter="\t", skiprows=1)
except Exception as e:
raise Exception(f"无法读取坐标文件,请检查文件格式: {str(e)}")
if len(coor_data.shape) == 1:
coor_data = coor_data.reshape(1, -1)
# 检查数据有效性
if coor_data is None or coor_data.shape[1] < 2:
raise Exception("坐标文件格式错误需要至少2列数据第1列为纬度第2列为经度")
print(f"成功读取坐标文件,共 {coor_data.shape[0]} 行,{coor_data.shape[1]}")
print(f"数据预览前3行")
for i in range(min(3, coor_data.shape[0])):
print(f"{i + 1}: {coor_data[i, :min(5, coor_data.shape[1])]}") # 只显示前5列
# 提取原始坐标
lat_array = coor_data[:, 0] # 第1列是纬度
lon_array = coor_data[:, 1] # 第2列是经度
print(f"\n=== 原始坐标信息 ===")
print(f"原始坐标范围: 经度 {np.min(lon_array):.6f} ~ {np.max(lon_array):.6f}, 纬度 {np.min(lat_array):.6f} ~ {np.max(lat_array):.6f}")
# 坐标转换为UTM根据经度自动计算UTM分区
print("正在进行坐标转换...")
utm_x, utm_y = convert_to_utm(lon_array, lat_array, source_epsg, target_epsg=None)
# 检查转换结果
valid_utm_mask = ~(np.isnan(utm_x) | np.isnan(utm_y) | np.isinf(utm_x) | np.isinf(utm_y))
valid_count = np.sum(valid_utm_mask)
if valid_count > 0:
print(f"转换后UTM坐标范围: X {np.nanmin(utm_x):.2f} ~ {np.nanmax(utm_x):.2f}, Y {np.nanmin(utm_y):.2f} ~ {np.nanmax(utm_y):.2f}")
print(f"成功转换 {valid_count}/{len(utm_x)} 个坐标点")
else:
print("警告: 所有UTM坐标转换都失败了将尝试使用原始经纬度坐标进行像素坐标转换")
# 打开影像数据集
dataset = gdal.Open(imgpath)
im_width = dataset.RasterXSize # 栅格矩阵的列数
im_height = dataset.RasterYSize # 栅格矩阵的行数
num_bands = dataset.RasterCount # 栅格矩阵的波段数
geotransform = dataset.GetGeoTransform() # 仿射矩阵
im_proj = dataset.GetProjection() # 地图投影信息
print(f"影像尺寸: {im_width} x {im_height}, 波段数: {num_bands}")
print(f"仿射变换参数: {geotransform}")
print("\n=== 开始光谱提取 ===")
# 加载掩膜文件
flare_mask = load_mask_file(flare_path)
boundary_mask = load_mask_file(boundary_path)
boundary_adjuster = None
if boundary_mask is not None and radius > 0:
boundary_adjuster = prepare_boundary_adjuster(boundary_mask)
if boundary_adjuster is None:
print("提示: 无法构建边界调整器,采样点将不会根据水体边界进行内移。")
# 获取数据集的空间参考系统
dataset_srs = dataset.GetSpatialRef()
# 准备输出数组在原有数据基础上添加UTM坐标和光谱列
original_cols = coor_data.shape[1]
# 添加UTM坐标列2列和光谱列num_bands列
new_columns = np.zeros((coor_data.shape[0], 2 + num_bands))
coor_spectral = np.hstack((coor_data, new_columns))
# 将UTM坐标添加到数据中会在采样点调整后再更新为最终位置
coor_spectral[:, original_cols] = utm_x # 初始UTM X坐标
coor_spectral[:, original_cols + 1] = utm_y # 初始UTM Y坐标
print(f"处理 {coor_data.shape[0]} 个坐标点...")
# 如果UTM转换失败尝试使用影像坐标系进行转换
use_utm_fallback = False
if valid_count == 0 and dataset_srs is not None:
print("尝试使用影像坐标系进行坐标转换...")
try:
source_srs = osr.SpatialReference()
source_srs.ImportFromEPSG(source_epsg)
transform_to_image = osr.CoordinateTransformation(source_srs, dataset_srs)
use_utm_fallback = True
except:
use_utm_fallback = False
# 批量转换所有坐标点为像素坐标
pixel_x_array = np.zeros(coor_data.shape[0], dtype=np.int32)
pixel_y_array = np.zeros(coor_data.shape[0], dtype=np.int32)
valid_pixel_mask = np.zeros(coor_data.shape[0], dtype=bool)
# 批量计算像素坐标
for i in range(coor_data.shape[0]):
# 优先使用UTM坐标如果无效则使用备用方案
utm_x_point = utm_x[i]
utm_y_point = utm_y[i]
# 检查UTM坐标是否有效
if np.isnan(utm_x_point) or np.isnan(utm_y_point) or np.isinf(utm_x_point) or np.isinf(utm_y_point):
# 如果UTM转换失败尝试使用影像坐标系
if use_utm_fallback:
try:
lon_point = lon_array[i]
lat_point = lat_array[i]
if not (np.isnan(lon_point) or np.isnan(lat_point)):
# 转换为影像坐标系
img_coords = transform_to_image.TransformPoint(lon_point, lat_point)
pixel_x, pixel_y = geo_to_pixel(img_coords[0], img_coords[1], geotransform, dataset_srs)
# 更新UTM坐标列使用影像坐标系坐标
coor_spectral[i, original_cols] = img_coords[0]
coor_spectral[i, original_cols + 1] = img_coords[1]
else:
print(f"跳过坐标点 {i + 1}: 坐标无效")
coor_spectral[i, original_cols + 2:] = np.zeros(num_bands)
continue
except Exception as e:
# 如果影像坐标系转换也失败,尝试直接使用经纬度
try:
lon_point = lon_array[i]
lat_point = lat_array[i]
if not (np.isnan(lon_point) or np.isnan(lat_point)):
pixel_x, pixel_y = geo_to_pixel(lon_point, lat_point, geotransform, dataset_srs)
# 保留原始经纬度作为坐标
coor_spectral[i, original_cols] = lon_point
coor_spectral[i, original_cols + 1] = lat_point
else:
print(f"跳过坐标点 {i + 1}: 坐标无效")
coor_spectral[i, original_cols + 2:] = np.zeros(num_bands)
continue
except:
print(f"跳过坐标点 {i + 1}: 所有坐标转换方式都失败")
coor_spectral[i, original_cols + 2:] = np.zeros(num_bands)
continue
else:
# 尝试直接使用经纬度坐标
try:
lon_point = lon_array[i]
lat_point = lat_array[i]
if not (np.isnan(lon_point) or np.isnan(lat_point)):
pixel_x, pixel_y = geo_to_pixel(lon_point, lat_point, geotransform, dataset_srs)
# 保留原始经纬度作为坐标
coor_spectral[i, original_cols] = lon_point
coor_spectral[i, original_cols + 1] = lat_point
else:
print(f"跳过坐标点 {i + 1}: 坐标无效")
coor_spectral[i, original_cols + 2:] = np.zeros(num_bands)
continue
except:
print(f"跳过坐标点 {i + 1}: 坐标转换失败")
coor_spectral[i, original_cols + 2:] = np.zeros(num_bands)
continue
else:
# UTM坐标转换为像素坐标
pixel_x, pixel_y = geo_to_pixel(utm_x_point, utm_y_point, geotransform, dataset_srs)
# 存储像素坐标
pixel_x_array[i] = pixel_x
pixel_y_array[i] = pixel_y
# 根据水体边界调整采样中心
moved = False
original_pixel_x, original_pixel_y = pixel_x, pixel_y
if boundary_adjuster is not None and radius > 0:
new_pixel_x, new_pixel_y, moved = adjust_sampling_center(pixel_x, pixel_y, radius, boundary_adjuster)
if moved:
pixel_x, pixel_y = new_pixel_x, new_pixel_y
if i < 10 or (i % 100 == 0):
print(f" 采样点 {i + 1} 调整至水体内部: ({original_pixel_x}, {original_pixel_y}) -> ({pixel_x}, {pixel_y})")
pixel_x_array[i] = pixel_x
pixel_y_array[i] = pixel_y
# 检查坐标是否在影像范围内(使用调整后的坐标)
if 0 <= pixel_x < im_width and 0 <= pixel_y < im_height:
valid_pixel_mask[i] = True
# 更新UTM列为最终采样点的实际地图坐标
geo_x, geo_y = pixel_to_geo(pixel_x, pixel_y, geotransform)
coor_spectral[i, original_cols] = geo_x
coor_spectral[i, original_cols + 1] = geo_y
else:
valid_pixel_mask[i] = False
if i < 10 or (i % 100 == 0): # 只打印前10个或每100个打印一次
print(f"警告: 坐标点 {i + 1} (UTM X:{utm_x_point:.2f}, Y:{utm_y_point:.2f}) 超出影像范围")
# 批量提取光谱数据优化减少I/O操作
print(f"批量提取光谱数据... (有效坐标点: {np.sum(valid_pixel_mask)})")
if radius > 0:
# 半径采样模式:需要逐个处理
for i in range(coor_data.shape[0]):
if valid_pixel_mask[i]:
spectrum = get_average_spectral_in_radius(
dataset, pixel_x_array[i], pixel_y_array[i], radius, flare_mask, boundary_mask
)
coor_spectral[i, original_cols + 2:] = spectrum
else:
coor_spectral[i, original_cols + 2:] = np.zeros(num_bands)
else:
# 单点采样模式:批量读取(优化)
# 预读取所有波段数据(如果内存允许)
try:
# 尝试读取所有波段到内存(适用于内存充足的情况)
print("正在预加载所有波段数据到内存(优化模式)...")
all_bands_data = []
for band_idx in range(num_bands):
band = dataset.GetRasterBand(band_idx + 1)
band_data = band.ReadAsArray()
all_bands_data.append(band_data)
all_bands_data = np.array(all_bands_data) # shape: (bands, height, width)
print("预加载完成,开始批量提取像素值...")
# 批量提取像素值
for i in range(coor_data.shape[0]):
if valid_pixel_mask[i]:
px, py = int(pixel_x_array[i]), int(pixel_y_array[i])
# GDAL读取的数组形状是 (bands, height, width),像素坐标 (x,y) 对应数组索引 [:, y, x]
# 注意py是行y坐标px是列x坐标
if 0 <= px < all_bands_data.shape[2] and 0 <= py < all_bands_data.shape[1]:
spectrum = all_bands_data[:, py, px] # 直接索引,非常快
coor_spectral[i, original_cols + 2:] = spectrum
else:
coor_spectral[i, original_cols + 2:] = np.zeros(num_bands)
else:
coor_spectral[i, original_cols + 2:] = np.zeros(num_bands)
# 释放内存
del all_bands_data
print("批量提取完成")
except MemoryError:
# 如果内存不足,回退到逐个波段读取
print("内存不足,使用逐个波段读取模式...")
for i in range(coor_data.shape[0]):
if valid_pixel_mask[i]:
px, py = pixel_x_array[i], pixel_y_array[i]
spectrum = np.zeros(num_bands)
for band_idx in range(num_bands):
band = dataset.GetRasterBand(band_idx + 1)
spectrum[band_idx] = band.ReadAsArray(px, py, 1, 1)[0, 0]
coor_spectral[i, original_cols + 2:] = spectrum
else:
coor_spectral[i, original_cols + 2:] = np.zeros(num_bands)
del dataset
# 创建DataFrame用于CSV输出
# 去除前两列坐标列纬度和经度和UTM列
try:
# 如果原始数据有列名,使用原始列名(跳过前两列)
if coor_df is not None and hasattr(coor_df, 'columns'):
# 跳过前两列经纬度从第3列开始
if len(coor_df.columns) >= original_cols:
# 保留第3列及之后的原始列如果有的话
if original_cols > 2:
original_columns = list(coor_df.columns[2:original_cols])
else:
original_columns = []
else:
# 如果原始列数不足,只保留存在的列(跳过前两列)
if len(coor_df.columns) > 2:
original_columns = list(coor_df.columns[2:])
else:
original_columns = []
else:
# 如果没有列名只保留第3列及之后的列如果有的话
if original_cols > 2:
original_columns = ["col_" + str(j + 1) for j in range(2, original_cols)]
else:
original_columns = []
except:
# 异常处理只保留第3列及之后的列如果有的话
if original_cols > 2:
original_columns = ["col_" + str(j + 1) for j in range(2, original_cols)]
else:
original_columns = []
# 读取波长信息,用作光谱列名
wavelengths = None
try:
in_hdr_dict = spectral.envi.read_envi_header(get_hdr_file_path(imgpath))
wavelengths = np.array(in_hdr_dict['wavelength']).astype('float64')
# 将波长值转换为字符串作为列名
spectral_columns = [str(wl) for wl in wavelengths]
print(f"成功读取波长信息,共 {len(spectral_columns)} 个波段")
except Exception as e:
print(f"警告: 无法读取波长信息 ({str(e)}),使用默认列名 band_1, band_2, ...")
spectral_columns = ["band_" + str(j + 1) for j in range(num_bands)]
# 构建输出列名不包含前两列坐标列和UTM列
all_columns = original_columns + spectral_columns
# 从coor_spectral中提取需要输出的列
# 跳过前两列经纬度和UTM列只保留
# - 第3列到第original_cols列如果有的话
# - 光谱数据列从original_cols+2开始
output_data = []
if original_cols > 2:
# 保留第3列到第original_cols列
output_data.append(coor_spectral[:, 2:original_cols])
# 保留光谱数据列从original_cols+2开始
output_data.append(coor_spectral[:, original_cols + 2:])
# 合并数据
if len(output_data) > 0:
output_array = np.hstack(output_data) if len(output_data) > 1 else output_data[0]
else:
# 如果没有原始列,只输出光谱数据
output_array = coor_spectral[:, original_cols + 2:]
# 创建结果DataFrame
result_df = pd.DataFrame(output_array, columns=all_columns)
# 保存为CSV格式
result_df.to_csv(outpath, index=False, float_format='%.6f')
print(f"结果已保存到CSV文件: {outpath}")
return coor_spectral
# 直接运行示例
if __name__ == '__main__':
# 在这里直接设置参数
imgpath = r"D:\BaiduNetdiskDownload\yaobao\result3.bsq"# BIL格式影像文件路径
coorpath = r"E:\code\WQ\封装\work_dir\4_processed_data\processed_data.csv"# CSV格式坐标文件路径第1、2列为纬度和经度
output_path = r"E:\code\WQ\封装\test/yangdian_output.csv" # CSV格式输出文件路径
radius = 5 # 采样半径像素0表示单点采样>0表示半径内平均
flare_path = r"E:\code\WQ\封装\work_dir\2_glint\severe_glint_area.dat" # 耀斑掩膜文件路径可选None表示不使用
boundary_path ="D:\BaiduNetdiskDownload\yaobao\water_mask.dat" # 边界掩膜文件路径可选None表示不使用
source_epsg = 4326 # 源坐标系EPSG代码默认为4326 (WGS84地理坐标系)
verbose = True # 是否启用详细模式
if verbose:
print(f"影像文件: {imgpath}")
print(f"坐标文件: {coorpath}")
print(f"输出文件: {output_path}")
print(f"采样半径: {radius}")
if flare_path:
print(f"耀斑掩膜: {flare_path}")
if boundary_path:
print(f"边界掩膜: {boundary_path}")
if source_epsg:
print(f"指定坐标系: EPSG:{source_epsg}")
tmp = get_spectral_in_coor(imgpath, coorpath, output_path,
radius, flare_path, boundary_path, source_epsg)

View File

@ -0,0 +1,785 @@
from osgeo import gdal, osr
import numpy as np
import pandas as pd
import os
import spectral
from math import sin, cos, tan, sqrt, radians
# 启用GDAL异常处理
osr.UseExceptions()
# WGS84椭球参数
WGS84_A = 6378137.0 # 长半轴(米)
WGS84_F = 1 / 298.257223563 # 扁率
WGS84_E2 = WGS84_F * (2 - WGS84_F) # 第一偏心率平方
WGS84_EP2 = WGS84_E2 / (1 - WGS84_E2) # 第二偏心率平方
UTM_K0 = 0.9996 # UTM比例因子
def transform_coordinates(lon, lat, source_srs, target_srs):
"""
坐标系转换
Args:
lon: 经度
lat: 纬度
source_srs: 源坐标系
target_srs: 目标坐标系
Returns:
transformed_lon, transformed_lat: 转换后的坐标
"""
# 创建坐标转换对象
transform = osr.CoordinateTransformation(source_srs, target_srs)
# 执行坐标转换
point = transform.TransformPoint(lon, lat)
return point[0], point[1]
def geo_to_pixel(lon, lat, geotransform, dataset_srs=None):
"""
地理坐标转换为像素坐标
Args:
lon: 经度
lat: 纬度
geotransform: 仿射变换参数
dataset_srs: 数据集的空间参考系统(可选)
Returns:
pixel_x, pixel_y: 像素坐标
"""
# 使用仿射变换的逆变换将地理坐标转换为像素坐标
x_origin = geotransform[0]
y_origin = geotransform[3]
pixel_width = geotransform[1]
pixel_height = geotransform[5]
pixel_x = int((lon - x_origin) / pixel_width)
pixel_y = int((lat - y_origin) / pixel_height)
return pixel_x, pixel_y
def get_pixel_spectrum_batch(dataset, pixel_x_array, pixel_y_array):
"""
批量获取多个像素点的光谱数据(优化版本)
Args:
dataset: GDAL数据集
pixel_x_array: 像素X坐标数组
pixel_y_array: 像素Y坐标数组
Returns:
spectrum_array: 光谱数据数组 (n_points, n_bands)
"""
n_points = len(pixel_x_array)
n_bands = dataset.RasterCount
# 初始化输出数组
spectrum_array = np.zeros((n_points, n_bands), dtype=np.float32)
# 按波段批量读取(更高效)
for band_idx in range(n_bands):
band = dataset.GetRasterBand(band_idx + 1) # GDAL波段索引从1开始
band_data = band.ReadAsArray() # 读取整个波段
# 批量提取像素值
for i in range(n_points):
px, py = int(pixel_x_array[i]), int(pixel_y_array[i])
if 0 <= px < band_data.shape[1] and 0 <= py < band_data.shape[0]:
spectrum_array[i, band_idx] = band_data[py, px]
else:
spectrum_array[i, band_idx] = np.nan
return spectrum_array
def get_average_spectral_in_radius(dataset, center_x, center_y, radius, flare_mask=None, boundary_mask=None):
"""
获取指定半径内的平均光谱,避开耀斑和边界区域
Args:
dataset: GDAL数据集
center_x, center_y: 中心像素坐标
radius: 半径(像素)
flare_mask: 耀斑掩膜数组(可选)
boundary_mask: 边界掩膜数组(可选)
Returns:
平均光谱值数组
"""
num_bands = dataset.RasterCount
# 计算采样区域边界
x_start = max(0, center_x - radius)
x_end = min(dataset.RasterXSize, center_x + radius + 1)
y_start = max(0, center_y - radius)
y_end = min(dataset.RasterYSize, center_y + radius + 1)
# 读取区域数据
width = x_end - x_start
height = y_end - y_start
if width <= 0 or height <= 0:
return np.zeros(num_bands)
# 读取所有波段数据
spectral_data = dataset.ReadAsArray(x_start, y_start, width, height)
if spectral_data is None:
return np.zeros(num_bands)
# 确保数据是3维的 (bands, height, width)
if len(spectral_data.shape) == 2:
spectral_data = spectral_data.reshape(1, spectral_data.shape[0], spectral_data.shape[1])
# 创建圆形掩膜
y_indices, x_indices = np.ogrid[:height, :width]
center_x_local = center_x - x_start
center_y_local = center_y - y_start
# 计算距离掩膜
distance_mask = ((x_indices - center_x_local) ** 2 + (y_indices - center_y_local) ** 2) <= radius ** 2
# 应用耀斑掩膜(如果提供)
if flare_mask is not None:
flare_region = flare_mask[y_start:y_end, x_start:x_end]
if flare_region.shape == distance_mask.shape:
distance_mask = distance_mask & (flare_region == 0) # 假设0表示无耀斑
# 应用边界掩膜(如果提供)
if boundary_mask is not None:
boundary_region = boundary_mask[y_start:y_end, x_start:x_end]
if boundary_region.shape == distance_mask.shape:
distance_mask = distance_mask & (boundary_region == 1) # 假设0表示无边界
# 计算平均光谱
average_spectrum = np.zeros(num_bands)
valid_pixels = np.sum(distance_mask)
if valid_pixels > 0:
for band in range(num_bands):
band_data = spectral_data[band, :, :]
# 排除无效值
valid_data = band_data[distance_mask & (band_data != 0) & np.isfinite(band_data)]
if len(valid_data) > 0:
average_spectrum[band] = np.mean(valid_data)
return average_spectrum
def load_mask_file(mask_path):
"""
加载掩膜文件
Args:
mask_path: 掩膜文件路径(支持栅格文件如.dat/.tif等
Returns:
掩膜数组
"""
if mask_path is None or not os.path.exists(mask_path):
return None
try:
# 使用gdal.OpenEx打开文件明确指定为栅格文件
# 如果文件是矢量格式会返回None避免"多图层"错误
dataset = gdal.OpenEx(mask_path, gdal.OF_RASTER)
if dataset is None:
# 如果OpenEx失败尝试使用Open向后兼容
dataset = gdal.Open(mask_path, gdal.GA_ReadOnly)
if dataset is None:
print(f"警告: 无法打开掩膜文件 {mask_path},可能不是有效的栅格文件")
return None
# 检查是否为栅格数据集有RasterCount属性
if not hasattr(dataset, 'RasterCount') or dataset.RasterCount == 0:
print(f"警告: {mask_path} 不是有效的栅格文件")
del dataset
return None
mask_data = dataset.GetRasterBand(1).ReadAsArray()
del dataset
return mask_data
except Exception as e:
print(f"警告: 加载掩膜文件 {mask_path} 时出错: {str(e)}")
return None
def get_hdr_file_path(file_path):
"""
获取HDR文件路径
Args:
file_path: 影像文件路径
Returns:
HDR文件路径
"""
return os.path.splitext(file_path)[0] + ".hdr"
def calculate_utm_zone(longitude):
"""
根据经度计算UTM分区号
Args:
longitude: 经度
Returns:
utm_zone: UTM分区号1-60
"""
# UTM分区从180度开始每个分区6度
utm_zone = int((longitude + 180) / 6) + 1
# 确保分区号在有效范围内
utm_zone = max(1, min(60, utm_zone))
return utm_zone
def latlon_to_utm_math(lat_deg, lon_deg, zone=None):
"""
使用数学公式将WGS84经纬度转换为UTM坐标
Args:
lat_deg: 纬度(度)
lon_deg: 经度(度)
zone: UTM分区号如果为None则根据经度自动计算
Returns:
easting, northing: UTM坐标
"""
# 如果未指定分区,根据经度计算
if zone is None:
zone = calculate_utm_zone(lon_deg)
# 计算中央经线(度)
lon0 = (zone * 6 - 183)
lam0 = radians(lon0)
# 转换为弧度
phi = radians(lat_deg)
lam = radians(lon_deg)
# 计算中间变量
sinphi = sin(phi)
cosphi = cos(phi)
tanphi = tan(phi)
# 计算卯酉圈曲率半径
N = WGS84_A / sqrt(1 - WGS84_E2 * sinphi * sinphi)
T = tanphi * tanphi
C = WGS84_EP2 * cosphi * cosphi
A = cosphi * (lam - lam0)
# 计算子午圈弧长使用Snyder公式
M = (WGS84_A * ((1 - WGS84_E2/4 - 3*WGS84_E2**2/64 - 5*WGS84_E2**3/256) * phi
- (3*WGS84_E2/8 + 3*WGS84_E2**2/32 + 45*WGS84_E2**3/1024) * sin(2*phi)
+ (15*WGS84_E2**2/256 + 45*WGS84_E2**3/1024) * sin(4*phi)
- (35*WGS84_E2**3/3072) * sin(6*phi)))
# 计算东坐标Easting
E = (UTM_K0 * N * (A + (1 - T + C) * A**3 / 6
+ (5 - 18*T + T*T + 72*C - 58*WGS84_EP2) * A**5 / 120)
+ 500000.0)
# 计算北坐标Northing
# 对于南半球需要添加10000000米偏移
if lat_deg < 0:
Nn = (UTM_K0 * (M + N * tanphi * (A**2 / 2
+ (5 - T + 9*C + 4*C*C) * A**4 / 24
+ (61 - 58*T + T*T + 600*C - 330*WGS84_EP2) * A**6 / 720))
+ 10000000.0)
else:
Nn = (UTM_K0 * (M + N * tanphi * (A**2 / 2
+ (5 - T + 9*C + 4*C*C) * A**4 / 24
+ (61 - 58*T + T*T + 600*C - 330*WGS84_EP2) * A**6 / 720)))
return E, Nn
def convert_to_utm(lon, lat, source_epsg=4326, target_epsg=None):
"""
将坐标转换为UTM格式使用数学公式根据经度自动计算UTM分区
Args:
lon: 经度数组
lat: 纬度数组
source_epsg: 源坐标系EPSG代码默认为4326 (WGS84地理坐标系)
target_epsg: 目标坐标系EPSG代码如果为None则根据经度自动计算如果指定则从EPSG代码提取分区号
Returns:
utm_x, utm_y: 转换后的UTM坐标
"""
try:
# 检查源坐标系是否为WGS84
if source_epsg != 4326:
print(f"警告: 数学公式转换仅支持WGS84 (EPSG:4326)当前源坐标系为EPSG:{source_epsg}")
print("将尝试使用数学公式进行转换,但可能不准确")
# 批量转换坐标
utm_x = np.zeros_like(lon)
utm_y = np.zeros_like(lat)
# 如果指定了目标EPSG提取分区号
fixed_zone = None
if target_epsg is not None:
# 从EPSG代码提取分区号
# EPSG:32651 -> 51, EPSG:32751 -> 51
if 32601 <= target_epsg <= 32660:
fixed_zone = target_epsg - 32600
elif 32701 <= target_epsg <= 32760:
fixed_zone = target_epsg - 32700
else:
print(f"警告: 无法从EPSG代码 {target_epsg} 提取UTM分区号将根据经度自动计算")
# 向量化处理:标记无效坐标
invalid_mask = (np.isnan(lon) | np.isnan(lat) |
(lon < -180) | (lon > 180) |
(lat < -90) | (lat > 90))
# 统计无效坐标
invalid_count = np.sum(invalid_mask)
if invalid_count > 0:
invalid_indices = np.where(invalid_mask)[0]
print(f"警告: 发现 {invalid_count} 个无效坐标点,将跳过")
for idx in invalid_indices[:10]: # 只打印前10个
print(f" 坐标点 {idx + 1}: 经度={lon[idx]}, 纬度={lat[idx]}")
if invalid_count > 10:
print(f" ... 还有 {invalid_count - 10} 个无效坐标点")
# 对有效坐标进行转换
valid_mask = ~invalid_mask
if np.any(valid_mask):
valid_lon = lon[valid_mask]
valid_lat = lat[valid_mask]
valid_indices = np.where(valid_mask)[0]
# 计算UTM分区向量化
if fixed_zone is not None:
zones = np.full(len(valid_lon), fixed_zone)
else:
zones = np.array([calculate_utm_zone(lon_val) for lon_val in valid_lon])
# 批量转换(仍需要循环,但减少了开销)
for i, (lat_val, lon_val, zone) in enumerate(zip(valid_lat, valid_lon, zones)):
try:
E, Nn = latlon_to_utm_math(lat_val, lon_val, zone)
if not (np.isnan(E) or np.isnan(Nn) or np.isinf(E) or np.isinf(Nn)):
utm_x[valid_indices[i]] = E
utm_y[valid_indices[i]] = Nn
else:
utm_x[valid_indices[i]] = np.nan
utm_y[valid_indices[i]] = np.nan
except Exception as e:
utm_x[valid_indices[i]] = np.nan
utm_y[valid_indices[i]] = np.nan
# 设置无效坐标为NaN
utm_x[invalid_mask] = np.nan
utm_y[invalid_mask] = np.nan
return utm_x, utm_y
except Exception as e:
print(f"坐标转换初始化失败: {str(e)}")
return np.full_like(lon, np.nan), np.full_like(lat, np.nan)
def convert_to_utm51n(lon, lat, source_epsg=4326):
"""
将坐标转换为WGS84 UTM 51N格式保留向后兼容性
Args:
lon: 经度数组
lat: 纬度数组
source_epsg: 源坐标系EPSG代码默认为4326 (WGS84地理坐标系)
Returns:
utm_x, utm_y: 转换后的UTM坐标
"""
# 使用新的转换函数但强制使用UTM 51N
return convert_to_utm(lon, lat, source_epsg, target_epsg=32651)
def get_spectral_in_coor(imgpath, coorpath, outpath, radius=0, flare_path=None, boundary_path=None, source_epsg=4326):
"""
获取给定坐标的光谱曲线并将坐标转换为UTM格式根据经度自动计算UTM分区
Args:
imgpath: 影像文件路径BIL格式
coorpath: 坐标文件路径CSV格式第1、2列为纬度和经度
outpath: 输出文件路径CSV格式
radius: 采样半径(像素)
flare_path: 耀斑文件路径(可选)
boundary_path: 边界文件路径(可选)
source_epsg: 源坐标系EPSG代码默认为4326 (WGS84地理坐标系)
"""
# 读取原始坐标文件CSV格式
coor_df = None
coor_data = None
# 尝试不同的编码方式读取CSV文件
encodings = ['utf-8', 'gbk', 'gb2312', 'latin1', 'cp1252']
for encoding in encodings:
try:
# 尝试读取CSV文件
coor_df = pd.read_csv(coorpath, encoding=encoding)
# 只提取数值数据,跳过表头
coor_data = coor_df.select_dtypes(include=[np.number]).values
# 如果没有数值列,尝试转换所有列(跳过第一行表头)
if coor_data.shape[1] == 0:
# 尝试从第二行开始读取,第一行作为表头
coor_df = pd.read_csv(coorpath, encoding=encoding, header=0)
# 尝试将所有列转换为数值
numeric_df = coor_df.apply(pd.to_numeric, errors='coerce')
# 删除全为NaN的行通常是表头转换失败的行
numeric_df = numeric_df.dropna(how='all')
coor_data = numeric_df.values
print(f"成功使用 {encoding} 编码读取文件")
break
except Exception as e:
print(f"使用 {encoding} 编码读取失败: {str(e)}")
continue
# 如果所有编码都失败尝试numpy读取
if coor_data is None:
try:
print("尝试使用numpy读取数值数据...")
# 跳过第一行(表头),只读取数值
coor_data = np.loadtxt(coorpath, delimiter=",", skiprows=1)
except:
try:
coor_data = np.loadtxt(coorpath, delimiter="\t", skiprows=1)
except Exception as e:
raise Exception(f"无法读取坐标文件,请检查文件格式: {str(e)}")
if len(coor_data.shape) == 1:
coor_data = coor_data.reshape(1, -1)
# 检查数据有效性
if coor_data is None or coor_data.shape[1] < 2:
raise Exception("坐标文件格式错误需要至少2列数据第1列为纬度第2列为经度")
print(f"成功读取坐标文件,共 {coor_data.shape[0]} 行,{coor_data.shape[1]}")
print(f"数据预览前3行")
for i in range(min(3, coor_data.shape[0])):
print(f"{i + 1}: {coor_data[i, :min(5, coor_data.shape[1])]}") # 只显示前5列
# 提取原始坐标
lat_array = coor_data[:, 0] # 第1列是纬度
lon_array = coor_data[:, 1] # 第2列是经度
print(f"\n=== 原始坐标信息 ===")
print(f"原始坐标范围: 经度 {np.min(lon_array):.6f} ~ {np.max(lon_array):.6f}, 纬度 {np.min(lat_array):.6f} ~ {np.max(lat_array):.6f}")
# 坐标转换为UTM根据经度自动计算UTM分区
print("正在进行坐标转换...")
utm_x, utm_y = convert_to_utm(lon_array, lat_array, source_epsg, target_epsg=None)
# 检查转换结果
valid_utm_mask = ~(np.isnan(utm_x) | np.isnan(utm_y) | np.isinf(utm_x) | np.isinf(utm_y))
valid_count = np.sum(valid_utm_mask)
if valid_count > 0:
print(f"转换后UTM坐标范围: X {np.nanmin(utm_x):.2f} ~ {np.nanmax(utm_x):.2f}, Y {np.nanmin(utm_y):.2f} ~ {np.nanmax(utm_y):.2f}")
print(f"成功转换 {valid_count}/{len(utm_x)} 个坐标点")
else:
print("警告: 所有UTM坐标转换都失败了将尝试使用原始经纬度坐标进行像素坐标转换")
# 打开影像数据集
dataset = gdal.Open(imgpath)
im_width = dataset.RasterXSize # 栅格矩阵的列数
im_height = dataset.RasterYSize # 栅格矩阵的行数
num_bands = dataset.RasterCount # 栅格矩阵的波段数
geotransform = dataset.GetGeoTransform() # 仿射矩阵
im_proj = dataset.GetProjection() # 地图投影信息
print(f"影像尺寸: {im_width} x {im_height}, 波段数: {num_bands}")
print(f"仿射变换参数: {geotransform}")
print("\n=== 开始光谱提取 ===")
# 加载掩膜文件
flare_mask = load_mask_file(flare_path)
boundary_mask = load_mask_file(boundary_path)
# 获取数据集的空间参考系统
dataset_srs = dataset.GetSpatialRef()
# 准备输出数组在原有数据基础上添加UTM坐标和光谱列
original_cols = coor_data.shape[1]
# 添加UTM坐标列2列和光谱列num_bands列
new_columns = np.zeros((coor_data.shape[0], 2 + num_bands))
coor_spectral = np.hstack((coor_data, new_columns))
# 将UTM坐标添加到数据中
coor_spectral[:, original_cols] = utm_x # UTM X坐标
coor_spectral[:, original_cols + 1] = utm_y # UTM Y坐标
print(f"处理 {coor_data.shape[0]} 个坐标点...")
# 如果UTM转换失败尝试使用影像坐标系进行转换
use_utm_fallback = False
if valid_count == 0 and dataset_srs is not None:
print("尝试使用影像坐标系进行坐标转换...")
try:
source_srs = osr.SpatialReference()
source_srs.ImportFromEPSG(source_epsg)
transform_to_image = osr.CoordinateTransformation(source_srs, dataset_srs)
use_utm_fallback = True
except:
use_utm_fallback = False
# 批量转换所有坐标点为像素坐标
pixel_x_array = np.zeros(coor_data.shape[0], dtype=np.int32)
pixel_y_array = np.zeros(coor_data.shape[0], dtype=np.int32)
valid_pixel_mask = np.zeros(coor_data.shape[0], dtype=bool)
# 批量计算像素坐标
for i in range(coor_data.shape[0]):
# 优先使用UTM坐标如果无效则使用备用方案
utm_x_point = utm_x[i]
utm_y_point = utm_y[i]
# 检查UTM坐标是否有效
if np.isnan(utm_x_point) or np.isnan(utm_y_point) or np.isinf(utm_x_point) or np.isinf(utm_y_point):
# 如果UTM转换失败尝试使用影像坐标系
if use_utm_fallback:
try:
lon_point = lon_array[i]
lat_point = lat_array[i]
if not (np.isnan(lon_point) or np.isnan(lat_point)):
# 转换为影像坐标系
img_coords = transform_to_image.TransformPoint(lon_point, lat_point)
pixel_x, pixel_y = geo_to_pixel(img_coords[0], img_coords[1], geotransform, dataset_srs)
# 更新UTM坐标列使用影像坐标系坐标
coor_spectral[i, original_cols] = img_coords[0]
coor_spectral[i, original_cols + 1] = img_coords[1]
else:
print(f"跳过坐标点 {i + 1}: 坐标无效")
coor_spectral[i, original_cols + 2:] = np.zeros(num_bands)
continue
except Exception as e:
# 如果影像坐标系转换也失败,尝试直接使用经纬度
try:
lon_point = lon_array[i]
lat_point = lat_array[i]
if not (np.isnan(lon_point) or np.isnan(lat_point)):
pixel_x, pixel_y = geo_to_pixel(lon_point, lat_point, geotransform, dataset_srs)
# 保留原始经纬度作为坐标
coor_spectral[i, original_cols] = lon_point
coor_spectral[i, original_cols + 1] = lat_point
else:
print(f"跳过坐标点 {i + 1}: 坐标无效")
coor_spectral[i, original_cols + 2:] = np.zeros(num_bands)
continue
except:
print(f"跳过坐标点 {i + 1}: 所有坐标转换方式都失败")
coor_spectral[i, original_cols + 2:] = np.zeros(num_bands)
continue
else:
# 尝试直接使用经纬度坐标
try:
lon_point = lon_array[i]
lat_point = lat_array[i]
if not (np.isnan(lon_point) or np.isnan(lat_point)):
pixel_x, pixel_y = geo_to_pixel(lon_point, lat_point, geotransform, dataset_srs)
# 保留原始经纬度作为坐标
coor_spectral[i, original_cols] = lon_point
coor_spectral[i, original_cols + 1] = lat_point
else:
print(f"跳过坐标点 {i + 1}: 坐标无效")
coor_spectral[i, original_cols + 2:] = np.zeros(num_bands)
continue
except:
print(f"跳过坐标点 {i + 1}: 坐标转换失败")
coor_spectral[i, original_cols + 2:] = np.zeros(num_bands)
continue
else:
# UTM坐标转换为像素坐标
pixel_x, pixel_y = geo_to_pixel(utm_x_point, utm_y_point, geotransform, dataset_srs)
# 存储像素坐标
pixel_x_array[i] = pixel_x
pixel_y_array[i] = pixel_y
# 检查坐标是否在影像范围内
if 0 <= pixel_x < im_width and 0 <= pixel_y < im_height:
valid_pixel_mask[i] = True
else:
valid_pixel_mask[i] = False
if i < 10 or (i % 100 == 0): # 只打印前10个或每100个打印一次
print(f"警告: 坐标点 {i + 1} (UTM X:{utm_x_point:.2f}, Y:{utm_y_point:.2f}) 超出影像范围")
# 批量提取光谱数据优化减少I/O操作
print(f"批量提取光谱数据... (有效坐标点: {np.sum(valid_pixel_mask)})")
if radius > 0:
# 半径采样模式:需要逐个处理
for i in range(coor_data.shape[0]):
if valid_pixel_mask[i]:
spectrum = get_average_spectral_in_radius(
dataset, pixel_x_array[i], pixel_y_array[i], radius, flare_mask, boundary_mask
)
coor_spectral[i, original_cols + 2:] = spectrum
else:
coor_spectral[i, original_cols + 2:] = np.zeros(num_bands)
else:
# 单点采样模式:批量读取(优化)
# 预读取所有波段数据(如果内存允许)
try:
# 尝试读取所有波段到内存(适用于内存充足的情况)
print("正在预加载所有波段数据到内存(优化模式)...")
all_bands_data = []
for band_idx in range(num_bands):
band = dataset.GetRasterBand(band_idx + 1)
band_data = band.ReadAsArray()
all_bands_data.append(band_data)
all_bands_data = np.array(all_bands_data) # shape: (bands, height, width)
print("预加载完成,开始批量提取像素值...")
# 批量提取像素值
for i in range(coor_data.shape[0]):
if valid_pixel_mask[i]:
px, py = int(pixel_x_array[i]), int(pixel_y_array[i])
# GDAL读取的数组形状是 (bands, height, width),像素坐标 (x,y) 对应数组索引 [:, y, x]
# 注意py是行y坐标px是列x坐标
if 0 <= px < all_bands_data.shape[2] and 0 <= py < all_bands_data.shape[1]:
spectrum = all_bands_data[:, py, px] # 直接索引,非常快
coor_spectral[i, original_cols + 2:] = spectrum
else:
coor_spectral[i, original_cols + 2:] = np.zeros(num_bands)
else:
coor_spectral[i, original_cols + 2:] = np.zeros(num_bands)
# 释放内存
del all_bands_data
print("批量提取完成")
except MemoryError:
# 如果内存不足,回退到逐个波段读取
print("内存不足,使用逐个波段读取模式...")
for i in range(coor_data.shape[0]):
if valid_pixel_mask[i]:
px, py = pixel_x_array[i], pixel_y_array[i]
spectrum = np.zeros(num_bands)
for band_idx in range(num_bands):
band = dataset.GetRasterBand(band_idx + 1)
spectrum[band_idx] = band.ReadAsArray(px, py, 1, 1)[0, 0]
coor_spectral[i, original_cols + 2:] = spectrum
else:
coor_spectral[i, original_cols + 2:] = np.zeros(num_bands)
del dataset
# 创建DataFrame用于CSV输出
# 去除前两列坐标列纬度和经度和UTM列
try:
# 如果原始数据有列名,使用原始列名(跳过前两列)
if coor_df is not None and hasattr(coor_df, 'columns'):
# 跳过前两列经纬度从第3列开始
if len(coor_df.columns) >= original_cols:
# 保留第3列及之后的原始列如果有的话
if original_cols > 2:
original_columns = list(coor_df.columns[2:original_cols])
else:
original_columns = []
else:
# 如果原始列数不足,只保留存在的列(跳过前两列)
if len(coor_df.columns) > 2:
original_columns = list(coor_df.columns[2:])
else:
original_columns = []
else:
# 如果没有列名只保留第3列及之后的列如果有的话
if original_cols > 2:
original_columns = ["col_" + str(j + 1) for j in range(2, original_cols)]
else:
original_columns = []
except:
# 异常处理只保留第3列及之后的列如果有的话
if original_cols > 2:
original_columns = ["col_" + str(j + 1) for j in range(2, original_cols)]
else:
original_columns = []
# 读取波长信息,用作光谱列名
wavelengths = None
try:
in_hdr_dict = spectral.envi.read_envi_header(get_hdr_file_path(imgpath))
wavelengths = np.array(in_hdr_dict['wavelength']).astype('float64')
# 将波长值转换为字符串作为列名
spectral_columns = [str(wl) for wl in wavelengths]
print(f"成功读取波长信息,共 {len(spectral_columns)} 个波段")
except Exception as e:
print(f"警告: 无法读取波长信息 ({str(e)}),使用默认列名 band_1, band_2, ...")
spectral_columns = ["band_" + str(j + 1) for j in range(num_bands)]
# 构建输出列名不包含前两列坐标列和UTM列
all_columns = original_columns + spectral_columns
# 从coor_spectral中提取需要输出的列
# 跳过前两列经纬度和UTM列只保留
# - 第3列到第original_cols列如果有的话
# - 光谱数据列从original_cols+2开始
output_data = []
if original_cols > 2:
# 保留第3列到第original_cols列
output_data.append(coor_spectral[:, 2:original_cols])
# 保留光谱数据列从original_cols+2开始
output_data.append(coor_spectral[:, original_cols + 2:])
# 合并数据
if len(output_data) > 0:
output_array = np.hstack(output_data) if len(output_data) > 1 else output_data[0]
else:
# 如果没有原始列,只输出光谱数据
output_array = coor_spectral[:, original_cols + 2:]
# 创建结果DataFrame
result_df = pd.DataFrame(output_array, columns=all_columns)
# 保存为CSV格式
result_df.to_csv(outpath, index=False, float_format='%.6f')
print(f"结果已保存到CSV文件: {outpath}")
return coor_spectral
# 直接运行示例
if __name__ == '__main__':
# 在这里直接设置参数
imgpath = r"E:\code\WQ\封装\work_dir\3_deglint\deglint_goodman.bsq" # BIL格式影像文件路径
coorpath = r"E:\code\WQ\封装\work_dir\4_processed_data\processed_data.csv"# CSV格式坐标文件路径第1、2列为纬度和经度
output_path = r"E:\code\WQ\封装\work_dir\5_training_spectra/yangdian_output.csv" # CSV格式输出文件路径
radius = 5 # 采样半径像素0表示单点采样>0表示半径内平均
flare_path = r"E:\code\WQ\封装\work_dir\2_glint\severe_glint_area.dat" # 耀斑掩膜文件路径可选None表示不使用
boundary_path = r"D:\BaiduNetdiskDownload\yaobao\water_mask.dat" # 边界掩膜文件路径可选None表示不使用
source_epsg = 4326 # 源坐标系EPSG代码默认为4326 (WGS84地理坐标系)
verbose = True # 是否启用详细模式
if verbose:
print(f"影像文件: {imgpath}")
print(f"坐标文件: {coorpath}")
print(f"输出文件: {output_path}")
print(f"采样半径: {radius}")
if flare_path:
print(f"耀斑掩膜: {flare_path}")
if boundary_path:
print(f"边界掩膜: {boundary_path}")
if source_epsg:
print(f"指定坐标系: EPSG:{source_epsg}")
tmp = get_spectral_in_coor(imgpath, coorpath, output_path,
radius, flare_path, boundary_path, source_epsg)

View File

@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View File

@ -0,0 +1,124 @@
import pandas as pd
# ---- 工具:在多个候选列名里自动匹配实际列名 ----
def _find_col(df, candidates, required=True):
cols = [c.strip() for c in df.columns]
colmap = {c.strip(): c for c in df.columns} # strip 后到原名的映射
for cand in candidates:
if cand in cols:
return colmap[cand]
if required:
raise KeyError(f"找不到列:候选 {candidates} ,实际列有:{list(df.columns)}")
return None
# ---- 主函数:输入文件路径,输出文件路径(直接传参)----
def pick_best_by_target(input_csv: str,
output_csv: str = "best_by_target.csv",
tie_break_priority: list | None = None) -> pd.DataFrame:
"""
读取一个CSV表头包含目标列、测试集R² 等),
按“目标列”分组挑选“测试集R²”最高的那一行并做可选的并列打破
导出到 output_csv并返回结果 DataFrame。
"""
df = pd.read_csv(input_csv)
# 处理表头空格/BOM
df.columns = df.columns.str.replace("\ufeff", "", regex=False).str.strip()
# 兼容多种列名写法
target_col = _find_col(df, ["目标列", "Target", "target"])
test_r2_col = _find_col(df, ["测试集R²", "测试集R2", "测试集R^2", "Test R2", "test_R2", "test r2"])
# 常见可选并列指标(按需要会自动忽略不存在的列)
default_ties = [
# metric, order: "min" 表示越小越好;"max" 表示越大越好
("测试集RMSE", "min"), ("Test RMSE", "min"), ("test_RMSE", "min"),
("测试集MAE", "min"), ("Test MAE", "min"), ("test_MAE", "min"),
("测试集MSE", "min"), ("Test MSE", "min"), ("test_MSE", "min"),
]
# 如果用户传入自定义优先级,就覆盖;否则用默认
tie_break_priority = tie_break_priority or default_ties
# 转数值(无法解析置 NaN
df[test_r2_col] = pd.to_numeric(df[test_r2_col], errors="coerce")
# 仅使用有 R² 的行参与选择
df_valid = df.dropna(subset=[test_r2_col]).copy()
if df_valid.empty:
raise ValueError("没有有效的测试集R²数值全为空无法挑选最佳。")
# 每个目标列的候选数量
counts = df.groupby(target_col).size().rename("模型条数")
# 构造排序键:先按 测试集R² 降序,其次按若干并列指标(若列不存在会被跳过)
sort_cols = [test_r2_col]
sort_ascending = [False] # R² 越大越好
for col_name, order in tie_break_priority:
if col_name in df_valid.columns:
sort_cols.append(col_name)
sort_ascending.append(order == "min") # min → True, max → False
# 对每个目标列分组排序后取第一行
best = (
df_valid
.sort_values(by=sort_cols, ascending=sort_ascending, kind="mergesort")
.groupby(target_col, as_index=False)
.head(1)
)
# 合并候选数量,并按 测试集R² 再整体排序一下(可选)
best = best.merge(counts, left_on=target_col, right_index=True)
best = best.sort_values(by=[test_r2_col], ascending=False)
# 导出
best.to_csv(output_csv, index=False, encoding="utf-8-sig")
return best
# ---- 另一个便捷函数:直接传 DataFrame不用落盘读写----
def pick_best_by_target_df(df: pd.DataFrame,
tie_break_priority: list | None = None) -> pd.DataFrame:
"""
与 pick_best_by_target 相同逻辑,但输入是 DataFrame返回挑选后的 DataFrame。
"""
df = df.copy()
df.columns = df.columns.str.replace("\ufeff", "", regex=False).str.strip()
target_col = _find_col(df, ["目标列", "Target", "target"])
test_r2_col = _find_col(df, ["测试集R²", "测试集R2", "测试集R^2", "Test R2", "test_R2", "test r2"])
default_ties = [
("测试集RMSE", "min"), ("Test RMSE", "min"), ("test_RMSE", "min"),
("测试集MAE", "min"), ("Test MAE", "min"), ("test_MAE", "min"),
("测试集MSE", "min"), ("Test MSE", "min"), ("test_MSE", "min"),
]
tie_break_priority = tie_break_priority or default_ties
df[test_r2_col] = pd.to_numeric(df[test_r2_col], errors="coerce")
df_valid = df.dropna(subset=[test_r2_col]).copy()
if df_valid.empty:
raise ValueError("没有有效的测试集R²数值全为空无法挑选最佳。")
counts = df.groupby(target_col).size().rename("模型条数")
sort_cols = [test_r2_col]
sort_ascending = [False]
for col_name, order in tie_break_priority:
if col_name in df_valid.columns:
sort_cols.append(col_name)
sort_ascending.append(order == "min")
best = (
df_valid
.sort_values(by=sort_cols, ascending=sort_ascending, kind="mergesort")
.groupby(target_col, as_index=False)
.head(1)
.merge(counts, left_on=target_col, right_index=True)
.sort_values(by=[test_r2_col], ascending=False)
)
return best
# 路径方式
res = pick_best_by_target(r"E:\code\WQ\yaobao925\qvchuyaoban\batch_detailed_results.csv", output_csv=r"E:\code\WQ\yaobao925\qvchuyaoban\best_by_target.csv")
print(res.head())
# DataFrame 方式(如果你在笔记本里已有 df
# res_df = pick_best_by_target_df(df)
# res_df.to_csv("best_by_target.csv", index=False, encoding="utf-8-sig")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,392 @@
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
import warnings
warnings.filterwarnings('ignore')
class SingleVariableRegressionAnalysis:
"""
单变量回归分析类,支持多种回归方法和对每个自变量单独分析
"""
def __init__(self):
self.results = []
def linear_regression(self, x, y):
"""线性回归: y = a + b*x"""
try:
x_2d = x.reshape(-1, 1)
model = LinearRegression()
model.fit(x_2d, y)
y_pred = model.predict(x_2d)
r2 = r2_score(y, y_pred)
params = f"y = {model.intercept_:.6f} + {model.coef_[0]:.6f}*x"
return r2, params, y_pred
except Exception as e:
return np.nan, f"Error: {str(e)}", None
def exponential_regression(self, x, y):
"""指数回归: y = a * exp(b*x)"""
try:
# 确保y为正数
if np.any(y <= 0):
return np.nan, "Error: y must be positive for exponential regression", None
# 转换为线性形式: ln(y) = ln(a) + b*x
y_log = np.log(y)
x_2d = x.reshape(-1, 1)
model = LinearRegression()
model.fit(x_2d, y_log)
# 转换回指数形式
a = np.exp(model.intercept_)
b = model.coef_[0]
y_pred = a * np.exp(b * x)
r2 = r2_score(y, y_pred)
params = f"y = {a:.6f} * exp({b:.6f}*x)"
return r2, params, y_pred
except Exception as e:
return np.nan, f"Error: {str(e)}", None
def power_regression(self, x, y):
"""乘幂回归: y = a * x^b"""
try:
# 确保x和y为正数
if np.any(x <= 0) or np.any(y <= 0):
return np.nan, "Error: x and y must be positive for power regression", None
# 转换为线性形式: ln(y) = ln(a) + b*ln(x)
x_log = np.log(x)
y_log = np.log(y)
x_2d = x_log.reshape(-1, 1)
model = LinearRegression()
model.fit(x_2d, y_log)
# 转换回幂函数形式
a = np.exp(model.intercept_)
b = model.coef_[0]
y_pred = a * np.power(x, b)
r2 = r2_score(y, y_pred)
params = f"y = {a:.6f} * x^{b:.6f}"
return r2, params, y_pred
except Exception as e:
return np.nan, f"Error: {str(e)}", None
def logarithmic_regression(self, x, y):
"""对数回归: y = a + b*ln(x)"""
try:
# 确保x为正数
if np.any(x <= 0):
return np.nan, "Error: x must be positive for logarithmic regression", None
# 对x取对数
x_log = np.log(x)
x_2d = x_log.reshape(-1, 1)
model = LinearRegression()
model.fit(x_2d, y)
y_pred = model.predict(x_2d)
r2 = r2_score(y, y_pred)
params = f"y = {model.intercept_:.6f} + {model.coef_[0]:.6f}*ln(x)"
return r2, params, y_pred
except Exception as e:
return np.nan, f"Error: {str(e)}", None
def batch_single_variable_regression(self, data, x_columns, y_columns, methods='all', output_dir='custom_regression_results'):
"""
批量单变量回归分析 - 对每个自变量和因变量组合进行回归
Parameters:
-----------
data : pandas.DataFrame
输入数据
x_columns : list
自变量列名列表,对每个自变量单独进行回归
y_columns : str or list
因变量列名或列名列表
methods : str or list
回归方法,可选 'all' 或方法列表 ['linear', 'exponential', 'power', 'logarithmic']
output_dir : str
输出目录路径每个因变量将单独保存为一个CSV文件
"""
# 处理方法参数
if methods == 'all':
methods = ['linear', 'exponential', 'power', 'logarithmic']
method_functions = {
'linear': self.linear_regression,
'exponential': self.exponential_regression,
'power': self.power_regression,
'logarithmic': self.logarithmic_regression
}
# 确保x_columns为列表
if isinstance(x_columns, str):
x_columns = [x_columns]
# 确保y_columns为列表
if isinstance(y_columns, str):
y_columns = [y_columns]
# 创建输出目录
from pathlib import Path
output_path = Path(output_dir)
output_path.mkdir(exist_ok=True, parents=True)
self.results = {}
all_results = []
print(f"开始单变量回归分析:")
print(f"因变量数量: {len(y_columns)}")
print(f"自变量数量: {len(x_columns)}")
print(f"回归方法: {methods}")
print(f"输出目录: {output_dir}")
print("-" * 80)
# 对每个因变量进行回归分析
for y_col in y_columns:
print(f"\n分析因变量: {y_col}")
self.results[y_col] = []
# 对每个自变量单独进行回归分析
for x_col in x_columns:
print(f"\n 分析自变量: {x_col}")
# 准备数据
x_data = data[x_col].values
y_data = data[y_col].values
# 移除包含NaN的行
valid_mask = ~(np.isnan(x_data) | np.isnan(y_data))
x_clean = x_data[valid_mask]
y_clean = y_data[valid_mask]
if len(x_clean) == 0:
print(f" ⚠ 无有效数据,跳过")
continue
print(f" 有效样本数: {len(x_clean)}")
# 对当前自变量执行所有指定的回归方法
for method_name in methods:
if method_name not in method_functions:
continue
regression_func = method_functions[method_name]
try:
r2, equation, y_pred = regression_func(x_clean, y_clean)
if not np.isnan(r2):
result = {
'regression_method': method_name,
'x_variable': x_col,
'y_variable': y_col,
'r_squared': r2,
'equation': equation,
'sample_size': len(x_clean),
'x_mean': np.mean(x_clean),
'x_std': np.std(x_clean),
'y_mean': np.mean(y_clean),
'y_std': np.std(y_clean)
}
self.results[y_col].append(result)
all_results.append(result)
print(f" {method_name:12} | R² = {r2:.6f}")
else:
print(f" {method_name:12} | 失败")
except Exception as e:
print(f" {method_name:12} | 错误: {str(e)}")
# 为当前因变量保存单独的CSV文件
if self.results[y_col]:
results_df = pd.DataFrame(self.results[y_col])
# 按R²排序
results_df = results_df.sort_values(['x_variable', 'r_squared'], ascending=[True, False])
# 为每个因变量创建单独的文件名
safe_y_name = y_col.replace('/', '_').replace('\\', '_').replace(' ', '_')
output_file = output_path / f"{safe_y_name}_regression_results.csv"
results_df.to_csv(output_file, index=False, encoding='utf-8')
print(f"\n {y_col} 的结果已保存到: {output_file}")
# 显示该因变量的最佳模型
self._show_best_models_for_y(results_df, y_col)
# 保存汇总结果到CSV
if all_results:
summary_df = pd.DataFrame(all_results)
# 按因变量和R²排序
summary_df = summary_df.sort_values(['y_variable', 'x_variable', 'r_squared'], ascending=[True, True, False])
summary_file = output_path / "all_regression_results.csv"
summary_df.to_csv(summary_file, index=False, encoding='utf-8')
print(f"\n汇总结果已保存到: {summary_file}")
return self.results
def _show_best_models_for_y(self, results_df, y_variable):
"""显示指定因变量的最佳回归模型"""
if results_df.empty:
return
print(f"\n {y_variable} 的最佳回归模型:")
for x_var in results_df['x_variable'].unique():
x_results = results_df[results_df['x_variable'] == x_var]
best_model = x_results.loc[x_results['r_squared'].idxmax()]
print(f" 自变量 {x_var}:")
print(f" 方法: {best_model['regression_method']}")
print(f" R²: {best_model['r_squared']:.6f}")
print(f" 方程: {best_model['equation']}")
def _show_best_models(self):
"""显示每个自变量的最佳回归模型"""
if not self.results:
return
print("\n" + "=" * 80)
print("每个自变量的最佳回归模型:")
print("=" * 80)
results_df = pd.DataFrame(self.results)
for x_var in results_df['x_variable'].unique():
x_results = results_df[results_df['x_variable'] == x_var]
best_model = x_results.loc[x_results['r_squared'].idxmax()]
print(f"\n自变量: {x_var}")
print(f" 最佳方法: {best_model['regression_method']}")
print(f" R²: {best_model['r_squared']:.6f}")
print(f" 方程: {best_model['equation']}")
print(f" 样本数: {best_model['sample_size']}")
def get_results_df(self):
"""获取结果DataFrame"""
return pd.DataFrame(self.results)
def get_best_models_summary(self):
"""获取每个自变量的最佳模型汇总"""
if not self.results:
return pd.DataFrame()
results_df = pd.DataFrame(self.results)
best_models = []
for x_var in results_df['x_variable'].unique():
x_results = results_df[results_df['x_variable'] == x_var]
best_model = x_results.loc[x_results['r_squared'].idxmax()].to_dict()
best_models.append(best_model)
return pd.DataFrame(best_models)
def main():
"""主函数示例"""
# 创建示例数据
# 初始化回归分析器
analyzer = SingleVariableRegressionAnalysis()
print("=" * 80)
print("水质参数单变量回归分析")
print("=" * 80)
# 示例1: 使用所有回归方法分析光谱指数
print("\n1. 光谱指数与叶绿素a的回归分析:")
sample_data = pd.read_csv(r"E:\code\WQ\pipeline_result\work_dir\5_training_spectra\water_quality_results.csv")
spectral_indices = ['Al10SABI','Am092Bsub']
results1 = analyzer.batch_single_variable_regression(
data=sample_data,
x_columns=spectral_indices,
y_column='Chlorophyll',
methods='all',
output_file=r'E:\code\WQ\pipeline_result\work_dir\5_training_spectra\spectral_indices_regression.csv'
)
# # 示例2: 使用特定方法分析反射率波段
# print("\n2. 反射率波段与叶绿素a的回归分析:")
# reflectance_bands = ['R443', 'R490', 'R560', 'R665', 'R705', 'R740']
#
# results2 = analyzer.batch_single_variable_regression(
# data=sample_data,
# x_columns=reflectance_bands,
# y_column='Chl_a',
# methods=['linear', 'power', 'logarithmic'],
# output_file='reflectance_bands_regression.csv'
# )
# 示例3: 获取最佳模型汇总
print("\n3. 最佳模型汇总:")
best_models = analyzer.get_best_models_summary()
if not best_models.empty:
print(best_models[['x_variable', 'regression_method', 'r_squared', 'equation']].to_string(index=False))
best_models.to_csv(r'E:\code\WQ\pipeline_result\work_dir\5_training_spectra\best_models_summary.csv', index=False)
print("\n最佳模型汇总已保存到 'best_models_summary.csv'")
#
# def advanced_usage_example():
# """高级使用示例 - 处理实际数据"""
# # 读取您的实际数据
# try:
# # 替换为您的实际数据文件路径
# data = pd.read_csv('your_actual_water_data.csv')
#
# # 假设您的数据包含以下列(根据实际情况调整)
# # 光谱指数列: ['NDCI', 'FLH', 'NDTI', 'SABI', ...]
# # 反射率列: ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', ...] 或 ['R443', 'R490', ...]
# # 水质参数列: ['Chl_a', 'Turbidity', 'TSS', 'CDOM', ...]
#
# analyzer = SingleVariableRegressionAnalysis()
#
# # 分析叶绿素a与所有光谱指数的关系
# spectral_indices = ['NDCI', 'FLH', 'NDTI', 'SABI'] # 替换为您的实际列名
# analyzer.batch_single_variable_regression(
# data=data,
# x_columns=spectral_indices,
# y_column='Chl_a', # 替换为您的实际水质参数列名
# methods='all',
# output_file='chl_a_spectral_regression.csv'
# )
#
# # 分析浊度与反射率波段的关系
# reflectance_bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'] # 替换为您的实际列名
# analyzer.batch_single_variable_regression(
# data=data,
# x_columns=reflectance_bands,
# y_column='Turbidity', # 替换为您的实际水质参数列名
# methods=['linear', 'power'],
# output_file='turbidity_reflectance_regression.csv'
# )
#
# except FileNotFoundError:
# print("请准备您的实际数据文件 'your_actual_water_data.csv'")
# except Exception as e:
# print(f"处理数据时出错: {str(e)}")
if __name__ == "__main__":
main()
# 取消注释以下行来处理您的实际数据
# advanced_usage_example()

View File

@ -0,0 +1,382 @@
import numpy as np
import pandas as pd
import os
from osgeo import gdal
from src.utils.util import *
from src.core.type_define import *
import math
from pyproj import CRS
from pyproj import Transformer
import argparse
import json
def get_spectral_data_from_csv(csv_path, value_col, spectral_start_col, spectral_end_col):
"""
从CSV文件中读取实测值和光谱数据
:param csv_path: CSV文件路径
:param value_col: 实测值列索引
:param spectral_start_col: 光谱数据起始列索引
:param spectral_end_col: 光谱数据结束列索引
:return: 包含实测值和光谱数据的numpy数组和表头信息
"""
try:
# 使用pandas读取CSV数据处理缺失值
df = pd.read_csv(csv_path, na_values=['', ' ', 'NaN', 'nan', 'NULL', 'null'])
# 获取表头
header = df.columns.tolist()
print(f"原始数据形状: {df.shape}")
# 提取实测值列和光谱数据列
measured_values = df.iloc[:, value_col].values
spectral_data = df.iloc[:, spectral_start_col:spectral_end_col+1].values
# 组合数据
combined_data = np.column_stack((measured_values, spectral_data))
# 检查并清理数据中的NaN值
# 找到所有不包含NaN的行
valid_rows = ~np.isnan(combined_data).any(axis=1)
if not np.any(valid_rows):
raise ValueError("所有数据行都包含缺失值,无法进行模型训练")
# 过滤有效数据
cleaned_data = combined_data[valid_rows]
print(f"清理后数据形状: {cleaned_data.shape} (移除了 {combined_data.shape[0] - cleaned_data.shape[0]} 行无效数据)")
return cleaned_data, header
except pd.errors.EmptyDataError:
raise ValueError(f"CSV文件 '{csv_path}' 为空或不存在")
except Exception as e:
raise ValueError(f"读取CSV文件 '{csv_path}' 时出错: {e}")
def fit(x1, x2, y):
A = np.column_stack((x1, x2, np.ones((x2.shape[0], 1))))
coefficients, _, _, _ = np.linalg.lstsq(A, y, rcond=None)
return coefficients
def accuracy_evaluation(x1, x2, y_real, coefficients):
A = np.column_stack((x1, x2, np.ones((x2.shape[0], 1))))
y_pred = A.dot(coefficients)
accuracy = np.absolute((y_real - y_pred) / y_real * 100)
return accuracy
def accuracy_evaluation_tss(x1, x2, y_real, coefficients):
A = np.column_stack((x1, x2, np.ones((x2.shape[0], 1))))
y = A.dot(coefficients)
y_pred = np.exp(y)
accuracy = np.absolute((y_real - y_pred) / y_real * 100)
return accuracy
def get_x_in_coor(coor, *args):
new_columns_counter = len(args)
new_columns = np.zeros((coor.shape[0], new_columns_counter))
coor_extend = np.hstack((coor, new_columns))
for i in range(coor.shape[0]):
for j in range(new_columns_counter):
coor_extend[i, coor_extend.shape[1] - (new_columns_counter - j)] = args[j][
int(coor_extend[i, coor_extend.shape[1] - new_columns_counter - 1]),
int(coor_extend[i, coor_extend.shape[1] - new_columns_counter - 2])]
return coor_extend
def write_model_info(model_type, coefficients, accuracy, long, lat, outpath):
# 将 NumPy 数组转换为列表
#保存模型为json文件包括模型类型、模型系数、准确率、经纬度模型名称由上一级调用决定/model/non_empirical_model/preprocessing_method_model_name.jso
np_dict = {
'model_type': model_type,
'model_info': coefficients.tolist(),
'accuracy': accuracy.tolist(),
'long': long.tolist(),
'lat': lat.tolist()
}
# 将字典写入 JSON 文件,使用 indent 参数进行格式化每一级缩进4个空格
with open(outpath, 'w') as f:
json.dump(np_dict, f, indent=4)
def chl_a(csv_data, outpath_coeff, window=5, header=None): # 叶绿素
"""
叶绿素模型修正
:param csv_data: 从CSV读取的数据数组
:param outpath_coeff: 输出模型信息文件路径
:param window: 窗口大小
:极 header: CSV表头信息
:return: 模型系数
"""
# 实测值在第一列,光谱数据从第二列开始
measured_values = csv_data[:, 0]
spectral_data = csv_data[:, 1:]
# 通过表头查找波长位置
if header is not None:
# 查找波长对应的列索引
wave1_idx = find_wavelength_index(header, 651, spectral_start_col=1)
wave2_idx = find_wavelength_index(header, 707, spectral_start_col=1)
wave3_idx = find_wavelength_index(header, 670, spectral_start_col=1)
else:
# 如果没有表头,使用默认索引
wave1_idx = 651
wave2_idx = 707
wave3_idx = 670
# 计算波段平均值
band_651 = np.mean(spectral_data[:, wave1_idx-window:wave1_idx+window+1], axis=1)
band_707 = np.mean(spectral_data[:, wave2_idx-window:wave2_idx+window+1], axis=1)
band_670 = np.mean(spectral_data[:, wave3_idx-window:wave3_idx+window+1], axis=1)
x = (band_651 - band_707) / (band_707 - band_670)
# 修正模型参数并输出
coefficients = np.polyfit(x, measured_values, 1)
y_pred = np.polyval(coefficients, x)
accuracy = np.absolute((measured_values - y_pred) / measured_values * 100)
# 创建虚拟的经纬度坐标(因为不再需要地理坐标)
long = np.arange(len(measured_values))
lat = np.arange(len(measured_values))
write_model_info("chl-a", coefficients, accuracy, long, lat, outpath_coeff)
return coefficients
def nh3(csv_data, outpath_coeff, window=5, header=None): # 氨氮
measured_values = csv_data[:, 0]
spectral_data = csv_data[:, 1:]
# 通过表头查找波长位置
if header is not None:
wave1_idx = find_wavelength_index(header, 600, spectral_start_col=1)
wave2_idx = find_wavelength_index(header, 500, spectral_start_col=1)
wave3_idx = find_wavelength_index(header, 850, spectral_start_col=1)
else:
wave1_idx = 600
wave2_idx = 500
wave3_idx = 850
band_600 = np.mean(spectral_data[:, wave1_idx-window:wave1_idx+window+1], axis=1)
band_500 = np.mean(spectral_data[:, wave2_idx-window:wave2_idx+window+1], axis=1)
band_850 = np.mean(spectral_data[:, wave3_idx-window:wave3_idx+window+1], axis=1)
x1 = np.log(band_500 / band_850)
x2 = np.exp(band_600 / band_500)
coefficients = fit(x1, x2, measured_values)
accuracy = accuracy_evaluation(x1, x2, measured_values, coefficients)
long = np.arange(len(measured_values))
lat = np.arange(len(measured_values))
write_model_info("nh3", coefficients, accuracy, long, lat, outpath_coeff)
return coefficients
def mno4(csv_data, outpath_coeff, window=5, header=None): # 高猛酸盐
measured_values = csv_data[:, 0]
spectral_data = csv_data[:, 1:]
# 通过表头查找波长位置
if header is not None:
wave1_idx = find_wavelength_index(header, 500, spectral_start_col=1)
wave2_idx = find_wavelength_index(header, 440, spectral_start_col=1)
wave3_idx = find_wavelength_index(header, 610, spectral_start_col=1)
wave4_idx = find_wavelength_index(header, 800, spectral_start_col=1)
else:
wave1_idx = 500
wave2_idx = 440
wave3_idx = 610
wave4_idx = 800
band_500 = np.mean(spectral_data[:, wave1_idx-window:wave1_idx+window+1], axis=1)
band_440 = np.mean(spectral_data[:, wave2_idx-window:wave2_idx+window+1], axis=1)
band_610 = np.mean(spectral_data[:, wave3_idx-window:wave3_idx+window+1], axis=1)
band_800 = np.mean(spectral_data[:, wave4_idx-window:wave4_idx+window+1], axis=1)
x1 = band_500 / band_440
x2 = band_610 / band_800
coefficients = fit(x1, x2, measured_values)
accuracy = accuracy_evaluation(x1, x2, measured_values, coefficients)
long = np.arange(len(measured_values))
lat = np.arange(len(measured_values))
write_model_info("mno4", coefficients, accuracy, long, lat, outpath_coeff)
return coefficients
def tn(csv_data, outpath_coeff, window=5, header=None): # 总氮
measured_values = csv_data[:, 0]
spectral_data = csv_data[:, 1:]
# 通过表头查找波长位置
if header is not None:
wave1_idx = find_wavelength_index(header, 600, spectral_start_col=1)
wave2_idx = find_wavelength_index(header, 500, spectral_start_col=1)
wave3_idx = find_wavelength_index(header, 850, spectral_start_col=1)
else:
wave1_idx = 600
wave2_idx = 500
wave3_idx = 850
band_600 = np.mean(spectral_data[:, wave1_idx-window:wave1_idx+window+1], axis=1)
band_500 = np.mean(spectral_data[:, wave2_idx-window:wave2_idx+window+1], axis=1)
band_850 = np.mean(spectral_data[:, wave3_idx-window:wave3_idx+window+1], axis=1)
x1 = np.log(band_500 / band_850)
x2 = np.exp(band_600 / band_500)
coefficients = fit(x1, x2, measured_values)
accuracy = accuracy_evaluation(x1, x2, measured_values, coefficients)
long = np.arange(len(measured_values))
lat = np.arange(len(measured_values))
write_model_info("tn", coefficients, accuracy, long, lat, outpath_coeff)
return coefficients
def tp(csv_data, outpath_coeff, window=5, header=None): # 总磷
measured_values = csv_data[:, 0]
spectral_data = csv_data[:, 1:]
# 通过表头查找波长位置
if header is not None:
wave1_idx = find_wavelength_index(header, 600, spectral_start_col=1)
wave2_idx = find_wavelength_index(header, 500, spectral_start_col=1)
wave3_idx = find_wavelength_index(header, 850, spectral_start_col=1)
else:
wave1_idx = 600
wave2_idx = 500
wave3_idx = 850
band_600 = np.mean(spectral_data[:, wave1_idx-window:wave1_idx+window+1], axis=1)
band_500 = np.mean(spectral_data[:, wave2_idx-window:wave2_idx+window+1], axis=1)
band_850 = np.mean(spectral_data[:, wave3_idx-window:wave3_idx+window+1], axis=1)
x1 = np.log(band_500 / band_850)
x2 = np.exp(band_600 / band_500)
coefficients = fit(x1, x2, measured_values)
accuracy = accuracy_evaluation(x1, x2, measured_values, coefficients)
long = np.arange(len(measured_values))
lat = np.arange(len(measured_values))
write_model_info("tp", coefficients, accuracy, long, lat, outpath_coeff)
return coefficients
def tss(csv_data, outpath_coeff, window=5, header=None): # 总悬浮物
measured_values = csv_data[:, 0]
spectral_data = csv_data[:, 1:]
# 通过表头查找波长位置
if header is not None:
wave1_idx = find_wavelength_index(header, 555, spectral_start_col=1)
wave2_idx = find_wavelength_index(header, 670, spectral_start_col=1)
wave3_idx = find_wavelength_index(header, 490, spectral_start_col=1)
else:
wave1_idx = 555
wave2_idx = 670
wave3_idx = 490
band_555 = np.mean(spectral_data[:, wave1_idx-window:wave1_idx+window+1], axis=1)
band_670 = np.mean(spectral_data[:, wave2_idx-window:wave2_idx+window+1], axis=1)
band_490 = np.mean(spectral_data[:, wave3_idx-window:wave3_idx+window+1], axis=1)
x1 = band_555 + band_670
x2 = band_490 / band_555
y = np.log(measured_values)
coefficients = fit(x1, x2, y)
accuracy = accuracy_evaluation_tss(x1, x2, measured_values, coefficients)
long = np.arange(len(measured_values))
lat = np.arange(len(measured_values))
write_model_info("tss", coefficients, accuracy, long, lat, outpath_coeff)
return coefficients
def run_model_correction(algorithm, csv_file, value_col, spectral_start, spectral_end, model_info_outpath, window=5):
"""
运行模型修正
:param algorithm: 算法名称 (chl_a, nh3, mno4, tn, tp, tss)
:param csv_file: CSV文件路径
:param value_col: 实测值列索引
:param spectral_start: 光谱数据起始列索引
:param spectral_end: 光谱数据结束列索引
:param model_info_outpath: 输出模型信息文件路径
:param window: 窗口大小默认5
:return: 模型系数
"""
# 从CSV文件读取数据和表头直接找到模型对应的所需数据第一列为实测值从第二列开始为光谱数据
csv_data, header = get_spectral_data_from_csv(csv_file, value_col, spectral_start, spectral_end)
# 根据算法名称调用相应的函数
algorithm_funcs = {
'chl_a': chl_a,
'nh3': nh3,
'mno4': mno4,
'tn': tn,
'tp': tp,
'tss': tss
}
if algorithm not in algorithm_funcs:
raise ValueError(f"不支持的算法: {algorithm}。支持的算法有: {list(algorithm_funcs.keys())}")
# 调用相应的函数,传递表头信息
coefficients = algorithm_funcs[algorithm](csv_data, model_info_outpath, window, header)
return coefficients
def find_wavelength_index(header, target_wavelength, spectral_start_col=1):
"""
在表头中查找最接近目标波长的列索引
:param header: CSV表头列表
:param target_wavelength: 目标波长
:param spectral_start_col: 光谱数据起始列索引
:return: 最接近目标波长的列索引
"""
# 从光谱数据起始列开始查找
min_diff = float('inf')
best_index = target_wavelength # 默认值
for i in range(spectral_start_col, len(header)):
try:
# 尝试将列名转换为波长值
wavelength = float(header[i])
diff = abs(wavelength - target_wavelength)
if diff < min_diff:
min_diff = diff
best_index = i - spectral_start_col # 转换为光谱数据内的相对索引
except ValueError:
# 如果列名不是数字,跳过
continue
return best_index

View File

@ -0,0 +1,253 @@
import sys
from src.utils.util import *
import warnings
import pandas as pd
import re # Added for regex parsing in safe_load_spectral
# 配置光谱起始列前四列是坐标和像素信息x_coord,y_coord,pixel_x,pixel_y
SPEC_START_COL = 4
class RetrievalError(Exception):
"""面向用户的友好错误。"""
pass
def ensure_file_exists(path, name):
if not isinstance(path, str) or not path:
raise RetrievalError(f"{name} 路径为空。")
if not os.path.exists(path):
raise RetrievalError(f"{name} 不存在:{path}")
def safe_load_model(model_info_path):
ensure_file_exists(model_info_path, "模型信息文件")
try:
model_type, model_info, accuracy_ = load_numpy_dict_from_json(model_info_path)
except Exception as e:
raise RetrievalError(f"无法读取/解析模型文件:{model_info_path}\n原因:{e}")
if model_info is None:
raise RetrievalError("模型文件缺少 'model_info'")
model_info = np.asarray(model_info)
if model_info.ndim == 0 or model_info.size == 0:
raise RetrievalError("模型系数为空。")
return model_type, model_info, accuracy_
def safe_load_spectral(coor_spectral_path):
ensure_file_exists(coor_spectral_path, "坐标-光谱文件")
# 使用 pandas 读取文件
try:
# 读取为 DataFrame跳过第一行列名明确指定数据类型为 float
df = pd.read_csv(coor_spectral_path, encoding="utf-8-sig", header=0, dtype=float)
# 转换为 numpy 数组以保持原有格式
coor_spectral = df.values
except Exception as e:
raise RetrievalError(f"无法读取坐标-光谱文件:{coor_spectral_path}\n原因:{e}")
if coor_spectral.ndim != 2 or coor_spectral.shape[0] < 1:
raise RetrievalError("坐标-光谱文件维度异常:需要至少一行数据。")
if coor_spectral.shape[1] <= SPEC_START_COL:
raise RetrievalError(f"坐标-光谱文件列数不足(至少需要 {SPEC_START_COL+1} 列,含 4 列坐标信息 + ≥1 列光谱)。")
# 由于第一行已经是数据,不再需要提取波长行
# 波长信息需要从列名中提取
try:
# 读取列名来获取波长信息
df_with_header = pd.read_csv(coor_spectral_path, encoding="utf-8-sig", header=0)
wavelengths = df_with_header.columns[SPEC_START_COL:].astype(float).values
except Exception as e:
raise RetrievalError(f"无法解析波长信息:{e}")
if not np.all(np.isfinite(wavelengths)):
raise RetrievalError("波长数据包含 NaN/Inf。")
# 非严格单调也可,但给出警告
if np.any(np.diff(wavelengths) <= 0):
warnings.warn("波长非严格递增,这可能导致波段匹配误差。", RuntimeWarning)
return coor_spectral, wavelengths
def find_index(wavelength, array):
differences = np.abs(array - wavelength)
min_position = int(np.argmin(differences))
return min_position
def _clamp_window(index_abs, window, ncols, spec_start_col=SPEC_START_COL):
if window is None:
raise RetrievalError("window 为空。")
window = int(window)
if window < 0:
raise RetrievalError(f"window 必须为非负整数,收到:{window}")
left = max(spec_start_col, index_abs - window)
right = min(ncols, index_abs + window + 1)
if right - left <= 0:
raise RetrievalError(f"窗口无有效光谱列left={left}, right={right}, ncols={ncols})。")
return left, right
def get_mean_value(index_abs, array, window):
"""index_abs 为绝对列索引(含前两列坐标),这里会夹紧窗口。"""
left, right = _clamp_window(index_abs, window, array.shape[1], SPEC_START_COL)
# 仅在样本行上取平均
result = array[1:, left:right].mean(axis=1)
if not np.all(np.isfinite(result)):
warnings.warn("均值结果包含 NaN/Inf可能是窗口内存在异常值。", RuntimeWarning)
return result
def calculate(x1, x2, coefficients):
x1 = np.asarray(x1, dtype=np.float64).ravel()
x2 = np.asarray(x2, dtype=np.float64).ravel()
coeffs = np.asarray(coefficients, dtype=np.float64).reshape(-1)
if x1.shape[0] != x2.shape[0]:
raise RetrievalError(f"x1 与 x2 长度不一致: {x1.shape[0]} vs {x2.shape[0]}")
if coeffs.size != 3:
raise RetrievalError(f"线性模型系数应为 3 个x1, x2, 截距),收到 {coeffs.size} 个。")
# 诊断:检查 NaN/Inf
n_bad = (~np.isfinite(x1) | ~np.isfinite(x2)).sum()
if n_bad:
print(f"[警告] x 含 {n_bad} 个非有限值,将产生 NaN。")
# 避免 dot/blAS直接逐元素计算
y_pred = x1 * coeffs[0] + x2 * coeffs[1] + coeffs[2]
return y_pred
def _safe_polyval(coeffs, x, name):
coeffs = np.asarray(coeffs).reshape(-1)
if coeffs.ndim != 1 or coeffs.size < 1:
raise RetrievalError(f"{name} 的多项式系数非法。")
try:
y = np.polyval(coeffs, x)
except Exception as e:
raise RetrievalError(f"{name} 计算失败polyval{e}")
return y
def retrieval_chl_a(model_info_path, coor_spectral_path, output_path, window=5):
model_type, model_info, accuracy_ = safe_load_model(model_info_path)
coor_spectral, wavelengths = safe_load_spectral(coor_spectral_path)
def idx_abs_for(wave):
idx_rel = find_index(wave, wavelengths) # 相对光谱起始列的索引
return SPEC_START_COL + idx_rel # 转为绝对列索引
try:
idx_651 = idx_abs_for(651)
idx_707 = idx_abs_for(707)
idx_670 = idx_abs_for(670)
except Exception as e:
raise RetrievalError(f"波段索引计算失败:{e}")
band_651 = get_mean_value(idx_651, coor_spectral, window)
band_707 = get_mean_value(idx_707, coor_spectral, window)
band_670 = get_mean_value(idx_670, coor_spectral, window)
with np.errstate(divide='ignore', invalid='ignore'):
denom = (band_707 - band_670)
x = (band_651 - band_707) / denom
bad = ~np.isfinite(x)
if bad.any():
warnings.warn(f"chl_a 极速出现 {bad.sum()} 个无效比值分母≈0 或含 NaN这些位置结果将为 NaN。", RuntimeWarning)
retrieval_result = _safe_polyval(model_info, x, "chl_a")
# 创建DataFrame并保存为CSV
result_df = pd.DataFrame({
'longitude': coor_spectral[1:, 0],
'latitude': coor_spectral[1:, 1],
'prediction': retrieval_result
})
try:
result_df.to_csv(output_path, index=False, float_format='%.8f')
except Exception as e:
raise RetrievalError(f"写出结果失败:{output_path}\n原因:{e}")
return result_df.values
def retrieval_nh3(model_info_path, coor_spectral_path, output_path=None, window=5):
model_type, model_info, accuracy_ = safe_load_model(model_info_path)
coor_spectral, wavelengths = safe_load_spectral(coor_spectral_path)
def idx_abs_for(wave):
return SPEC_START_COL + find_index(wave, wavelengths)
idx_600 = idx_abs_for(600)
idx_500 = idx_abs_for(500)
idx_850 = idx_abs_for(850)
band_600 = get_mean_value(idx_600, coor_spectral, window)
band_500 = get_mean_value(idx_500, coor_spectral, window)
band_850 = get_mean_value(idx_850, coor_spectral, window)
with np.errstate(divide='ignore', invalid='ignore'):
x13 = np.log(band_500 / band_850)
x23 = np.exp(band_600 / band_500)
invalid = ~np.isfinite(x13) | ~np.isfinite(x23)
if invalid.any():
warnings.warn(f"nh3 自变量出现 {invalid.sum()} 个无效值0/负数/NaN对应位置结果将为 NaN。", RuntimeWarning)
retrieval_result = calculate(x13, x23, model_info)
# 创建DataFrame
result_df = pd.DataFrame({
'longitude': coor_spectral[1:, 0],
'latitude': coor_spectral[1:, 1],
'prediction': retrieval_result
})
if output_path is not None:
try:
result_df.to_csv(output_path, index=False, float_format='%.8f')
except Exception as e:
raise RetrievalError(f"写出结果失败:{output_path}\n原因:{e}")
return result_df.values
def retrieval_tss(model_info_path, coor_spectral_path, output_path, window=5):
# 先跑 nh3 的同型模型(按你的原逻辑)
position_content = retrieval_nh3(model_info_path, coor_spectral_path, output_path=None, window=window)
# 对结果进行指数变换
predictions = np.exp(position_content[:, -1])
# 创建DataFrame
result_df = pd.DataFrame({
'longitude': position_content[:, 0],
'latitude': position_content[:, 1],
'prediction': predictions
})
if not np.all(np.isfinite(result_df['prediction'])):
warnings.warn("tss 结果包含非有限值(可能因指数溢出),已保留为 NaN。", RuntimeWarning)
try:
result_df.to_csv(output_path, index=False, float_format='%.8f')
except Exception as e:
raise RetrievalError(f"写出结果失败:{output_path}\n原因:{e}")
return result_df.values
def non_empirical_retrieval(algorithm, model_info_path, coor_spectral_path, output_path, wave_radius=5.0):
try:
if algorithm == "chl_a":
return retrieval_chl_a(model_info_path, coor_spectral_path, output_path, wave_radius)
elif algorithm in ["nh3", "mno4", "tn", "tp"]:
return retrieval_nh3(model_info_path, coor_spectral_path, output_path, wave_radius)
elif algorithm == "tss":
return retrieval_tss(model_info_path, coor_spectral_path, output_path, wave_radius)
else:
raise RetrievalError(f"未知算法:{algorithm}可选chl_a / nh3 / mno4 / tn / tp / tss")
except RetrievalError as e:
# 面向用户的友好错误
print(f"[错误] {e}", file=sys.stderr)
sys.exit(2)
except Exception as e:
# 未预料的异常,附带类型与少量上下文
print(f"[致命错误] {type(e).__name__}: {e}", file=sys.stderr)
sys.exit(3)
if __name__ == "__main__":
algorithm= "chl_a"
model_info_path= r"E:\code\WQ\pipeline_result\work_dir\5_training_spectra\6_5_non_empirical_models\SS\SS_chl_a.json"
coor_spectral_path= r"E:\code\WQ\pipeline_result\work_dir\7_sampling\sampling_spectra.csv"
output_path= r"E:\code\WQ\pipeline_result\work_dir\8_predictions\SS_chl_a.csv"
wave_radius=5.0
non_empirical_retrieval(algorithm, model_info_path, coor_spectral_path, output_path, wave_radius)

View File

@ -0,0 +1 @@
# -*- coding: utf-8 -*-

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,894 @@
import numpy as np
import pandas as pd
import joblib
import os
from pathlib import Path
from typing import List, Dict, Union, Tuple, Optional
import warnings
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
import scipy.stats as stats
warnings.filterwarnings('ignore')
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['font.size'] = 12
# 机器学习模型导入 - 改为回归模型
from sklearn.svm import SVR
from sklearn.ensemble import RandomForestRegressor
from sklearn.neighbors import KNeighborsRegressor
from sklearn.linear_model import LinearRegression, Ridge, Lasso, ElasticNet
from sklearn.model_selection import GridSearchCV, cross_val_score, KFold, train_test_split
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
from sklearn.cross_decomposition import PLSRegression
# 第三方模型导入
# try:
# import lightgbm as lgb
# LGB_AVAILABLE = True
# except ImportError:
# LGB_AVAILABLE = False
LGB_AVAILABLE = False # 注释掉lightgbm
# try:
# import catboost as cb
# CB_AVAILABLE = True
# except ImportError:
# CB_AVAILABLE = False
CB_AVAILABLE = False # 注释掉catboost
# 导入预处理模块
# 动态导入预处理模块
import sys
import os
from src.preprocessing.spectral_Preprocessing import Preprocessing
class WaterQualityScatterBatch:
"""水质参数反演批量散点图绘制类"""
def __init__(self):
"""初始化批量散点图绘制类"""
# 定义支持的回归模型及其参数网格
self.model_configs = {
'SVR': {
'model': SVR,
'params': {
'C': [0.1, 1, 10, 100],
'gamma': ['scale', 'auto', 0.001, 0.01, 0.1, 1],
'kernel': ['rbf', 'poly', 'sigmoid'],
'epsilon': [0.01, 0.1, 0.2]
},
'available': True
},
'RF': {
'model': RandomForestRegressor,
'params': {
'n_estimators': [50, 100, 200],
'max_depth': [None, 10, 20, 30],
'min_samples_split': [2, 5, 10],
'min_samples_leaf': [1, 2, 4]
},
'available': True
},
'KNN': {
'model': KNeighborsRegressor,
'params': {
'n_neighbors': [3, 5, 7, 9, 11],
'weights': ['uniform', 'distance'],
'metric': ['euclidean', 'manhattan', 'minkowski']
},
'available': True
},
'LinearRegression': {
'model': LinearRegression,
'params': {
'fit_intercept': [True, False]
},
'available': True
},
'Ridge': {
'model': Ridge,
'params': {
'alpha': [0.01, 0.1, 1, 10, 100],
'fit_intercept': [True, False]
},
'available': True
},
'Lasso': {
'model': Lasso,
'params': {
'alpha': [0.01, 0.1, 1, 10, 100],
'fit_intercept': [True, False],
'max_iter': [1000, 2000]
},
'available': True
},
'ElasticNet': {
'model': ElasticNet,
'params': {
'alpha': [0.01, 0.1, 1, 10],
'l1_ratio': [0.1, 0.3, 0.5, 0.7, 0.9],
'fit_intercept': [True, False],
'max_iter': [1000, 2000]
},
'available': True
},
'XGBoost': {
'model': None, # xgboost is removed, so set to None
'params': {
'n_estimators': [50, 100, 200],
'max_depth': [3, 6, 9],
'learning_rate': [0.01, 0.1, 0.2],
'subsample': [0.8, 0.9, 1.0]
},
'available': False
},
'LightGBM': {
'model': lgb.LGBMRegressor if LGB_AVAILABLE else None,
'params': {
'n_estimators': [50, 100, 200],
'max_depth': [3, 6, 9],
'learning_rate': [0.01, 0.1, 0.2],
'num_leaves': [31, 50, 100]
},
'available': LGB_AVAILABLE
},
'CatBoost': {
'model': cb.CatBoostRegressor if CB_AVAILABLE else None,
'params': {
'iterations': [50, 100, 200],
'depth': [3, 6, 9],
'learning_rate': [0.01, 0.1, 0.2],
'l2_leaf_reg': [1, 3, 5]
},
'available': CB_AVAILABLE
},
'PLS': {
'model': PLSRegression,
'params': {
'n_components': [2, 3, 5, 7, 10]
},
'available': True
}
}
# 预处理方法列表
self.preprocessing_methods = [
"None", "MMS", "SS", "CT", "SNV", "MA", "SG", "MSC", "D1", "D2", "DT", "WVAE"
]
# 样本划分方法列表
self.split_methods = ["random", "spxy", "ks"]
def load_data(self, csv_path: str, target_column_name: str = None, target_column: int = None, feature_start_column: int = 13) -> Tuple[pd.DataFrame, pd.Series]:
"""
加载CSV数据
Args:
csv_path: CSV文件路径
target_column_name: 目标值列名(优先使用)
target_column: 目标值列索引(当列名不存在时使用)
feature_start_column: 特征开始列索引
Returns:
X: 特征数据
y: 目标值数据
"""
data = pd.read_csv(csv_path)
# 根据列名或列索引提取目标值
if target_column_name and target_column_name in data.columns:
print(f"使用列名 '{target_column_name}' 作为目标值")
y = data[target_column_name]
target_col_index = data.columns.get_loc(target_column_name)
elif target_column is not None:
print(f"使用列索引 {target_column} 作为目标值")
y = data.iloc[:, target_column]
target_col_index = target_column
else:
raise ValueError("必须指定 target_column_name 或 target_column")
# 提取特征数据
X = data.iloc[:, feature_start_column:]
# 去除y值为空的行
mask = ~y.isna()
data_cleaned = data[mask]
if target_column_name and target_column_name in data.columns:
y = data_cleaned[target_column_name]
else:
y = data_cleaned.iloc[:, target_col_index]
X = data_cleaned.iloc[:, feature_start_column:]
print(f"数据加载完成:")
print(f" 目标列: {target_column_name if target_column_name else f'索引{target_col_index}'}")
print(f" 样本数量: {X.shape[0]}")
print(f" 特征数量: {X.shape[1]}")
print(f" 目标值范围: {y.min():.4f} ~ {y.max():.4f}")
print(f" 目标值均值: {y.mean():.4f}")
return X, y
def preprocess_data(self, X: pd.DataFrame, method: str) -> np.ndarray:
"""
数据预处理
Args:
X: 原始特征数据
method: 预处理方法
Returns:
预处理后的数据
"""
print(f"应用预处理方法: {method}")
# 如果方法为None直接返回原始数据
if method == "None" or method is None:
print("跳过预处理,使用原始数据")
return X.values
try:
X_processed = Preprocessing(method, X)
# 确保返回的是numpy数组
if isinstance(X_processed, pd.DataFrame):
X_processed = X_processed.values
print(f"预处理完成,数据形状: {X_processed.shape}")
return X_processed
except Exception as e:
print(f"预处理失败: {e}")
print("使用原始数据")
return X.values
def random(self, data, label, test_ratio=0.2, random_state=123):
"""随机划分数据集"""
X_train, X_test, y_train, y_test = train_test_split(
data, label, test_size=test_ratio, random_state=random_state
)
return X_train, X_test, y_train, y_test
def spxy(self, data, label, test_size=0.2):
"""SPXY算法划分数据集"""
# 确保 data 和 label 是 NumPy 数组
data = data.to_numpy() if isinstance(data, pd.DataFrame) else data
label = label.to_numpy() if isinstance(label, pd.Series) else label
# 备份原始数据和标签
x_backup = data
y_backup = label
M = data.shape[0]
N = round((1 - test_size) * M)
samples = np.arange(M)
# 归一化标签数据
label = (label - np.mean(label)) / np.std(label)
D = np.zeros((M, M))
Dy = np.zeros((M, M))
# 计算样本之间的距离
for i in range(M - 1):
xa = data[i, :]
ya = label[i]
for j in range((i + 1), M):
xb = data[j, :]
yb = label[j]
D[i, j] = np.linalg.norm(xa - xb)
Dy[i, j] = np.linalg.norm(ya - yb)
# 距离归一化
Dmax = np.max(D)
Dymax = np.max(Dy)
D = D / Dmax + Dy / Dymax
# 找到最远的两个点
maxD = D.max(axis=0)
index_row = D.argmax(axis=0)
index_column = maxD.argmax()
m = np.zeros(N, dtype=int)
m[0] = index_row[index_column]
m[1] = index_column
dminmax = np.zeros(N)
dminmax[1] = D[m[0], m[1]]
# 根据距离选择训练集
for i in range(2, N):
pool = np.delete(samples, m[:i])
dmin = np.zeros(M - i)
for j in range(M - i):
indexa = pool[j]
d = np.zeros(i)
for k in range(i):
indexb = m[k]
if indexa < indexb:
d[k] = D[indexa, indexb]
else:
d[k] = D[indexb, indexa]
dmin[j] = np.min(d)
dminmax[i] = np.max(dmin)
index = np.argmax(dmin)
m[i] = pool[index]
m_complement = np.delete(samples, m)
# 划分训练集和测试集
X_train = data[m, :]
y_train = y_backup[m]
X_test = data[m_complement, :]
y_test = y_backup[m_complement]
return X_train, X_test, y_train, y_test
def ks(self, data, label, test_size=0.2):
"""Kennard-Stone算法划分数据集"""
# 确保 data 和 label 是 NumPy 数组
data = data.to_numpy() if isinstance(data, pd.DataFrame) else data
label = label.to_numpy() if isinstance(label, pd.Series) else label
M = data.shape[0]
N = round((1 - test_size) * M)
samples = np.arange(M)
D = np.zeros((M, M))
for i in range((M - 1)):
xa = data[i, :]
for j in range((i + 1), M):
xb = data[j, :]
D[i, j] = np.linalg.norm(xa - xb)
maxD = np.max(D, axis=0)
index_row = np.argmax(D, axis=0)
index_column = np.argmax(maxD)
m = np.zeros(N)
m[0] = np.array(index_row[index_column])
m[1] = np.array(index_column)
m = m.astype(int)
dminmax = np.zeros(N)
dminmax[1] = D[m[0], m[1]]
for i in range(2, N):
pool = np.delete(samples, m[:i])
dmin = np.zeros((M - i))
for j in range((M - i)):
indexa = pool[j]
d = np.zeros(i)
for k in range(i):
indexb = m[k]
if indexa < indexb:
d[k] = D[indexa, indexb]
else:
d[k] = D[indexb, indexa]
dmin[j] = np.min(d)
dminmax[i] = np.max(dmin)
index = np.argmax(dmin)
m[i] = pool[index]
m_complement = np.delete(np.arange(data.shape[0]), m)
X_train = data[m, :]
y_train = label[m]
X_test = data[m_complement, :]
y_test = label[m_complement]
return X_train, X_test, y_train, y_test
def split_data(self, X: np.ndarray, y: pd.Series, method: str = "random",
test_size: float = 0.2, random_state: int = 42) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
"""
根据指定方法划分数据集
"""
print(f"使用 {method} 方法划分数据集")
if method == "random":
return self.random(X, y, test_ratio=test_size, random_state=random_state)
elif method == "spxy":
return self.spxy(X, y, test_size=test_size)
elif method == "ks":
return self.ks(X, y, test_size=test_size)
else:
raise ValueError(f"不支持的划分方法: {method}. 支持的方法: {self.split_methods}")
def plot_scatter_with_confidence(self, y_train, y_pred_train, y_test, y_pred_test,
r2_train, mae_train, r2_test, mae_test,
folder_name, split_method, preprocess_method, model_name,
save_path):
"""
绘制带置信区间的散点图,模仿提供的代码样式
参数:
- y_train, y_pred_train: 训练集的真实值和预测值
- y_test, y_pred_test: 测试集的真实值和预测值
- r2_train, mae_train: 训练集的R²和MAE指标
- r2_test, mae_test: 测试集的R²和MAE指标
- folder_name: 文件夹名称
- split_method: 数据划分方法
- preprocess_method: 预处理方法
- model_name: 模型名称
- save_path: 保存路径
"""
# scale_factor 用于放大置信区间
scale_factor = 1.5 # 调整这个值,越大置信区间越宽 scale_factor = 1 是理论上的标准置信区间宽度
confidence = 0.95 # 95% 的置信水平
# 拟合训练集线
z_train = np.polyfit(y_train, y_pred_train, 1)
p_train = np.poly1d(z_train)
predicted_values_train = p_train(y_train)
residuals_train = y_pred_train - predicted_values_train
mean_error_train = np.mean(residuals_train**2)
t_value_train = stats.t.ppf((1 + confidence) / 2., len(y_train) - 1)
ci_train = t_value_train * scale_factor * np.sqrt(mean_error_train) * np.sqrt(1 / len(y_train) + (y_train - np.mean(y_train))**2 / np.sum((y_train - np.mean(y_train))**2))
x_extended_train = np.linspace(min(y_train), max(y_train), 100)
predicted_extended_train = p_train(x_extended_train)
ci_extended_train = t_value_train * scale_factor * np.sqrt(mean_error_train) * np.sqrt(1 / len(y_train) + (x_extended_train - np.mean(y_train))**2 / np.sum((y_train - np.mean(y_train))**2))
# 拟合测试集线
z_test = np.polyfit(y_test, y_pred_test, 1)
p_test = np.poly1d(z_test)
predicted_values_test = p_test(y_test)
residuals_test = y_pred_test - predicted_values_test
mean_error_test = np.mean(residuals_test**2)
t_value_test = stats.t.ppf((1 + confidence) / 2., len(y_test) - 1)
ci_test = t_value_test * scale_factor * np.sqrt(mean_error_test) * np.sqrt(1 / len(y_test) + (y_test - np.mean(y_test))**2 / np.sum((y_test - np.mean(y_test))**2))
x_extended_test = np.linspace(min(y_test), max(y_test), 100)
predicted_extended_test = p_test(x_extended_test)
ci_extended_test = t_value_test * scale_factor * np.sqrt(mean_error_test) * np.sqrt(1 / len(y_test) + (x_extended_test - np.mean(y_test))**2 / np.sum((y_test - np.mean(y_test))**2))
# 设置新的配色方案
train_color = '#1f77b4' # 训练集主色:蓝色系
test_color = '#ff7f0e' # 测试集主色:橙色系
confidence_train_color = '#aec7e8' # 训练集置信区间浅蓝色
confidence_test_color = '#ffbb78' # 测试集置信区间浅橙色
# 设置图形大小和分布
fig = plt.figure(figsize=(10, 8), dpi=300) # 降低dpi以提高兼容性
gs = fig.add_gridspec(4, 4, hspace=0.3, wspace=0.3)
ax_main = fig.add_subplot(gs[1:, :-1]) # 主图
ax_hist_x = fig.add_subplot(gs[0, :-1], sharex=ax_main) # 上方的直方图
ax_hist_y = fig.add_subplot(gs[1:, -1], sharey=ax_main) # 右侧的直方图
# 绘制训练集
ax_main.scatter(y_train, y_pred_train, color=train_color, label="训练集预测值", alpha=0.6)
ax_main.plot(y_train, p_train(y_train), color=train_color, alpha=0.9,
label=f"训练集拟合线\n$R^2$ = {r2_train:.2f}, MAE = {mae_train:.2f}")
ax_main.fill_between(x_extended_train, predicted_extended_train - ci_extended_train,
predicted_extended_train + ci_extended_train,
color=confidence_train_color, alpha=0.5, label="训练集95%置信区间")
# 绘制测试集
ax_main.scatter(y_test, y_pred_test, color=test_color, label="测试集预测值", alpha=0.6)
ax_main.plot(y_test, p_test(y_test), color=test_color, alpha=0.9,
label=f"测试集拟合线\n$R^2$ = {r2_test:.2f}, MAE = {mae_test:.2f}")
ax_main.fill_between(x_extended_test, predicted_extended_test - ci_extended_test,
predicted_extended_test + ci_extended_test,
color=confidence_test_color, alpha=0.5, label="测试集95%置信区间")
# 添加参考线
ax_main.plot([min(y_train.min(), y_test.min()), max(y_train.max(), y_test.max())],
[min(y_train.min(), y_test.min()), max(y_train.max(), y_test.max())],
color='grey', linestyle='--', alpha=0.6, label="1:1 参考线")
# 设置主图
ax_main.set_xlabel("观测值", fontsize=12)
ax_main.set_ylabel("预测值", fontsize=12)
ax_main.legend(loc="upper left", fontsize=10)
ax_main.grid(True, alpha=0.3)
# 绘制上方的直方图 (真实值的分布)
ax_hist_x.hist(y_train, bins=20, color=train_color, alpha=0.7, edgecolor='black', label="训练集观测值分布")
ax_hist_x.hist(y_test, bins=20, color=test_color, alpha=0.7, edgecolor='black', label="测试集观测值分布")
ax_hist_x.tick_params(labelbottom=False) # 隐藏 x 轴的标签
ax_hist_x.set_ylabel("频次", fontsize=10)
ax_hist_x.legend(fontsize=8)
# 绘制右侧的直方图 (预测值的分布)
ax_hist_y.hist(y_pred_train, bins=20, orientation='horizontal', color=train_color, alpha=0.7, edgecolor='black')
ax_hist_y.hist(y_pred_test, bins=20, orientation='horizontal', color=test_color, alpha=0.7, edgecolor='black')
ax_hist_y.set_xlabel("频次", fontsize=10)
ax_hist_y.tick_params(labelleft=False) # 隐藏 y 轴的标签
# 添加标题
title = f'{folder_name} - 最佳模型预测效果对比图\n'
title += f'{split_method}_{preprocess_method}_{model_name}'
fig.suptitle(title, fontsize=14, fontweight='bold')
# 保存和展示图像
plt.tight_layout()
plt.savefig(save_path, format='png', bbox_inches='tight', dpi=300)
print(f"散点图已保存至: {save_path}")
def get_best_model_from_summary(self, artifacts_dir: Path, metric: str = 'test_r2', target_column_name: str = None) -> Tuple[str, str, Dict]:
"""
从训练摘要中获取最佳模型信息
Args:
artifacts_dir: 模型目录
metric: 评估指标
target_column_name: 目标列名(用于构建文件路径)
Returns:
preprocess_method: 预处理方法
model_name: 模型名称
best_result: 最佳模型结果信息
"""
# 清理目标列名,移除可能的特殊字符
if target_column_name:
safe_target_name = "".join(c for c in target_column_name if c.isalnum() or c in ('-', '_')).rstrip()
# 尝试加载以目标列名为前缀的详细结果文件
detailed_path = artifacts_dir / f"{safe_target_name}_detailed_results.csv"
summary_path = artifacts_dir / f"{safe_target_name}_training_summary.csv"
else:
# 兼容旧版本,使用固定文件名
detailed_path = artifacts_dir / "detailed_results.csv"
summary_path = artifacts_dir / "training_summary.csv"
summary_df = None
# 优先使用详细结果文件
if detailed_path.exists():
print(f"使用详细结果文件: {detailed_path}")
summary_df = pd.read_csv(detailed_path)
# 将中文列名映射到英文
metric_mapping = {
'test_r2': '测试集R²',
'train_r2': '训练集R²',
'test_rmse': '测试集RMSE',
'train_rmse': '训练集RMSE',
'cv_mean': 'CV均值'
}
if metric in metric_mapping and metric_mapping[metric] in summary_df.columns:
metric_col = metric_mapping[metric]
else:
metric_col = metric
elif summary_path.exists():
print(f"使用训练摘要文件: {summary_path}")
summary_df = pd.read_csv(summary_path)
metric_col = metric
else:
# 如果使用了目标列名前缀的文件不存在,尝试查找旧版本的文件
if target_column_name:
old_detailed_path = artifacts_dir / "detailed_results.csv"
old_summary_path = artifacts_dir / "training_summary.csv"
if old_detailed_path.exists():
print(f"使用旧版本详细结果文件: {old_detailed_path}")
summary_df = pd.read_csv(old_detailed_path)
# 将中文列名映射到英文
metric_mapping = {
'test_r2': '测试集R²',
'train_r2': '训练集R²',
'test_rmse': '测试集RMSE',
'train_rmse': '训练集RMSE',
'cv_mean': 'CV均值'
}
if metric in metric_mapping and metric_mapping[metric] in summary_df.columns:
metric_col = metric_mapping[metric]
else:
metric_col = metric
elif old_summary_path.exists():
print(f"使用旧版本训练摘要文件: {old_summary_path}")
summary_df = pd.read_csv(old_summary_path)
metric_col = metric
else:
raise FileNotFoundError(f"训练摘要文件不存在: {summary_path}{detailed_path}{old_summary_path}{old_detailed_path}")
else:
raise FileNotFoundError(f"训练摘要文件不存在: {summary_path}{detailed_path}")
if summary_df.empty:
raise ValueError("训练摘要为空")
# 检查指标列是否存在
if metric_col not in summary_df.columns:
available_cols = list(summary_df.columns)
raise ValueError(f"指标 '{metric_col}' 不存在。可用列: {available_cols}")
# 获取最佳模型对于R²等指标值越大越好
if 'r2' in metric.lower() or 'score' in metric.lower():
best_idx = summary_df[metric_col].idxmax()
else: # 对于RMSE、MAE等值越小越好
best_idx = summary_df[metric_col].idxmin()
best_row = summary_df.loc[best_idx]
# 根据文件类型解析模型信息
if '划分方法' in summary_df.columns:
# 详细结果文件格式(中文列名)
split_method = best_row['划分方法']
preprocess_method = best_row['预处理方法']
model_name = best_row['建模方法']
best_combination = f"{split_method}_{preprocess_method}_{model_name}"
else:
# 简化结果文件格式(英文列名)
best_combination = best_row['combination']
# 解析组合名称(格式: split_method_preprocess_method_model_name
parts = best_combination.split('_')
if len(parts) < 3:
raise ValueError(f"无效的模型组合名称格式: {best_combination}")
split_method = parts[0]
preprocess_method = parts[1]
model_name = '_'.join(parts[2:])
print(f"最佳模型组合: {best_combination}")
print(f" 划分方法: {split_method}")
print(f" 预处理方法: {preprocess_method}")
print(f" 模型名称: {model_name}")
print(f" {metric_col}: {best_row[metric_col]:.4f}")
# 构建模型文件前缀
model_file_prefix = f"{split_method}_{preprocess_method}"
# 构建结果信息
best_result = {
'combination': best_combination,
'split_method': split_method,
'preprocess_method': preprocess_method,
'model_name': model_name,
'metric_value': best_row[metric_col],
'model_file_prefix': model_file_prefix
}
# 尝试获取更多指标信息
for col in summary_df.columns:
if col not in ['combination', '划分方法', '预处理方法', '建模方法', '最佳参数']:
try:
best_result[col] = best_row[col]
except:
pass
return model_file_prefix, model_name, best_result
def load_model(self, artifacts_dir: Path, preprocess_method: str, model_name: str, target_column_name: str = None):
"""
加载保存的模型
Args:
artifacts_dir: 模型目录
preprocess_method: 预处理方法名称
model_name: 模型名称
target_column_name: 目标列名(用于构建文件路径)
Returns:
加载的模型数据
"""
if target_column_name:
# 清理目标列名,移除可能的特殊字符
safe_target_name = "".join(c for c in target_column_name if c.isalnum() or c in ('-', '_')).rstrip()
# 尝试加载以目标列名为前缀的模型文件
filename = f"{safe_target_name}_{preprocess_method}_{model_name}.joblib"
filepath = artifacts_dir / filename
if filepath.exists():
print(f"加载模型文件: {filepath}")
return joblib.load(filepath)
# 如果带前缀的文件不存在,尝试加载旧版本的文件
old_filename = f"{preprocess_method}_{model_name}.joblib"
old_filepath = artifacts_dir / old_filename
if old_filepath.exists():
print(f"加载旧版本模型文件: {old_filepath}")
return joblib.load(old_filepath)
raise FileNotFoundError(f"模型文件不存在: {filepath}{old_filepath}")
else:
# 兼容旧版本,使用固定文件名
filename = f"{preprocess_method}_{model_name}.joblib"
filepath = artifacts_dir / filename
if not filepath.exists():
raise FileNotFoundError(f"模型文件不存在: {filepath}")
return joblib.load(filepath)
def plot_best_model_scatter(self, artifacts_dir: str, csv_path: str, output_dir: str,
folder_name: str, metric: str = 'test_r2',
target_column: int = None, feature_start_column: int = 13,
test_size: float = 0.2, random_state: int = 42):
"""
绘制最佳模型的散点图
Args:
artifacts_dir: 模型目录
csv_path: 原始CSV数据文件路径
output_dir: 输出目录
folder_name: 文件夹名称(用作图片名称和目标列名)
metric: 评估指标
target_column: 目标值列索引如果为None则使用folder_name作为列名
feature_start_column: 特征开始列索引
test_size: 测试集比例
random_state: 随机种子
"""
artifacts_path = Path(artifacts_dir)
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
try:
print(f"\n{'='*60}")
print(f"处理文件夹: {folder_name}")
print(f"{'='*60}")
# 获取最佳模型信息
model_file_prefix, model_name, best_result = self.get_best_model_from_summary(
artifacts_path, metric, folder_name
)
# 加载数据 - 优先使用文件夹名称作为目标列名
X_raw, y_true = self.load_data(csv_path, target_column_name=folder_name, target_column=target_column, feature_start_column=feature_start_column)
# 获取最佳模型的预处理方法
actual_preprocess_method = best_result['preprocess_method']
split_method = best_result['split_method']
# 加载最佳模型
best_model_data = self.load_model(artifacts_path, model_file_prefix, model_name, folder_name)
best_model = best_model_data['model']
# 应用相同的数据预处理
X_processed = self.preprocess_data(X_raw, actual_preprocess_method)
# 使用相同的数据分割方法
X_train, X_test, y_train, y_test = self.split_data(
X_processed, y_true, method=split_method,
test_size=test_size, random_state=random_state
)
# 预测训练集和测试集
y_pred_train = best_model.predict(X_train)
y_pred_test = best_model.predict(X_test)
# 计算评估指标
train_r2 = r2_score(y_train, y_pred_train)
test_r2 = r2_score(y_test, y_pred_test)
train_rmse = np.sqrt(mean_squared_error(y_train, y_pred_train))
test_rmse = np.sqrt(mean_squared_error(y_test, y_pred_test))
train_mae = mean_absolute_error(y_train, y_pred_train)
test_mae = mean_absolute_error(y_test, y_pred_test)
# 绘制带置信区间的散点图(模仿提供的代码样式)
self.plot_scatter_with_confidence(
y_train, y_pred_train, y_test, y_pred_test,
train_r2, train_mae, test_r2, test_mae,
folder_name, split_method, actual_preprocess_method, model_name,
output_path / f"{folder_name}_scatter_with_confidence.png"
)
plt.close() # 关闭图形以释放内存
return {
'status': 'success',
'save_path': str(output_path / f"{folder_name}_scatter_with_confidence.png"),
'best_result': best_result,
'metrics': {
'train_r2': train_r2,
'test_r2': test_r2,
'train_rmse': train_rmse,
'test_rmse': test_rmse,
'train_mae': train_mae,
'test_mae': test_mae
}
}
except Exception as e:
print(f"处理文件夹 {folder_name} 失败: {e}")
return {
'status': 'error',
'error': str(e)
}
def batch_plot_scatter(self, models_root_dir: str, csv_path: str, output_dir: str,
metric: str = 'test_r2', target_column: int = None,
feature_start_column: int = 13, test_size: float = 0.2,
random_state: int = 42):
"""
批量处理多个子文件夹中的模型并绘制散点图
Args:
models_root_dir: 包含多个子文件夹的根目录
csv_path: 原始CSV数据文件路径
output_dir: 输出目录
metric: 评估指标
target_column: 目标值列索引如果为None则使用文件夹名称作为列名
feature_start_column: 特征开始列索引
test_size: 测试集比例
random_state: 随机种子
"""
models_root = Path(models_root_dir)
# 查找所有子文件夹
subdirs = [d for d in models_root.iterdir() if d.is_dir()]
if not subdirs:
print(f"在目录 {models_root_dir} 中未找到子文件夹")
return {}
print("=" * 80)
print("批量散点图绘制任务")
print("=" * 80)
print(f"模型根目录: {models_root_dir}")
print(f"数据文件: {csv_path}")
print(f"输出目录: {output_dir}")
print(f"评估指标: {metric}")
print(f"找到 {len(subdirs)} 个模型子文件夹")
print("=" * 80)
all_results = {}
for subdir in subdirs:
folder_name = subdir.name
result = self.plot_best_model_scatter(
artifacts_dir=str(subdir),
csv_path=csv_path,
output_dir=output_dir,
folder_name=folder_name,
metric=metric,
target_column=target_column,
feature_start_column=feature_start_column,
test_size=test_size,
random_state=random_state
)
all_results[folder_name] = result
print(f"\n{'='*80}")
print(f"批量散点图绘制完成,共处理 {len(subdirs)} 个模型文件夹")
print(f"{'='*80}")
# 打印汇总信息
print("\n汇总结果:")
success_count = 0
for folder_name, result in all_results.items():
if result['status'] == 'success':
metrics = result['metrics']
print(f"{folder_name}: 测试集R²={metrics['test_r2']:.4f}, "
f"RMSE={metrics['test_rmse']:.4f}")
success_count += 1
else:
print(f"{folder_name}: 失败 - {result['error']}")
print(f"\n成功处理: {success_count}/{len(subdirs)} 个文件夹")
print(f"输出目录: {output_dir}")
return all_results
def main():
"""主函数示例"""
# 创建批量散点图绘制实例
scatter_batch = WaterQualityScatterBatch()
# 配置路径
models_root_dir = r"E:\code\WQ\yaobao925\qvchuyaoban" # 包含多个子文件夹的根目录
csv_path = r"E:\code\WQ\yaobao925\data\qvyaoban\data.csv" # 原始数据文件
output_dir = r"E:\code\WQ\yaobao925\plot\qvyaoban_sctter" # 散点图输出目录
# 批量绘制散点图
results = scatter_batch.batch_plot_scatter(
models_root_dir=models_root_dir,
csv_path=csv_path,
output_dir=output_dir,
metric='test_r2', # 评估指标
target_column=None, # 使用文件夹名称作为目标列名
feature_start_column=13, # 特征开始列索引
test_size=0.2, # 测试集比例
random_state=42 # 随机种子
)
print("\n任务完成!")
if __name__ == "__main__":
main()

22
src/core/type_define.py Normal file
View File

@ -0,0 +1,22 @@
from enum import Enum, unique
class FlareModel(Enum):
otsu = 0
threshold = 1
img = 2
class ImgType(Enum):
ref = 0
content = 1
# @unique
class CoorType(Enum):
latlong = 0
utm = 1
class PointPosStrategy(Enum):
nearest_single = 0
four_quadrant = 1

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

242
src/gui/STYLES_README.md Normal file
View File

@ -0,0 +1,242 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
水质参数反演分析系统 - UI样式系统文档
Modern UI Stylesheet System Documentation
================================================================================
1. 概述
------
本系统采用现代化的扁平设计风格,提供了一套完整的样式表和主题管理系统。
所有UI组件都遵循统一的设计规范确保整体的视觉一致性和用户体验。
2. 颜色系统
-----------
主要颜色定义在 ModernStylesheet.COLORS 中:
- main_bg (#F0F0F0):主窗口背景,浅灰色
- panel_bg (#FFFFFF):面板/容器背景,纯白色
- text_primary (#000000):主文字颜色,黑色
- text_secondary (#666666):辅助文字颜色,灰色
- border (#D0D0D0):边框颜色,浅灰
- border_light (#E8E8E8):浅边框颜色
- accent (#007BFF):强调色,蓝色
- success (#28A745):成功绿
- error (#DC3545):错误红
- warning (#FFC107):警告黄
- hover (#E8E8E8):悬停背景色
- selected (#0056B3):选中色
3. 按钮样式
-----------
系统提供了四种预定义的按钮样式:
a) 普通按钮normal
background-color: 白色
border: 1px 灰色边框
border-radius: 7px
用法: ModernStylesheet.get_button_stylesheet('normal')
b) 主按钮primary- 蓝色
background-color: 蓝色 (#007BFF)
color: 白色
border-radius: 7px
用法: ModernStylesheet.get_button_stylesheet('primary')
c) 成功按钮success- 绿色
background-color: 绿色 (#28A745)
color: 白色
border-radius: 7px
用法: ModernStylesheet.get_button_stylesheet('success')
常用于:独立运行、确认操作等
d) 危险按钮danger- 红色
background-color: 红色 (#DC3545)
color: 白色
border-radius: 7px
用法: ModernStylesheet.get_button_stylesheet('danger')
常用于:停止、删除操作等
示例代码:
---------
from src.gui.styles import ModernStylesheet
# 创建成功按钮
run_btn = QPushButton("运行")
run_btn.setStyleSheet(ModernStylesheet.get_button_stylesheet('success'))
# 创建危险按钮
stop_btn = QPushButton("停止")
stop_btn.setStyleSheet(ModernStylesheet.get_button_stylesheet('danger'))
4. 输入框样式
-------------
所有输入框QLineEdit, QComboBox, QSpinBox等都采用统一样式
- background-color: 白色
- border: 1px 灰色边框
- border-radius: 5-10px圆角
- 焦点时边框变为蓝色accent color
5. 分组框QGroupBox
----------------------
分组框采用简洁的设计:
- background-color: 白色
- border: 无or仅下边框1px 浅灰)
- border-radius: 0
- 内边距: 9px
6. 复选框和单选框
-----------------
复选框和单选框保持默认样式,具有以下特性:
- 大小: 16x16px
- 选中时蓝色背景accent color
- 边框: 1px 灰色
7. 应用样式表
--------------
主样式表通过 apply_stylesheet() 方法应用到整个应用:
self.setStyleSheet(ModernStylesheet.get_main_stylesheet())
专用样式表可按需应用:
# 工具栏样式
toolbar_widget.setStyleSheet(ModernStylesheet.get_toolbar_stylesheet())
# 边栏样式
sidebar_widget.setStyleSheet(ModernStylesheet.get_sidebar_stylesheet())
8. 布局特点
-----------
应用的主要布局特点:
a) 顶部工具栏
- 白色背景
- 下边框 1px 浅灰
- 包含logo、模块切换按钮、窗口控制按钮
b) 左侧导航栏(宽度:~280px
- 白色背景
- 右边框 1px 浅灰
- 包含步骤列表、运行/停止按钮
- 步骤列表支持选中状态显示
c) 右侧内容区
- 浅灰背景
- 包含标签页、日志区、进度条
- 标签页支持切换
d) 底部状态栏
- 白色背景
- 上边框 1px 浅灰
- 显示当前状态和进度信息
9. 自定义样式
--------------
如需为某个组件应用自定义样式,建议:
a) 简单修改(如颜色):
widget.setStyleSheet(f"background-color: {ModernStylesheet.COLORS['panel_bg']};")
b) 复杂修改:
添加新方法到 ModernStylesheet 类
@staticmethod
def get_custom_stylesheet():
return "..."
c) 一次性样式:
直接在widget.setStyleSheet中定义
注意:保持与整体风格的一致性
10. 最佳实践
--------------
✓ DO:
- 使用 ModernStylesheet 中的颜色常量
- 使用预定义的样式表方法
- 维持一致的间距和圆角半径
- 使用适当的按钮类型success/danger等
- 为交互元素提供hover和pressed状态反馈
✗ DON'T:
- 直接使用硬编码颜色值
- 混合不同的设计风格
- 过度使用渐变和阴影
- 忽视focus和disabled状态
- 使用过小或过大的字体
11. 响应式设计
---------------
系统支持基本的响应式布局:
- 导航栏最大宽度: 280px
- 内容区域自动调整
- 步骤面板自动滚动
12. 字体设置
-----------
主要字体:
- 界面标题Arial, 13-14pt, Bold
- 普通文本:系统默认, 11-12pt
- 等宽字体日志Courier New, 10pt, Monospace
13. 性能优化
-----------
- 样式表在应用启动时加载
- 避免频繁修改样式表
- 使用CSS类而非硬编码样式
- 合理使用selector优化渲染
14. 常见问题
-----------
Q: 如何改变全局字体大小?
A: 修改 ModernStylesheet 类中的样式表定义
Q: 如何添加新的按钮类型?
A: 在 ModernStylesheet 类中添加新方法
Q: 如何支持深色模式?
A: 创建新的样式类,定义深色配色方案
Q: 标签页标签栏消失了怎么办?
A: 检查QTabBar::tab的height设置确保高度大于0
================================================================================
更新历史:
- v1.0: 初始版本,实现现代化扁平设计风格
- v1.1: 改进导航栏和日志区域样式
- v1.2: 添加专用样式表方法(工具栏、边栏等)
================================================================================
"""
# 快速参考表
QUICK_REFERENCE = """
┌─ 快速参考 ─────────────────────────────────────────────────────────────┐
│ │
│ 按钮样式: │
│ 正常: ModernStylesheet.get_button_stylesheet('normal') │
│ 主要: ModernStylesheet.get_button_stylesheet('primary') │
│ 成功: ModernStylesheet.get_button_stylesheet('success') │
│ 危险: ModernStylesheet.get_button_stylesheet('danger') │
│ │
│ 颜色引用: │
│ ModernStylesheet.COLORS['main_bg'] # #F0F0F0 浅灰 │
│ ModernStylesheet.COLORS['panel_bg'] # #FFFFFF 白色 │
│ ModernStylesheet.COLORS['text_primary'] # #000000 黑色 │
│ ModernStylesheet.COLORS['accent'] # #007BFF 蓝色 │
│ ModernStylesheet.COLORS['success'] # #28A745 绿色 │
│ ModernStylesheet.COLORS['error'] # #DC3545 红色 │
│ │
│ 样式表应用: │
│ self.setStyleSheet(ModernStylesheet.get_main_stylesheet()) │
│ widget.setStyleSheet(ModernStylesheet.get_toolbar_stylesheet()) │
│ widget.setStyleSheet(ModernStylesheet.get_sidebar_stylesheet()) │
│ │
└───────────────────────────────────────────────────────────────────────┘
"""
if __name__ == "__main__":
print(QUICK_REFERENCE)

1
src/gui/__init__.py Normal file
View File

@ -0,0 +1 @@
# -*- coding: utf-8 -*-

570
src/gui/styles.py Normal file
View File

@ -0,0 +1,570 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
现代化样式表和主题管理模块
Modern Stylesheet and Theme Management Module
"""
class ModernStylesheet:
"""现代化样式表集合"""
# 颜色定义
COLORS = {
'main_bg': '#F0F0F0', # 主窗口背景:浅灰
'panel_bg': '#FFFFFF', # 面板/容器背景:白色
'text_primary': '#000000', # 主文字:黑色
'text_secondary': '#666666', # 辅助文字:灰色
'border': '#D0D0D0', # 边框:浅灰
'border_light': '#E8E8E8', # 浅边框
'accent': '#007BFF', # 强调色:蓝色
'success': '#28A745', # 成功绿
'error': '#DC3545', # 错误红
'warning': '#FFC107', # 警告黄
'hover': '#E8E8E8', # 悬停背景
'selected': '#0056B3', # 选中色
}
@staticmethod
def get_main_stylesheet():
"""获取主样式表"""
return f"""
/* 主窗口 */
QMainWindow {{
background-color: {ModernStylesheet.COLORS['main_bg']};
}}
/* 中央部件和容器 */
QWidget {{
background-color: {ModernStylesheet.COLORS['main_bg']};
color: {ModernStylesheet.COLORS['text_primary']};
}}
/* 分组框 */
QGroupBox {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
color: {ModernStylesheet.COLORS['text_primary']};
font-weight: bold;
border: 0px;
margin-top: 10px;
padding-top: 15px;
padding-left: 9px;
padding-right: 9px;
padding-bottom: 9px;
border-bottom: 1px solid {ModernStylesheet.COLORS['border_light']};
}}
QGroupBox::title {{
subcontrol-origin: margin;
subcontrol-position: top left;
padding: 0 5px;
font-size: 12px;
font-weight: bold;
color: {ModernStylesheet.COLORS['text_primary']};
}}
/* 按钮 */
QPushButton {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
color: {ModernStylesheet.COLORS['text_primary']};
border: 1px solid {ModernStylesheet.COLORS['border']};
border-radius: 7px;
padding: 3px 5px;
min-height: 25px;
max-height: 33px;
font-size: 12px;
font-weight: normal;
outline: none;
}}
QPushButton:hover {{
background-color: {ModernStylesheet.COLORS['hover']};
border: 1px solid {ModernStylesheet.COLORS['border']};
}}
QPushButton:pressed {{
background-color: {ModernStylesheet.COLORS['border_light']};
}}
QPushButton:disabled {{
background-color: {ModernStylesheet.COLORS['hover']};
color: {ModernStylesheet.COLORS['text_secondary']};
border: 1px solid {ModernStylesheet.COLORS['border_light']};
}}
QPushButton:focus {{
outline: none;
}}
/* 输入框 */
QLineEdit {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
color: {ModernStylesheet.COLORS['text_primary']};
border: 1px solid {ModernStylesheet.COLORS['border']};
border-radius: 10px;
padding: 5px 8px;
min-height: 20px;
selection-background-color: {ModernStylesheet.COLORS['selected']};
selection-color: white;
}}
QLineEdit:focus {{
border: 1px solid {ModernStylesheet.COLORS['accent']};
background-color: {ModernStylesheet.COLORS['panel_bg']};
}}
/* 下拉框 */
QComboBox {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
color: {ModernStylesheet.COLORS['text_primary']};
border: 1px solid {ModernStylesheet.COLORS['border']};
border-radius: 5px;
padding: 5px 8px;
min-height: 25px;
selection-background-color: {ModernStylesheet.COLORS['selected']};
}}
QComboBox:focus {{
border: 1px solid {ModernStylesheet.COLORS['accent']};
}}
QComboBox::drop-down {{
border: 0px;
padding-right: 5px;
}}
QComboBox QAbstractItemView {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
color: {ModernStylesheet.COLORS['text_primary']};
selection-background-color: {ModernStylesheet.COLORS['selected']};
selection-color: white;
border: 1px solid {ModernStylesheet.COLORS['border']};
}}
/* 数值输入框 */
QSpinBox, QDoubleSpinBox {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
color: {ModernStylesheet.COLORS['text_primary']};
border: 1px solid {ModernStylesheet.COLORS['border']};
border-radius: 5px;
padding: 5px 8px;
min-height: 25px;
}}
QSpinBox:focus, QDoubleSpinBox:focus {{
border: 1px solid {ModernStylesheet.COLORS['accent']};
}}
QSpinBox::up-button, QDoubleSpinBox::up-button {{
border: 0px;
padding-right: 5px;
}}
QSpinBox::down-button, QDoubleSpinBox::down-button {{
border: 0px;
padding-right: 5px;
}}
/* 复选框 */
QCheckBox {{
color: {ModernStylesheet.COLORS['text_primary']};
spacing: 5px;
}}
QCheckBox::indicator {{
width: 16px;
height: 16px;
border: 1px solid {ModernStylesheet.COLORS['border']};
border-radius: 3px;
background-color: {ModernStylesheet.COLORS['panel_bg']};
}}
QCheckBox::indicator:checked {{
background-color: {ModernStylesheet.COLORS['accent']};
border: 1px solid {ModernStylesheet.COLORS['accent']};
}}
/* 单选框 */
QRadioButton {{
color: {ModernStylesheet.COLORS['text_primary']};
spacing: 5px;
}}
QRadioButton::indicator {{
width: 16px;
height: 16px;
border: 1px solid {ModernStylesheet.COLORS['border']};
border-radius: 8px;
background-color: {ModernStylesheet.COLORS['panel_bg']};
}}
QRadioButton::indicator:checked {{
background: qradial(circle, {ModernStylesheet.COLORS['accent']} 0%, {ModernStylesheet.COLORS['accent']} 40%, {ModernStylesheet.COLORS['panel_bg']} 60%);
border: 1px solid {ModernStylesheet.COLORS['accent']};
}}
/* 文本编辑框 */
QTextEdit {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
color: {ModernStylesheet.COLORS['text_primary']};
border: 1px solid {ModernStylesheet.COLORS['border']};
border-radius: 5px;
padding: 5px;
selection-background-color: {ModernStylesheet.COLORS['selected']};
selection-color: white;
}}
QTextEdit:focus {{
border: 1px solid {ModernStylesheet.COLORS['accent']};
}}
/* 列表部件 */
QListWidget {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
color: {ModernStylesheet.COLORS['text_primary']};
border: 1px solid {ModernStylesheet.COLORS['border']};
border-radius: 5px;
outline: none;
}}
QListWidget::item {{
padding: 6px;
border: 0px;
}}
QListWidget::item:hover {{
background-color: {ModernStylesheet.COLORS['hover']};
}}
QListWidget::item:selected {{
background-color: {ModernStylesheet.COLORS['selected']};
color: white;
}}
/* 滚动区域 */
QScrollArea {{
background-color: {ModernStylesheet.COLORS['main_bg']};
border: 0px;
}}
/* 滚动条 */
QScrollBar:vertical {{
background-color: {ModernStylesheet.COLORS['main_bg']};
width: 12px;
border: 0px;
}}
QScrollBar::handle:vertical {{
background-color: {ModernStylesheet.COLORS['border']};
border-radius: 6px;
min-height: 20px;
}}
QScrollBar::handle:vertical:hover {{
background-color: {ModernStylesheet.COLORS['text_secondary']};
}}
QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {{
border: 0px;
background-color: transparent;
}}
QScrollBar:horizontal {{
background-color: {ModernStylesheet.COLORS['main_bg']};
height: 12px;
border: 0px;
}}
QScrollBar::handle:horizontal {{
background-color: {ModernStylesheet.COLORS['border']};
border-radius: 6px;
min-width: 20px;
}}
QScrollBar::handle:horizontal:hover {{
background-color: {ModernStylesheet.COLORS['text_secondary']};
}}
QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal {{
border: 0px;
background-color: transparent;
}}
/* 进度条 */
QProgressBar {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
color: {ModernStylesheet.COLORS['text_primary']};
border: 1px solid {ModernStylesheet.COLORS['border']};
border-radius: 5px;
padding: 2px;
text-align: center;
height: 20px;
}}
QProgressBar::chunk {{
background-color: {ModernStylesheet.COLORS['success']};
border-radius: 3px;
}}
/* 标签 */
QLabel {{
color: {ModernStylesheet.COLORS['text_primary']};
background-color: transparent;
}}
/* 标签栏 */
QTabBar::tab {{
background-color: {ModernStylesheet.COLORS['main_bg']};
color: {ModernStylesheet.COLORS['text_primary']};
border: 1px solid {ModernStylesheet.COLORS['border']};
border-bottom: 0px;
padding: 8px 12px;
margin-right: 2px;
border-radius: 5px 5px 0px 0px;
}}
QTabBar::tab:selected {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
border: 1px solid {ModernStylesheet.COLORS['border']};
border-bottom: 2px solid {ModernStylesheet.COLORS['accent']};
color: {ModernStylesheet.COLORS['accent']};
}}
QTabBar::tab:hover {{
background-color: {ModernStylesheet.COLORS['hover']};
}}
QTabWidget::pane {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
border: 1px solid {ModernStylesheet.COLORS['border']};
border-top: 0px;
border-radius: 0px 0px 5px 5px;
}}
/* 菜单栏 */
QMenuBar {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
color: {ModernStylesheet.COLORS['text_primary']};
border-bottom: 1px solid {ModernStylesheet.COLORS['border_light']};
padding: 2px;
}}
QMenuBar::item:selected {{
background-color: {ModernStylesheet.COLORS['hover']};
}}
/* 菜单 */
QMenu {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
color: {ModernStylesheet.COLORS['text_primary']};
border: 1px solid {ModernStylesheet.COLORS['border']};
padding: 4px 0px;
border-radius: 5px;
}}
QMenu::item:selected {{
background-color: {ModernStylesheet.COLORS['hover']};
padding-left: 20px;
}}
QMenu::separator {{
height: 1px;
background-color: {ModernStylesheet.COLORS['border_light']};
margin: 4px 0px;
}}
/* 状态栏 */
QStatusBar {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
color: {ModernStylesheet.COLORS['text_primary']};
border-top: 1px solid {ModernStylesheet.COLORS['border_light']};
}}
/* 框架 */
QFrame {{
background-color: {ModernStylesheet.COLORS['main_bg']};
border: 0px;
}}
/* 对话框 */
QDialog {{
background-color: {ModernStylesheet.COLORS['main_bg']};
}}
/* 消息框 */
QMessageBox {{
background-color: {ModernStylesheet.COLORS['main_bg']};
}}
QMessageBox QLabel {{
color: {ModernStylesheet.COLORS['text_primary']};
}}
"""
@staticmethod
def get_button_stylesheet(style_type='normal'):
"""获取特定样式的按钮样式表"""
colors = ModernStylesheet.COLORS
if style_type == 'primary':
# 蓝色主按钮
return f"""
QPushButton {{
background-color: {colors['accent']};
color: white;
border: 1px solid {colors['accent']};
border-radius: 7px;
padding: 3px 5px;
min-height: 25px;
max-height: 33px;
font-weight: bold;
}}
QPushButton:hover {{
background-color: #0056b3;
border: 1px solid #0056b3;
}}
QPushButton:pressed {{
background-color: #003d82;
}}
QPushButton:disabled {{
background-color: {colors['hover']};
color: {colors['text_secondary']};
border: 1px solid {colors['border_light']};
}}
"""
elif style_type == 'success':
# 绿色成功按钮
return f"""
QPushButton {{
background-color: {colors['success']};
color: white;
border: 1px solid {colors['success']};
border-radius: 7px;
padding: 3px 5px;
min-height: 25px;
max-height: 33px;
font-weight: bold;
}}
QPushButton:hover {{
background-color: #218838;
border: 1px solid #218838;
}}
QPushButton:pressed {{
background-color: #1a6c28;
}}
QPushButton:disabled {{
background-color: {colors['hover']};
color: {colors['text_secondary']};
border: 1px solid {colors['border_light']};
}}
"""
elif style_type == 'danger':
# 红色危险按钮
return f"""
QPushButton {{
background-color: {colors['error']};
color: white;
border: 1px solid {colors['error']};
border-radius: 7px;
padding: 3px 5px;
min-height: 25px;
max-height: 33px;
font-weight: bold;
}}
QPushButton:hover {{
background-color: #c82333;
border: 1px solid #c82333;
}}
QPushButton:pressed {{
background-color: #9a1a24;
}}
QPushButton:disabled {{
background-color: {colors['hover']};
color: {colors['text_secondary']};
border: 1px solid {colors['border_light']};
}}
"""
else: # normal/default
return f"""
QPushButton {{
background-color: {colors['panel_bg']};
color: {colors['text_primary']};
border: 1px solid {colors['border']};
border-radius: 7px;
padding: 3px 5px;
min-height: 25px;
max-height: 33px;
}}
QPushButton:hover {{
background-color: {colors['hover']};
border: 1px solid {colors['border']};
}}
QPushButton:pressed {{
background-color: {colors['border_light']};
}}
QPushButton:disabled {{
background-color: {colors['hover']};
color: {colors['text_secondary']};
border: 1px solid {colors['border_light']};
}}
"""
@staticmethod
def get_toolbar_stylesheet():
"""获取顶部工具栏样式表"""
colors = ModernStylesheet.COLORS
return f"""
QWidget {{
background-color: {colors['panel_bg']};
border-bottom: 1px solid {colors['border_light']};
}}
QLabel {{
color: {colors['text_primary']};
}}
QPushButton {{
background-color: {colors['panel_bg']};
color: {colors['text_primary']};
border: 1px solid {colors['border']};
border-radius: 5px;
padding: 5px 10px;
min-height: 25px;
}}
QPushButton:hover {{
background-color: {colors['hover']};
}}
"""
@staticmethod
def get_sidebar_stylesheet():
"""获取左侧边栏样式表"""
colors = ModernStylesheet.COLORS
return f"""
QWidget {{
background-color: {colors['panel_bg']};
border-right: 1px solid {colors['border_light']};
}}
QLabel {{
color: {colors['text_primary']};
font-weight: bold;
}}
QListWidget {{
background-color: {colors['panel_bg']};
border: 0px;
border-right: 1px solid {colors['border_light']};
}}
QListWidget::item {{
padding: 8px;
border-left: 3px solid transparent;
}}
QListWidget::item:hover {{
background-color: {colors['hover']};
}}
QListWidget::item:selected {{
background-color: transparent;
color: {colors['accent']};
border-left: 3px solid {colors['accent']};
font-weight: bold;
}}
"""

6300
src/gui/water_quality_gui.py Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,15 @@
ENVI
description = {
work_dir\2_glint\severe_glint_area.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["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}

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,1002.515991,0.11209397634185636,y = -0.005956 + 0.001186*x,134,10.960663313432837,3.9096921347220377,0.007041335820895523,0.0138473135041692
logarithmic,Chlorophyll,1002.515991,0.09022914646608904,y = -0.019813 + 0.011526*ln(x),134,10.960663313432837,3.9096921347220377,0.007041335820895523,0.0138473135041692
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 1002.515991 0.11209397634185636 y = -0.005956 + 0.001186*x 134 10.960663313432837 3.9096921347220377 0.007041335820895523 0.0138473135041692
3 logarithmic Chlorophyll 1002.515991 0.09022914646608904 y = -0.019813 + 0.011526*ln(x) 134 10.960663313432837 3.9096921347220377 0.007041335820895523 0.0138473135041692

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,1007.041016,0.13129585788396014,y = -0.007873 + 0.001537*x,134,10.960663313432837,3.9096921347220377,0.008974216417910446,0.016584272713125302
logarithmic,Chlorophyll,1007.041016,0.10398887849221805,y = -0.025553 + 0.014819*ln(x),134,10.960663313432837,3.9096921347220377,0.008974216417910446,0.016584272713125302
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 1007.041016 0.13129585788396014 y = -0.007873 + 0.001537*x 134 10.960663313432837 3.9096921347220377 0.008974216417910446 0.016584272713125302
3 logarithmic Chlorophyll 1007.041016 0.10398887849221805 y = -0.025553 + 0.014819*ln(x) 134 10.960663313432837 3.9096921347220377 0.008974216417910446 0.016584272713125302

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,1011.56897,0.11897246869922418,y = -0.007866 + 0.001621*x,134,10.960663313432837,3.9096921347220377,0.00990283582089552,0.01837518499092342
logarithmic,Chlorophyll,1011.56897,0.09605697495450882,y = -0.026865 + 0.015780*ln(x),134,10.960663313432837,3.9096921347220377,0.00990283582089552,0.01837518499092342
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 1011.56897 0.11897246869922418 y = -0.007866 + 0.001621*x 134 10.960663313432837 3.9096921347220377 0.00990283582089552 0.01837518499092342
3 logarithmic Chlorophyll 1011.56897 0.09605697495450882 y = -0.026865 + 0.015780*ln(x) 134 10.960663313432837 3.9096921347220377 0.00990283582089552 0.01837518499092342

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,374.285004,0.0577461915301245,y = 0.009707 + 0.000311*x,134,10.960663313432837,3.9096921347220377,0.013112298507462688,0.005054260878733534
logarithmic,Chlorophyll,374.285004,0.052490162787109385,y = 0.005636 + 0.003209*ln(x),134,10.960663313432837,3.9096921347220377,0.013112298507462688,0.005054260878733534
exponential,Chlorophyll,374.285004,0.030557192829324564,y = 0.010822 * exp(0.013060*x),134,10.960663313432837,3.9096921347220377,0.013112298507462688,0.005054260878733534
power,Chlorophyll,374.285004,0.02576326804736484,y = 0.009209 * x^0.130700,134,10.960663313432837,3.9096921347220377,0.013112298507462688,0.005054260878733534
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 374.285004 0.0577461915301245 y = 0.009707 + 0.000311*x 134 10.960663313432837 3.9096921347220377 0.013112298507462688 0.005054260878733534
3 logarithmic Chlorophyll 374.285004 0.052490162787109385 y = 0.005636 + 0.003209*ln(x) 134 10.960663313432837 3.9096921347220377 0.013112298507462688 0.005054260878733534
4 exponential Chlorophyll 374.285004 0.030557192829324564 y = 0.010822 * exp(0.013060*x) 134 10.960663313432837 3.9096921347220377 0.013112298507462688 0.005054260878733534
5 power Chlorophyll 374.285004 0.02576326804736484 y = 0.009209 * x^0.130700 134 10.960663313432837 3.9096921347220377 0.013112298507462688 0.005054260878733534

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
logarithmic,Chlorophyll,378.311005,0.008061439581006025,y = 0.013092 + 0.001044*ln(x),134,10.960663313432837,3.9096921347220377,0.01552370895522388,0.00419444858565235
linear,Chlorophyll,378.311005,0.008052879252108514,y = 0.014468 + 0.000096*x,134,10.960663313432837,3.9096921347220377,0.01552370895522388,0.00419444858565235
power,Chlorophyll,378.311005,-0.016155019039159058,y = 0.015641 * x^-0.016124,134,10.960663313432837,3.9096921347220377,0.01552370895522388,0.00419444858565235
exponential,Chlorophyll,378.311005,-0.01708357282563666,y = 0.015362 * exp(-0.001784*x),134,10.960663313432837,3.9096921347220377,0.01552370895522388,0.00419444858565235
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 logarithmic Chlorophyll 378.311005 0.008061439581006025 y = 0.013092 + 0.001044*ln(x) 134 10.960663313432837 3.9096921347220377 0.01552370895522388 0.00419444858565235
3 linear Chlorophyll 378.311005 0.008052879252108514 y = 0.014468 + 0.000096*x 134 10.960663313432837 3.9096921347220377 0.01552370895522388 0.00419444858565235
4 power Chlorophyll 378.311005 -0.016155019039159058 y = 0.015641 * x^-0.016124 134 10.960663313432837 3.9096921347220377 0.01552370895522388 0.00419444858565235
5 exponential Chlorophyll 378.311005 -0.01708357282563666 y = 0.015362 * exp(-0.001784*x) 134 10.960663313432837 3.9096921347220377 0.01552370895522388 0.00419444858565235

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,382.341003,0.010983531384569756,y = 0.013856 + 0.000202*x,134,10.960663313432837,3.9096921347220377,0.016074067164179102,0.007548431031201279
logarithmic,Chlorophyll,382.341003,0.010636805221273526,y = 0.011048 + 0.002157*ln(x),134,10.960663313432837,3.9096921347220377,0.016074067164179102,0.007548431031201279
power,Chlorophyll,382.341003,-0.007234268459601845,y = 0.015174 * x^0.006143,134,10.960663313432837,3.9096921347220377,0.016074067164179102,0.007548431031201279
exponential,Chlorophyll,382.341003,-0.008026222697967267,y = 0.015380 * exp(0.000073*x),134,10.960663313432837,3.9096921347220377,0.016074067164179102,0.007548431031201279
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 382.341003 0.010983531384569756 y = 0.013856 + 0.000202*x 134 10.960663313432837 3.9096921347220377 0.016074067164179102 0.007548431031201279
3 logarithmic Chlorophyll 382.341003 0.010636805221273526 y = 0.011048 + 0.002157*ln(x) 134 10.960663313432837 3.9096921347220377 0.016074067164179102 0.007548431031201279
4 power Chlorophyll 382.341003 -0.007234268459601845 y = 0.015174 * x^0.006143 134 10.960663313432837 3.9096921347220377 0.016074067164179102 0.007548431031201279
5 exponential Chlorophyll 382.341003 -0.008026222697967267 y = 0.015380 * exp(0.000073*x) 134 10.960663313432837 3.9096921347220377 0.016074067164179102 0.007548431031201279

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
logarithmic,Chlorophyll,386.373993,0.004476522091747537,y = 0.013943 + 0.001356*ln(x),134,10.960663313432837,3.9096921347220377,0.017102343283582087,0.007312955327938564
linear,Chlorophyll,386.373993,0.003937809502393641,y = 0.015816 + 0.000117*x,134,10.960663313432837,3.9096921347220377,0.017102343283582087,0.007312955327938564
power,Chlorophyll,386.373993,-0.013451645087448227,y = 0.018099 * x^-0.040970,134,10.960663313432837,3.9096921347220377,0.017102343283582087,0.007312955327938564
exponential,Chlorophyll,386.373993,-0.01526209268366463,y = 0.017374 * exp(-0.004977*x),134,10.960663313432837,3.9096921347220377,0.017102343283582087,0.007312955327938564
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 logarithmic Chlorophyll 386.373993 0.004476522091747537 y = 0.013943 + 0.001356*ln(x) 134 10.960663313432837 3.9096921347220377 0.017102343283582087 0.007312955327938564
3 linear Chlorophyll 386.373993 0.003937809502393641 y = 0.015816 + 0.000117*x 134 10.960663313432837 3.9096921347220377 0.017102343283582087 0.007312955327938564
4 power Chlorophyll 386.373993 -0.013451645087448227 y = 0.018099 * x^-0.040970 134 10.960663313432837 3.9096921347220377 0.017102343283582087 0.007312955327938564
5 exponential Chlorophyll 386.373993 -0.01526209268366463 y = 0.017374 * exp(-0.004977*x) 134 10.960663313432837 3.9096921347220377 0.017102343283582087 0.007312955327938564

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
logarithmic,Chlorophyll,390.410004,0.0033869580773776553,y = 0.014722 + 0.001210*ln(x),134,10.960663313432837,3.9096921347220377,0.017540880597014925,0.00750323608895778
linear,Chlorophyll,390.410004,0.0026484411391527463,y = 0.016458 + 0.000099*x,134,10.960663313432837,3.9096921347220377,0.017540880597014925,0.00750323608895778
power,Chlorophyll,390.410004,-0.01625121404032659,y = 0.019411 * x^-0.060440,134,10.960663313432837,3.9096921347220377,0.017540880597014925,0.00750323608895778
exponential,Chlorophyll,390.410004,-0.018540174411018073,y = 0.018243 * exp(-0.007186*x),134,10.960663313432837,3.9096921347220377,0.017540880597014925,0.00750323608895778
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 logarithmic Chlorophyll 390.410004 0.0033869580773776553 y = 0.014722 + 0.001210*ln(x) 134 10.960663313432837 3.9096921347220377 0.017540880597014925 0.00750323608895778
3 linear Chlorophyll 390.410004 0.0026484411391527463 y = 0.016458 + 0.000099*x 134 10.960663313432837 3.9096921347220377 0.017540880597014925 0.00750323608895778
4 power Chlorophyll 390.410004 -0.01625121404032659 y = 0.019411 * x^-0.060440 134 10.960663313432837 3.9096921347220377 0.017540880597014925 0.00750323608895778
5 exponential Chlorophyll 390.410004 -0.018540174411018073 y = 0.018243 * exp(-0.007186*x) 134 10.960663313432837 3.9096921347220377 0.017540880597014925 0.00750323608895778

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
logarithmic,Chlorophyll,394.450012,0.0016938639111105935,y = 0.015234 + 0.000830*ln(x),134,10.960663313432837,3.9096921347220377,0.01716890298507463,0.007280847323239202
linear,Chlorophyll,394.450012,0.0010649475553690113,y = 0.016503 + 0.000061*x,134,10.960663313432837,3.9096921347220377,0.01716890298507463,0.007280847323239202
power,Chlorophyll,394.450012,-0.023745377413006752,y = 0.020435 * x^-0.094840,134,10.960663313432837,3.9096921347220377,0.01716890298507463,0.007280847323239202
exponential,Chlorophyll,394.450012,-0.02617627918721488,y = 0.018415 * exp(-0.010666*x),134,10.960663313432837,3.9096921347220377,0.01716890298507463,0.007280847323239202
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 logarithmic Chlorophyll 394.450012 0.0016938639111105935 y = 0.015234 + 0.000830*ln(x) 134 10.960663313432837 3.9096921347220377 0.01716890298507463 0.007280847323239202
3 linear Chlorophyll 394.450012 0.0010649475553690113 y = 0.016503 + 0.000061*x 134 10.960663313432837 3.9096921347220377 0.01716890298507463 0.007280847323239202
4 power Chlorophyll 394.450012 -0.023745377413006752 y = 0.020435 * x^-0.094840 134 10.960663313432837 3.9096921347220377 0.01716890298507463 0.007280847323239202
5 exponential Chlorophyll 394.450012 -0.02617627918721488 y = 0.018415 * exp(-0.010666*x) 134 10.960663313432837 3.9096921347220377 0.01716890298507463 0.007280847323239202

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
logarithmic,Chlorophyll,398.493011,0.000857763974499659,y = 0.015092 + 0.000573*ln(x),134,10.960663313432837,3.9096921347220377,0.016425865671641792,0.00705544097312418
linear,Chlorophyll,398.493011,0.0003890186261535922,y = 0.016036 + 0.000036*x,134,10.960663313432837,3.9096921347220377,0.016425865671641792,0.00705544097312418
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 logarithmic Chlorophyll 398.493011 0.000857763974499659 y = 0.015092 + 0.000573*ln(x) 134 10.960663313432837 3.9096921347220377 0.016425865671641792 0.00705544097312418
3 linear Chlorophyll 398.493011 0.0003890186261535922 y = 0.016036 + 0.000036*x 134 10.960663313432837 3.9096921347220377 0.016425865671641792 0.00705544097312418

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
logarithmic,Chlorophyll,402.539001,0.00048016503667658306,y = 0.015505 + 0.000443*ln(x),134,10.960663313432837,3.9096921347220377,0.01653574626865672,0.007288381669035372
linear,Chlorophyll,402.539001,0.0001313248786827259,y = 0.016302 + 0.000021*x,134,10.960663313432837,3.9096921347220377,0.01653574626865672,0.007288381669035372
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 logarithmic Chlorophyll 402.539001 0.00048016503667658306 y = 0.015505 + 0.000443*ln(x) 134 10.960663313432837 3.9096921347220377 0.01653574626865672 0.007288381669035372
3 linear Chlorophyll 402.539001 0.0001313248786827259 y = 0.016302 + 0.000021*x 134 10.960663313432837 3.9096921347220377 0.01653574626865672 0.007288381669035372

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
logarithmic,Chlorophyll,406.588989,0.00016428918964617178,y = 0.015242 + 0.000242*ln(x),134,10.960663313432837,3.9096921347220377,0.015806723880597017,0.006825478500958131
linear,Chlorophyll,406.588989,1.6937017762730378e-06,y = 0.015782 + 0.000002*x,134,10.960663313432837,3.9096921347220377,0.015806723880597017,0.006825478500958131
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 logarithmic Chlorophyll 406.588989 0.00016428918964617178 y = 0.015242 + 0.000242*ln(x) 134 10.960663313432837 3.9096921347220377 0.015806723880597017 0.006825478500958131
3 linear Chlorophyll 406.588989 1.6937017762730378e-06 y = 0.015782 + 0.000002*x 134 10.960663313432837 3.9096921347220377 0.015806723880597017 0.006825478500958131

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
logarithmic,Chlorophyll,410.641998,0.00010695507791136372,y = 0.014822 + 0.000189*ln(x),134,10.960663313432837,3.9096921347220377,0.015261298507462688,0.0065848636688817614
linear,Chlorophyll,410.641998,2.2039578226884515e-06,y = 0.015289 + -0.000003*x,134,10.960663313432837,3.9096921347220377,0.015261298507462688,0.0065848636688817614
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 logarithmic Chlorophyll 410.641998 0.00010695507791136372 y = 0.014822 + 0.000189*ln(x) 134 10.960663313432837 3.9096921347220377 0.015261298507462688 0.0065848636688817614
3 linear Chlorophyll 410.641998 2.2039578226884515e-06 y = 0.015289 + -0.000003*x 134 10.960663313432837 3.9096921347220377 0.015261298507462688 0.0065848636688817614

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,414.699005,9.23718683270014e-05,y = 0.014978 + -0.000015*x,134,10.960663313432837,3.9096921347220377,0.014808014925373135,0.006298696608817295
logarithmic,Chlorophyll,414.699005,1.0794055052776308e-05,y = 0.014674 + 0.000057*ln(x),134,10.960663313432837,3.9096921347220377,0.014808014925373135,0.006298696608817295
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 414.699005 9.23718683270014e-05 y = 0.014978 + -0.000015*x 134 10.960663313432837 3.9096921347220377 0.014808014925373135 0.006298696608817295
3 logarithmic Chlorophyll 414.699005 1.0794055052776308e-05 y = 0.014674 + 0.000057*ln(x) 134 10.960663313432837 3.9096921347220377 0.014808014925373135 0.006298696608817295

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,418.759003,0.0002645667637589666,y = 0.014364 + -0.000025*x,134,10.960663313432837,3.9096921347220377,0.014088052238805972,0.006051440804527788
logarithmic,Chlorophyll,418.759003,7.794051727350038e-06,y = 0.014197 + -0.000047*ln(x),134,10.960663313432837,3.9096921347220377,0.014088052238805972,0.006051440804527788
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 418.759003 0.0002645667637589666 y = 0.014364 + -0.000025*x 134 10.960663313432837 3.9096921347220377 0.014088052238805972 0.006051440804527788
3 logarithmic Chlorophyll 418.759003 7.794051727350038e-06 y = 0.014197 + -0.000047*ln(x) 134 10.960663313432837 3.9096921347220377 0.014088052238805972 0.006051440804527788

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,422.821991,0.0008115657894584016,y = 0.014105 + -0.000042*x,134,10.960663313432837,3.9096921347220377,0.013641977611940298,0.005799322545956216
logarithmic,Chlorophyll,422.821991,0.0001768579797475356,y = 0.014140 + -0.000214*ln(x),134,10.960663313432837,3.9096921347220377,0.013641977611940298,0.005799322545956216
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 422.821991 0.0008115657894584016 y = 0.014105 + -0.000042*x 134 10.960663313432837 3.9096921347220377 0.013641977611940298 0.005799322545956216
3 logarithmic Chlorophyll 422.821991 0.0001768579797475356 y = 0.014140 + -0.000214*ln(x) 134 10.960663313432837 3.9096921347220377 0.013641977611940298 0.005799322545956216

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,426.889008,0.0013073210454338513,y = 0.014170 + -0.000053*x,134,10.960663313432837,3.9096921347220377,0.013589074626865672,0.005728319043930576
logarithmic,Chlorophyll,426.889008,0.0004182937928386421,y = 0.014345 + -0.000325*ln(x),134,10.960663313432837,3.9096921347220377,0.013589074626865672,0.005728319043930576
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 426.889008 0.0013073210454338513 y = 0.014170 + -0.000053*x 134 10.960663313432837 3.9096921347220377 0.013589074626865672 0.005728319043930576
3 logarithmic Chlorophyll 426.889008 0.0004182937928386421 y = 0.014345 + -0.000325*ln(x) 134 10.960663313432837 3.9096921347220377 0.013589074626865672 0.005728319043930576

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,430.959015,0.002347137019542922,y = 0.013733 + -0.000067*x,134,10.960663313432837,3.9096921347220377,0.012997753731343284,0.005410808768465578
logarithmic,Chlorophyll,430.959015,0.0010658686661263461,y = 0.014138 + -0.000489*ln(x),134,10.960663313432837,3.9096921347220377,0.012997753731343284,0.005410808768465578
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 430.959015 0.002347137019542922 y = 0.013733 + -0.000067*x 134 10.960663313432837 3.9096921347220377 0.012997753731343284 0.005410808768465578
3 logarithmic Chlorophyll 430.959015 0.0010658686661263461 y = 0.014138 + -0.000489*ln(x) 134 10.960663313432837 3.9096921347220377 0.012997753731343284 0.005410808768465578

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,435.032013,0.0024283085040497365,y = 0.013179 + -0.000069*x,134,10.960663313432837,3.9096921347220377,0.012427850746268653,0.005435180040005626
logarithmic,Chlorophyll,435.032013,0.0011266238526388417,y = 0.013606 + -0.000506*ln(x),134,10.960663313432837,3.9096921347220377,0.012427850746268653,0.005435180040005626
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 435.032013 0.0024283085040497365 y = 0.013179 + -0.000069*x 134 10.960663313432837 3.9096921347220377 0.012427850746268653 0.005435180040005626
3 logarithmic Chlorophyll 435.032013 0.0011266238526388417 y = 0.013606 + -0.000506*ln(x) 134 10.960663313432837 3.9096921347220377 0.012427850746268653 0.005435180040005626

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,439.109009,0.0042064615418079265,y = 0.013397 + -0.000086*x,134,10.960663313432837,3.9096921347220377,0.012450895522388062,0.005205005715323194
logarithmic,Chlorophyll,439.109009,0.002294686396103418,y = 0.014061 + -0.000691*ln(x),134,10.960663313432837,3.9096921347220377,0.012450895522388062,0.005205005715323194
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 439.109009 0.0042064615418079265 y = 0.013397 + -0.000086*x 134 10.960663313432837 3.9096921347220377 0.012450895522388062 0.005205005715323194
3 logarithmic Chlorophyll 439.109009 0.002294686396103418 y = 0.014061 + -0.000691*ln(x) 134 10.960663313432837 3.9096921347220377 0.012450895522388062 0.005205005715323194

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,443.190002,0.004695213661859765,y = 0.013279 + -0.000091*x,134,10.960663313432837,3.9096921347220377,0.012285432835820896,0.00517286197733264
logarithmic,Chlorophyll,443.190002,0.0026235944054925353,y = 0.013996 + -0.000734*ln(x),134,10.960663313432837,3.9096921347220377,0.012285432835820896,0.00517286197733264
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 443.190002 0.004695213661859765 y = 0.013279 + -0.000091*x 134 10.960663313432837 3.9096921347220377 0.012285432835820896 0.00517286197733264
3 logarithmic Chlorophyll 443.190002 0.0026235944054925353 y = 0.013996 + -0.000734*ln(x) 134 10.960663313432837 3.9096921347220377 0.012285432835820896 0.00517286197733264

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,447.27301,0.005169120886448608,y = 0.013250 + -0.000094*x,134,10.960663313432837,3.9096921347220377,0.012221335820895522,0.005101097814158477
logarithmic,Chlorophyll,447.27301,0.002968315833349222,y = 0.014016 + -0.000770*ln(x),134,10.960663313432837,3.9096921347220377,0.012221335820895522,0.005101097814158477
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 447.27301 0.005169120886448608 y = 0.013250 + -0.000094*x 134 10.960663313432837 3.9096921347220377 0.012221335820895522 0.005101097814158477
3 logarithmic Chlorophyll 447.27301 0.002968315833349222 y = 0.014016 + -0.000770*ln(x) 134 10.960663313432837 3.9096921347220377 0.012221335820895522 0.005101097814158477

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,451.360992,0.004863772601295668,y = 0.013262 + -0.000092*x,134,10.960663313432837,3.9096921347220377,0.012257104477611941,0.00513769471108476
logarithmic,Chlorophyll,451.360992,0.002739591016255649,y = 0.013993 + -0.000745*ln(x),134,10.960663313432837,3.9096921347220377,0.012257104477611941,0.00513769471108476
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 451.360992 0.004863772601295668 y = 0.013262 + -0.000092*x 134 10.960663313432837 3.9096921347220377 0.012257104477611941 0.00513769471108476
3 logarithmic Chlorophyll 451.360992 0.002739591016255649 y = 0.013993 + -0.000745*ln(x) 134 10.960663313432837 3.9096921347220377 0.012257104477611941 0.00513769471108476

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,455.450989,0.005525011318207929,y = 0.013206 + -0.000097*x,134,10.960663313432837,3.9096921347220377,0.012144328358208955,0.005093595896892254
logarithmic,Chlorophyll,455.450989,0.0032249891993542112,y = 0.014012 + -0.000802*ln(x),134,10.960663313432837,3.9096921347220377,0.012144328358208955,0.005093595896892254
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 455.450989 0.005525011318207929 y = 0.013206 + -0.000097*x 134 10.960663313432837 3.9096921347220377 0.012144328358208955 0.005093595896892254
3 logarithmic Chlorophyll 455.450989 0.0032249891993542112 y = 0.014012 + -0.000802*ln(x) 134 10.960663313432837 3.9096921347220377 0.012144328358208955 0.005093595896892254

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,459.545013,0.005303969126716268,y = 0.013029 + -0.000095*x,134,10.960663313432837,3.9096921347220377,0.011992097014925374,0.005076948054716495
logarithmic,Chlorophyll,459.545013,0.0030599507272712767,y = 0.013805 + -0.000778*ln(x),134,10.960663313432837,3.9096921347220377,0.011992097014925374,0.005076948054716495
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 459.545013 0.005303969126716268 y = 0.013029 + -0.000095*x 134 10.960663313432837 3.9096921347220377 0.011992097014925374 0.005076948054716495
3 logarithmic Chlorophyll 459.545013 0.0030599507272712767 y = 0.013805 + -0.000778*ln(x) 134 10.960663313432837 3.9096921347220377 0.011992097014925374 0.005076948054716495

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,463.641998,0.005309017626029533,y = 0.013098 + -0.000096*x,134,10.960663313432837,3.9096921347220377,0.012043410447761194,0.0051616384058770694
logarithmic,Chlorophyll,463.641998,0.00309369061071596,y = 0.013897 + -0.000796*ln(x),134,10.960663313432837,3.9096921347220377,0.012043410447761194,0.0051616384058770694
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 463.641998 0.005309017626029533 y = 0.013098 + -0.000096*x 134 10.960663313432837 3.9096921347220377 0.012043410447761194 0.0051616384058770694
3 logarithmic Chlorophyll 463.641998 0.00309369061071596 y = 0.013897 + -0.000796*ln(x) 134 10.960663313432837 3.9096921347220377 0.012043410447761194 0.0051616384058770694

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,467.743011,0.005910540579640466,y = 0.013129 + -0.000101*x,134,10.960663313432837,3.9096921347220377,0.012021395522388062,0.0051373056777988335
logarithmic,Chlorophyll,467.743011,0.0035312797033351107,y = 0.013992 + -0.000846*ln(x),134,10.960663313432837,3.9096921347220377,0.012021395522388062,0.0051373056777988335
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 467.743011 0.005910540579640466 y = 0.013129 + -0.000101*x 134 10.960663313432837 3.9096921347220377 0.012021395522388062 0.0051373056777988335
3 logarithmic Chlorophyll 467.743011 0.0035312797033351107 y = 0.013992 + -0.000846*ln(x) 134 10.960663313432837 3.9096921347220377 0.012021395522388062 0.0051373056777988335

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,471.846985,0.006597953952974689,y = 0.013090 + -0.000107*x,134,10.960663313432837,3.9096921347220377,0.011916462686567163,0.005154508155317495
logarithmic,Chlorophyll,471.846985,0.004055554987167143,y = 0.014036 + -0.000910*ln(x),134,10.960663313432837,3.9096921347220377,0.011916462686567163,0.005154508155317495
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 471.846985 0.006597953952974689 y = 0.013090 + -0.000107*x 134 10.960663313432837 3.9096921347220377 0.011916462686567163 0.005154508155317495
3 logarithmic Chlorophyll 471.846985 0.004055554987167143 y = 0.014036 + -0.000910*ln(x) 134 10.960663313432837 3.9096921347220377 0.011916462686567163 0.005154508155317495

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,475.954987,0.006969427568661812,y = 0.013222 + -0.000110*x,134,10.960663313432837,3.9096921347220377,0.012010992537313433,0.005173190365687869
logarithmic,Chlorophyll,475.954987,0.0043493646432547495,y = 0.014214 + -0.000945*ln(x),134,10.960663313432837,3.9096921347220377,0.012010992537313433,0.005173190365687869
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 475.954987 0.006969427568661812 y = 0.013222 + -0.000110*x 134 10.960663313432837 3.9096921347220377 0.012010992537313433 0.005173190365687869
3 logarithmic Chlorophyll 475.954987 0.0043493646432547495 y = 0.014214 + -0.000945*ln(x) 134 10.960663313432837 3.9096921347220377 0.012010992537313433 0.005173190365687869

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,480.065002,0.006908555626254476,y = 0.013165 + -0.000112*x,134,10.960663313432837,3.9096921347220377,0.011938738805970149,0.005260977465686793
logarithmic,Chlorophyll,480.065002,0.004358699372388197,y = 0.014181 + -0.000962*ln(x),134,10.960663313432837,3.9096921347220377,0.011938738805970149,0.005260977465686793
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 480.065002 0.006908555626254476 y = 0.013165 + -0.000112*x 134 10.960663313432837 3.9096921347220377 0.011938738805970149 0.005260977465686793
3 logarithmic Chlorophyll 480.065002 0.004358699372388197 y = 0.014181 + -0.000962*ln(x) 134 10.960663313432837 3.9096921347220377 0.011938738805970149 0.005260977465686793

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,484.179993,0.007786080902936532,y = 0.013479 + -0.000120*x,134,10.960663313432837,3.9096921347220377,0.01216315671641791,0.00531894585260112
logarithmic,Chlorophyll,484.179993,0.00503315433665652,y = 0.014599 + -0.001046*ln(x),134,10.960663313432837,3.9096921347220377,0.01216315671641791,0.00531894585260112
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 484.179993 0.007786080902936532 y = 0.013479 + -0.000120*x 134 10.960663313432837 3.9096921347220377 0.01216315671641791 0.00531894585260112
3 logarithmic Chlorophyll 484.179993 0.00503315433665652 y = 0.014599 + -0.001046*ln(x) 134 10.960663313432837 3.9096921347220377 0.01216315671641791 0.00531894585260112

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,488.296997,0.009003426521211222,y = 0.013413 + -0.000127*x,134,10.960663313432837,3.9096921347220377,0.01202031343283582,0.005235852382412684
logarithmic,Chlorophyll,488.296997,0.0059888617317502835,y = 0.014636 + -0.001123*ln(x),134,10.960663313432837,3.9096921347220377,0.01202031343283582,0.005235852382412684
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 488.296997 0.009003426521211222 y = 0.013413 + -0.000127*x 134 10.960663313432837 3.9096921347220377 0.01202031343283582 0.005235852382412684
3 logarithmic Chlorophyll 488.296997 0.0059888617317502835 y = 0.014636 + -0.001123*ln(x) 134 10.960663313432837 3.9096921347220377 0.01202031343283582 0.005235852382412684

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,492.417999,0.009356273796731096,y = 0.013426 + -0.000130*x,134,10.960663313432837,3.9096921347220377,0.011996694029850746,0.00526918646504346
logarithmic,Chlorophyll,492.417999,0.0063786563113004124,y = 0.014714 + -0.001166*ln(x),134,10.960663313432837,3.9096921347220377,0.011996694029850746,0.00526918646504346
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 492.417999 0.009356273796731096 y = 0.013426 + -0.000130*x 134 10.960663313432837 3.9096921347220377 0.011996694029850746 0.00526918646504346
3 logarithmic Chlorophyll 492.417999 0.0063786563113004124 y = 0.014714 + -0.001166*ln(x) 134 10.960663313432837 3.9096921347220377 0.011996694029850746 0.00526918646504346

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,496.542999,0.008454580487572083,y = 0.013491 + -0.000126*x,134,10.960663313432837,3.9096921347220377,0.012105947761194029,0.00537461785981684
logarithmic,Chlorophyll,496.542999,0.005612309162053686,y = 0.014705 + -0.001116*ln(x),134,10.960663313432837,3.9096921347220377,0.012105947761194029,0.00537461785981684
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 496.542999 0.008454580487572083 y = 0.013491 + -0.000126*x 134 10.960663313432837 3.9096921347220377 0.012105947761194029 0.00537461785981684
3 logarithmic Chlorophyll 496.542999 0.005612309162053686 y = 0.014705 + -0.001116*ln(x) 134 10.960663313432837 3.9096921347220377 0.012105947761194029 0.00537461785981684

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,500.67099,0.008930402290994066,y = 0.013947 + -0.000130*x,134,10.960663313432837,3.9096921347220377,0.012519723880597015,0.005386983290859261
logarithmic,Chlorophyll,500.67099,0.006027433290726858,y = 0.015220 + -0.001159*ln(x),134,10.960663313432837,3.9096921347220377,0.012519723880597015,0.005386983290859261
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 500.67099 0.008930402290994066 y = 0.013947 + -0.000130*x 134 10.960663313432837 3.9096921347220377 0.012519723880597015 0.005386983290859261
3 logarithmic Chlorophyll 500.67099 0.006027433290726858 y = 0.015220 + -0.001159*ln(x) 134 10.960663313432837 3.9096921347220377 0.012519723880597015 0.005386983290859261

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,504.802002,0.007851805368295328,y = 0.014159 + -0.000122*x,134,10.960663313432837,3.9096921347220377,0.012821291044776119,0.005386616665575906
logarithmic,Chlorophyll,504.802002,0.005168584239575225,y = 0.015321 + -0.001073*ln(x),134,10.960663313432837,3.9096921347220377,0.012821291044776119,0.005386616665575906
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 504.802002 0.007851805368295328 y = 0.014159 + -0.000122*x 134 10.960663313432837 3.9096921347220377 0.012821291044776119 0.005386616665575906
3 logarithmic Chlorophyll 504.802002 0.005168584239575225 y = 0.015321 + -0.001073*ln(x) 134 10.960663313432837 3.9096921347220377 0.012821291044776119 0.005386616665575906

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,508.936005,0.006500148302153508,y = 0.014525 + -0.000113*x,134,10.960663313432837,3.9096921347220377,0.013285626865671642,0.005484303548583865
logarithmic,Chlorophyll,508.936005,0.004158811025431031,y = 0.015569 + -0.000980*ln(x),134,10.960663313432837,3.9096921347220377,0.013285626865671642,0.005484303548583865
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 508.936005 0.006500148302153508 y = 0.014525 + -0.000113*x 134 10.960663313432837 3.9096921347220377 0.013285626865671642 0.005484303548583865
3 logarithmic Chlorophyll 508.936005 0.004158811025431031 y = 0.015569 + -0.000980*ln(x) 134 10.960663313432837 3.9096921347220377 0.013285626865671642 0.005484303548583865

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,513.073975,0.004917130582781315,y = 0.014969 + -0.000099*x,134,10.960663313432837,3.9096921347220377,0.013879231343283581,0.005544190630289309
logarithmic,Chlorophyll,513.073975,0.0029641857181392783,y = 0.015828 + -0.000836*ln(x),134,10.960663313432837,3.9096921347220377,0.013879231343283581,0.005544190630289309
exponential,Chlorophyll,513.073975,-0.01889032090850251,y = 0.016669 * exp(-0.020406*x),134,10.960663313432837,3.9096921347220377,0.013879231343283581,0.005544190630289309
power,Chlorophyll,513.073975,-0.019715344472010177,y = 0.020892 * x^-0.192919,134,10.960663313432837,3.9096921347220377,0.013879231343283581,0.005544190630289309
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 513.073975 0.004917130582781315 y = 0.014969 + -0.000099*x 134 10.960663313432837 3.9096921347220377 0.013879231343283581 0.005544190630289309
3 logarithmic Chlorophyll 513.073975 0.0029641857181392783 y = 0.015828 + -0.000836*ln(x) 134 10.960663313432837 3.9096921347220377 0.013879231343283581 0.005544190630289309
4 exponential Chlorophyll 513.073975 -0.01889032090850251 y = 0.016669 * exp(-0.020406*x) 134 10.960663313432837 3.9096921347220377 0.013879231343283581 0.005544190630289309
5 power Chlorophyll 513.073975 -0.019715344472010177 y = 0.020892 * x^-0.192919 134 10.960663313432837 3.9096921347220377 0.013879231343283581 0.005544190630289309

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,517.216003,0.004276559761211218,y = 0.015763 + -0.000093*x,134,10.960663313432837,3.9096921347220377,0.014746992537313432,0.005540761628631703
logarithmic,Chlorophyll,517.216003,0.00245772439289782,y = 0.016520 + -0.000761*ln(x),134,10.960663313432837,3.9096921347220377,0.014746992537313432,0.005540761628631703
exponential,Chlorophyll,517.216003,-0.018892619920322984,y = 0.017382 * exp(-0.018434*x),134,10.960663313432837,3.9096921347220377,0.014746992537313432,0.005540761628631703
power,Chlorophyll,517.216003,-0.0194484153066794,y = 0.021251 * x^-0.172972,134,10.960663313432837,3.9096921347220377,0.014746992537313432,0.005540761628631703
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 517.216003 0.004276559761211218 y = 0.015763 + -0.000093*x 134 10.960663313432837 3.9096921347220377 0.014746992537313432 0.005540761628631703
3 logarithmic Chlorophyll 517.216003 0.00245772439289782 y = 0.016520 + -0.000761*ln(x) 134 10.960663313432837 3.9096921347220377 0.014746992537313432 0.005540761628631703
4 exponential Chlorophyll 517.216003 -0.018892619920322984 y = 0.017382 * exp(-0.018434*x) 134 10.960663313432837 3.9096921347220377 0.014746992537313432 0.005540761628631703
5 power Chlorophyll 517.216003 -0.0194484153066794 y = 0.021251 * x^-0.172972 134 10.960663313432837 3.9096921347220377 0.014746992537313432 0.005540761628631703

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,521.361023,0.002867645407956476,y = 0.015976 + -0.000077*x,134,10.960663313432837,3.9096921347220377,0.01513621641791045,0.0055935618166287285
logarithmic,Chlorophyll,521.361023,0.001510103149844122,y = 0.016540 + -0.000602*ln(x),134,10.960663313432837,3.9096921347220377,0.01513621641791045,0.0055935618166287285
exponential,Chlorophyll,521.361023,-0.013492164822140218,y = 0.017293 * exp(-0.014959*x),134,10.960663313432837,3.9096921347220377,0.01513621641791045,0.0055935618166287285
power,Chlorophyll,521.361023,-0.01389692075440152,y = 0.020293 * x^-0.139034,134,10.960663313432837,3.9096921347220377,0.01513621641791045,0.0055935618166287285
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 521.361023 0.002867645407956476 y = 0.015976 + -0.000077*x 134 10.960663313432837 3.9096921347220377 0.01513621641791045 0.0055935618166287285
3 logarithmic Chlorophyll 521.361023 0.001510103149844122 y = 0.016540 + -0.000602*ln(x) 134 10.960663313432837 3.9096921347220377 0.01513621641791045 0.0055935618166287285
4 exponential Chlorophyll 521.361023 -0.013492164822140218 y = 0.017293 * exp(-0.014959*x) 134 10.960663313432837 3.9096921347220377 0.01513621641791045 0.0055935618166287285
5 power Chlorophyll 521.361023 -0.01389692075440152 y = 0.020293 * x^-0.139034 134 10.960663313432837 3.9096921347220377 0.01513621641791045 0.0055935618166287285

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,525.508972,0.0016701377663735917,y = 0.016584 + -0.000059*x,134,10.960663313432837,3.9096921347220377,0.015935962686567166,0.005657732827939037
logarithmic,Chlorophyll,525.508972,0.0007153098124390578,y = 0.016913 + -0.000419*ln(x),134,10.960663313432837,3.9096921347220377,0.015935962686567166,0.005657732827939037
exponential,Chlorophyll,525.508972,-0.011873247394506237,y = 0.017736 * exp(-0.012223*x),134,10.960663313432837,3.9096921347220377,0.015935962686567166,0.005657732827939037
power,Chlorophyll,525.508972,-0.01195937275095682,y = 0.020122 * x^-0.111667,134,10.960663313432837,3.9096921347220377,0.015935962686567166,0.005657732827939037
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 525.508972 0.0016701377663735917 y = 0.016584 + -0.000059*x 134 10.960663313432837 3.9096921347220377 0.015935962686567166 0.005657732827939037
3 logarithmic Chlorophyll 525.508972 0.0007153098124390578 y = 0.016913 + -0.000419*ln(x) 134 10.960663313432837 3.9096921347220377 0.015935962686567166 0.005657732827939037
4 exponential Chlorophyll 525.508972 -0.011873247394506237 y = 0.017736 * exp(-0.012223*x) 134 10.960663313432837 3.9096921347220377 0.015935962686567166 0.005657732827939037
5 power Chlorophyll 525.508972 -0.01195937275095682 y = 0.020122 * x^-0.111667 134 10.960663313432837 3.9096921347220377 0.015935962686567166 0.005657732827939037

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,529.659973,0.001100615217659584,y = 0.016897 + -0.000048*x,134,10.960663313432837,3.9096921347220377,0.016371305970149252,0.005647344987370815
logarithmic,Chlorophyll,529.659973,0.00038742510141320796,y = 0.017089 + -0.000308*ln(x),134,10.960663313432837,3.9096921347220377,0.016371305970149252,0.005647344987370815
power,Chlorophyll,529.659973,-0.010602748616709512,y = 0.019984 * x^-0.095978,134,10.960663313432837,3.9096921347220377,0.016371305970149252,0.005647344987370815
exponential,Chlorophyll,529.659973,-0.010676230097632189,y = 0.017950 * exp(-0.010610*x),134,10.960663313432837,3.9096921347220377,0.016371305970149252,0.005647344987370815
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 529.659973 0.001100615217659584 y = 0.016897 + -0.000048*x 134 10.960663313432837 3.9096921347220377 0.016371305970149252 0.005647344987370815
3 logarithmic Chlorophyll 529.659973 0.00038742510141320796 y = 0.017089 + -0.000308*ln(x) 134 10.960663313432837 3.9096921347220377 0.016371305970149252 0.005647344987370815
4 power Chlorophyll 529.659973 -0.010602748616709512 y = 0.019984 * x^-0.095978 134 10.960663313432837 3.9096921347220377 0.016371305970149252 0.005647344987370815
5 exponential Chlorophyll 529.659973 -0.010676230097632189 y = 0.017950 * exp(-0.010610*x) 134 10.960663313432837 3.9096921347220377 0.016371305970149252 0.005647344987370815

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,533.815002,0.0005274884679772329,y = 0.017331 + -0.000034*x,134,10.960663313432837,3.9096921347220377,0.016960171641791044,0.005752288800181051
logarithmic,Chlorophyll,533.815002,9.639796014881963e-05,y = 0.017325 + -0.000156*ln(x),134,10.960663313432837,3.9096921347220377,0.016960171641791044,0.005752288800181051
power,Chlorophyll,533.815002,-0.010942625292486463,y = 0.020200 * x^-0.085250,134,10.960663313432837,3.9096921347220377,0.016960171641791044,0.005752288800181051
exponential,Chlorophyll,533.815002,-0.011375297319334177,y = 0.018394 * exp(-0.009577*x),134,10.960663313432837,3.9096921347220377,0.016960171641791044,0.005752288800181051
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 533.815002 0.0005274884679772329 y = 0.017331 + -0.000034*x 134 10.960663313432837 3.9096921347220377 0.016960171641791044 0.005752288800181051
3 logarithmic Chlorophyll 533.815002 9.639796014881963e-05 y = 0.017325 + -0.000156*ln(x) 134 10.960663313432837 3.9096921347220377 0.016960171641791044 0.005752288800181051
4 power Chlorophyll 533.815002 -0.010942625292486463 y = 0.020200 * x^-0.085250 134 10.960663313432837 3.9096921347220377 0.016960171641791044 0.005752288800181051
5 exponential Chlorophyll 533.815002 -0.011375297319334177 y = 0.018394 * exp(-0.009577*x) 134 10.960663313432837 3.9096921347220377 0.016960171641791044 0.005752288800181051

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,537.973999,0.010059827315010317,y = 0.018287 + -0.000095*x,134,10.960663313432837,3.9096921347220377,0.017245291044776116,0.003706413209287316
logarithmic,Chlorophyll,537.973999,0.0058263736903666485,y = 0.019072 + -0.000784*ln(x),134,10.960663313432837,3.9096921347220377,0.017245291044776116,0.003706413209287316
exponential,Chlorophyll,537.973999,-0.0006317634379562342,y = 0.018947 * exp(-0.009908*x),134,10.960663313432837,3.9096921347220377,0.017245291044776116,0.003706413209287316
power,Chlorophyll,537.973999,-0.004088770616538007,y = 0.020915 * x^-0.089031,134,10.960663313432837,3.9096921347220377,0.017245291044776116,0.003706413209287316
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 537.973999 0.010059827315010317 y = 0.018287 + -0.000095*x 134 10.960663313432837 3.9096921347220377 0.017245291044776116 0.003706413209287316
3 logarithmic Chlorophyll 537.973999 0.0058263736903666485 y = 0.019072 + -0.000784*ln(x) 134 10.960663313432837 3.9096921347220377 0.017245291044776116 0.003706413209287316
4 exponential Chlorophyll 537.973999 -0.0006317634379562342 y = 0.018947 * exp(-0.009908*x) 134 10.960663313432837 3.9096921347220377 0.017245291044776116 0.003706413209287316
5 power Chlorophyll 537.973999 -0.004088770616538007 y = 0.020915 * x^-0.089031 134 10.960663313432837 3.9096921347220377 0.017245291044776116 0.003706413209287316

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,542.13501,0.10592938275035968,y = 0.019264 + -0.000164*x,134,10.960663313432837,3.9096921347220377,0.017471380597014925,0.0019645221126944118
exponential,Chlorophyll,542.13501,0.09468361275300774,y = 0.019618 * exp(-0.011250*x),134,10.960663313432837,3.9096921347220377,0.017471380597014925,0.0019645221126944118
logarithmic,Chlorophyll,542.13501,0.07410535895090076,y = 0.020924 + -0.001482*ln(x),134,10.960663313432837,3.9096921347220377,0.017471380597014925,0.0019645221126944118
power,Chlorophyll,542.13501,0.06336507350101761,y = 0.022043 * x^-0.102942,134,10.960663313432837,3.9096921347220377,0.017471380597014925,0.0019645221126944118
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 542.13501 0.10592938275035968 y = 0.019264 + -0.000164*x 134 10.960663313432837 3.9096921347220377 0.017471380597014925 0.0019645221126944118
3 exponential Chlorophyll 542.13501 0.09468361275300774 y = 0.019618 * exp(-0.011250*x) 134 10.960663313432837 3.9096921347220377 0.017471380597014925 0.0019645221126944118
4 logarithmic Chlorophyll 542.13501 0.07410535895090076 y = 0.020924 + -0.001482*ln(x) 134 10.960663313432837 3.9096921347220377 0.017471380597014925 0.0019645221126944118
5 power Chlorophyll 542.13501 0.06336507350101761 y = 0.022043 * x^-0.102942 134 10.960663313432837 3.9096921347220377 0.017471380597014925 0.0019645221126944118

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,546.301025,0.12040522641720053,y = 0.019716 + -0.000169*x,134,10.960663313432837,3.9096921347220377,0.01786192537313433,0.0019057641301598596
exponential,Chlorophyll,546.301025,0.11002711959899414,y = 0.020039 * exp(-0.011103*x),134,10.960663313432837,3.9096921347220377,0.01786192537313433,0.0019057641301598596
logarithmic,Chlorophyll,546.301025,0.08587624549622919,y = 0.021467 + -0.001547*ln(x),134,10.960663313432837,3.9096921347220377,0.01786192537313433,0.0019057641301598596
power,Chlorophyll,546.301025,0.07589213783045401,y = 0.022516 * x^-0.102241,134,10.960663313432837,3.9096921347220377,0.01786192537313433,0.0019057641301598596
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 546.301025 0.12040522641720053 y = 0.019716 + -0.000169*x 134 10.960663313432837 3.9096921347220377 0.01786192537313433 0.0019057641301598596
3 exponential Chlorophyll 546.301025 0.11002711959899414 y = 0.020039 * exp(-0.011103*x) 134 10.960663313432837 3.9096921347220377 0.01786192537313433 0.0019057641301598596
4 logarithmic Chlorophyll 546.301025 0.08587624549622919 y = 0.021467 + -0.001547*ln(x) 134 10.960663313432837 3.9096921347220377 0.01786192537313433 0.0019057641301598596
5 power Chlorophyll 546.301025 0.07589213783045401 y = 0.022516 * x^-0.102241 134 10.960663313432837 3.9096921347220377 0.01786192537313433 0.0019057641301598596

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,550.468994,0.1269569921216488,y = 0.020121 + -0.000172*x,134,10.960663313432837,3.9096921347220377,0.01824102985074627,0.0018825013010254905
exponential,Chlorophyll,550.468994,0.1175391734287099,y = 0.020411 * exp(-0.010816*x),134,10.960663313432837,3.9096921347220377,0.01824102985074627,0.0018825013010254905
logarithmic,Chlorophyll,550.468994,0.0907980339917791,y = 0.021903 + -0.001572*ln(x),134,10.960663313432837,3.9096921347220377,0.01824102985074627,0.0018825013010254905
power,Chlorophyll,550.468994,0.08162875081638976,y = 0.022867 * x^-0.099639,134,10.960663313432837,3.9096921347220377,0.01824102985074627,0.0018825013010254905
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 550.468994 0.1269569921216488 y = 0.020121 + -0.000172*x 134 10.960663313432837 3.9096921347220377 0.01824102985074627 0.0018825013010254905
3 exponential Chlorophyll 550.468994 0.1175391734287099 y = 0.020411 * exp(-0.010816*x) 134 10.960663313432837 3.9096921347220377 0.01824102985074627 0.0018825013010254905
4 logarithmic Chlorophyll 550.468994 0.0907980339917791 y = 0.021903 + -0.001572*ln(x) 134 10.960663313432837 3.9096921347220377 0.01824102985074627 0.0018825013010254905
5 power Chlorophyll 550.468994 0.08162875081638976 y = 0.022867 * x^-0.099639 134 10.960663313432837 3.9096921347220377 0.01824102985074627 0.0018825013010254905

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,554.640991,0.1376426262180579,y = 0.020508 + -0.000178*x,134,10.960663313432837,3.9096921347220377,0.018552656716417912,0.0018796053138591957
exponential,Chlorophyll,554.640991,0.12753098839026022,y = 0.020816 * exp(-0.011054*x),134,10.960663313432837,3.9096921347220377,0.018552656716417912,0.0018796053138591957
logarithmic,Chlorophyll,554.640991,0.09810495477002423,y = 0.022354 + -0.001631*ln(x),134,10.960663313432837,3.9096921347220377,0.018552656716417912,0.0018796053138591957
power,Chlorophyll,554.640991,0.08828430738543391,y = 0.023368 * x^-0.101637,134,10.960663313432837,3.9096921347220377,0.018552656716417912,0.0018796053138591957
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 554.640991 0.1376426262180579 y = 0.020508 + -0.000178*x 134 10.960663313432837 3.9096921347220377 0.018552656716417912 0.0018796053138591957
3 exponential Chlorophyll 554.640991 0.12753098839026022 y = 0.020816 * exp(-0.011054*x) 134 10.960663313432837 3.9096921347220377 0.018552656716417912 0.0018796053138591957
4 logarithmic Chlorophyll 554.640991 0.09810495477002423 y = 0.022354 + -0.001631*ln(x) 134 10.960663313432837 3.9096921347220377 0.018552656716417912 0.0018796053138591957
5 power Chlorophyll 554.640991 0.08828430738543391 y = 0.023368 * x^-0.101637 134 10.960663313432837 3.9096921347220377 0.018552656716417912 0.0018796053138591957

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,558.815979,0.14438886343879165,y = 0.020984 + -0.000192*x,134,10.960663313432837,3.9096921347220377,0.018875544776119402,0.0019794547666891088
exponential,Chlorophyll,558.815979,0.13400466793505816,y = 0.021319 * exp(-0.011710*x),134,10.960663313432837,3.9096921347220377,0.018875544776119402,0.0019794547666891088
logarithmic,Chlorophyll,558.815979,0.10606464763119816,y = 0.023038 + -0.001786*ln(x),134,10.960663313432837,3.9096921347220377,0.018875544776119402,0.0019794547666891088
power,Chlorophyll,558.815979,0.09560595602330613,y = 0.024181 * x^-0.109152,134,10.960663313432837,3.9096921347220377,0.018875544776119402,0.0019794547666891088
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 558.815979 0.14438886343879165 y = 0.020984 + -0.000192*x 134 10.960663313432837 3.9096921347220377 0.018875544776119402 0.0019794547666891088
3 exponential Chlorophyll 558.815979 0.13400466793505816 y = 0.021319 * exp(-0.011710*x) 134 10.960663313432837 3.9096921347220377 0.018875544776119402 0.0019794547666891088
4 logarithmic Chlorophyll 558.815979 0.10606464763119816 y = 0.023038 + -0.001786*ln(x) 134 10.960663313432837 3.9096921347220377 0.018875544776119402 0.0019794547666891088
5 power Chlorophyll 558.815979 0.09560595602330613 y = 0.024181 * x^-0.109152 134 10.960663313432837 3.9096921347220377 0.018875544776119402 0.0019794547666891088

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,562.994995,0.13570684972920022,y = 0.021065 + -0.000193*x,134,10.960663313432837,3.9096921347220377,0.018946902985074628,0.002050816811679121
exponential,Chlorophyll,562.994995,0.1251679621881412,y = 0.021424 * exp(-0.011845*x),134,10.960663313432837,3.9096921347220377,0.018946902985074628,0.002050816811679121
logarithmic,Chlorophyll,562.994995,0.10005264191024388,y = 0.023135 + -0.001797*ln(x),134,10.960663313432837,3.9096921347220377,0.018946902985074628,0.002050816811679121
power,Chlorophyll,562.994995,0.08944628510214314,y = 0.024352 * x^-0.110685,134,10.960663313432837,3.9096921347220377,0.018946902985074628,0.002050816811679121
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 562.994995 0.13570684972920022 y = 0.021065 + -0.000193*x 134 10.960663313432837 3.9096921347220377 0.018946902985074628 0.002050816811679121
3 exponential Chlorophyll 562.994995 0.1251679621881412 y = 0.021424 * exp(-0.011845*x) 134 10.960663313432837 3.9096921347220377 0.018946902985074628 0.002050816811679121
4 logarithmic Chlorophyll 562.994995 0.10005264191024388 y = 0.023135 + -0.001797*ln(x) 134 10.960663313432837 3.9096921347220377 0.018946902985074628 0.002050816811679121
5 power Chlorophyll 562.994995 0.08944628510214314 y = 0.024352 * x^-0.110685 134 10.960663313432837 3.9096921347220377 0.018946902985074628 0.002050816811679121

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,567.177002,0.03705163102869502,y = 0.020812 + -0.000155*x,134,10.960663313432837,3.9096921347220377,0.01911655970149254,0.0031426043067057114
exponential,Chlorophyll,567.177002,0.02735476743599441,y = 0.021355 * exp(-0.011096*x),134,10.960663313432837,3.9096921347220377,0.01911655970149254,0.0031426043067057114
logarithmic,Chlorophyll,567.177002,0.02624551679688847,y = 0.022403 + -0.001411*ln(x),134,10.960663313432837,3.9096921347220377,0.01911655970149254,0.0031426043067057114
power,Chlorophyll,567.177002,0.01690050625981776,y = 0.024064 * x^-0.103446,134,10.960663313432837,3.9096921347220377,0.01911655970149254,0.0031426043067057114
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 567.177002 0.03705163102869502 y = 0.020812 + -0.000155*x 134 10.960663313432837 3.9096921347220377 0.01911655970149254 0.0031426043067057114
3 exponential Chlorophyll 567.177002 0.02735476743599441 y = 0.021355 * exp(-0.011096*x) 134 10.960663313432837 3.9096921347220377 0.01911655970149254 0.0031426043067057114
4 logarithmic Chlorophyll 567.177002 0.02624551679688847 y = 0.022403 + -0.001411*ln(x) 134 10.960663313432837 3.9096921347220377 0.01911655970149254 0.0031426043067057114
5 power Chlorophyll 567.177002 0.01690050625981776 y = 0.024064 * x^-0.103446 134 10.960663313432837 3.9096921347220377 0.01911655970149254 0.0031426043067057114

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,571.362976,0.032367014815650186,y = 0.020732 + -0.000161*x,134,10.960663313432837,3.9096921347220377,0.018965664179104478,0.0035018296559745925
logarithmic,Chlorophyll,571.362976,0.023243518566287924,y = 0.022412 + -0.001479*ln(x),134,10.960663313432837,3.9096921347220377,0.018965664179104478,0.0035018296559745925
exponential,Chlorophyll,571.362976,0.021156108573575194,y = 0.021404 * exp(-0.012237*x),134,10.960663313432837,3.9096921347220377,0.018965664179104478,0.0035018296559745925
power,Chlorophyll,571.362976,0.012371457852355827,y = 0.024473 * x^-0.115076,134,10.960663313432837,3.9096921347220377,0.018965664179104478,0.0035018296559745925
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 571.362976 0.032367014815650186 y = 0.020732 + -0.000161*x 134 10.960663313432837 3.9096921347220377 0.018965664179104478 0.0035018296559745925
3 logarithmic Chlorophyll 571.362976 0.023243518566287924 y = 0.022412 + -0.001479*ln(x) 134 10.960663313432837 3.9096921347220377 0.018965664179104478 0.0035018296559745925
4 exponential Chlorophyll 571.362976 0.021156108573575194 y = 0.021404 * exp(-0.012237*x) 134 10.960663313432837 3.9096921347220377 0.018965664179104478 0.0035018296559745925
5 power Chlorophyll 571.362976 0.012371457852355827 y = 0.024473 * x^-0.115076 134 10.960663313432837 3.9096921347220377 0.018965664179104478 0.0035018296559745925

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,575.551025,0.003711200606445142,y = 0.019973 + -0.000095*x,134,10.960663313432837,3.9096921347220377,0.018931119402985072,0.006097893443512235
logarithmic,Chlorophyll,575.551025,0.0022851664540198824,y = 0.020813 + -0.000808*ln(x),134,10.960663313432837,3.9096921347220377,0.018931119402985072,0.006097893443512235
exponential,Chlorophyll,575.551025,-0.008535989595423121,y = 0.021158 * exp(-0.012309*x),134,10.960663313432837,3.9096921347220377,0.018931119402985072,0.006097893443512235
power,Chlorophyll,575.551025,-0.009305973499541542,y = 0.024221 * x^-0.115919,134,10.960663313432837,3.9096921347220377,0.018931119402985072,0.006097893443512235
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 575.551025 0.003711200606445142 y = 0.019973 + -0.000095*x 134 10.960663313432837 3.9096921347220377 0.018931119402985072 0.006097893443512235
3 logarithmic Chlorophyll 575.551025 0.0022851664540198824 y = 0.020813 + -0.000808*ln(x) 134 10.960663313432837 3.9096921347220377 0.018931119402985072 0.006097893443512235
4 exponential Chlorophyll 575.551025 -0.008535989595423121 y = 0.021158 * exp(-0.012309*x) 134 10.960663313432837 3.9096921347220377 0.018931119402985072 0.006097893443512235
5 power Chlorophyll 575.551025 -0.009305973499541542 y = 0.024221 * x^-0.115919 134 10.960663313432837 3.9096921347220377 0.018931119402985072 0.006097893443512235

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,579.744019,0.005094509026133509,y = 0.019711 + -0.000110*x,134,10.960663313432837,3.9096921347220377,0.018505432835820897,0.006025405615191274
logarithmic,Chlorophyll,579.744019,0.0034065768371064342,y = 0.020776 + -0.000974*ln(x),134,10.960663313432837,3.9096921347220377,0.018505432835820897,0.006025405615191274
exponential,Chlorophyll,579.744019,-0.007270136129956084,y = 0.020909 * exp(-0.013357*x),134,10.960663313432837,3.9096921347220377,0.018505432835820897,0.006025405615191274
power,Chlorophyll,579.744019,-0.008400608136997167,y = 0.024296 * x^-0.127275,134,10.960663313432837,3.9096921347220377,0.018505432835820897,0.006025405615191274
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 579.744019 0.005094509026133509 y = 0.019711 + -0.000110*x 134 10.960663313432837 3.9096921347220377 0.018505432835820897 0.006025405615191274
3 logarithmic Chlorophyll 579.744019 0.0034065768371064342 y = 0.020776 + -0.000974*ln(x) 134 10.960663313432837 3.9096921347220377 0.018505432835820897 0.006025405615191274
4 exponential Chlorophyll 579.744019 -0.007270136129956084 y = 0.020909 * exp(-0.013357*x) 134 10.960663313432837 3.9096921347220377 0.018505432835820897 0.006025405615191274
5 power Chlorophyll 579.744019 -0.008400608136997167 y = 0.024296 * x^-0.127275 134 10.960663313432837 3.9096921347220377 0.018505432835820897 0.006025405615191274

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,583.939026,0.004657425272328819,y = 0.019070 + -0.000108*x,134,10.960663313432837,3.9096921347220377,0.017881,0.006215784305887186
logarithmic,Chlorophyll,583.939026,0.003161690862374833,y = 0.020137 + -0.000968*ln(x),134,10.960663313432837,3.9096921347220377,0.017881,0.006215784305887186
exponential,Chlorophyll,583.939026,-0.00834323144293947,y = 0.020355 * exp(-0.014251*x),134,10.960663313432837,3.9096921347220377,0.017881,0.006215784305887186
power,Chlorophyll,583.939026,-0.009289166222129941,y = 0.023939 * x^-0.136644,134,10.960663313432837,3.9096921347220377,0.017881,0.006215784305887186
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 583.939026 0.004657425272328819 y = 0.019070 + -0.000108*x 134 10.960663313432837 3.9096921347220377 0.017881 0.006215784305887186
3 logarithmic Chlorophyll 583.939026 0.003161690862374833 y = 0.020137 + -0.000968*ln(x) 134 10.960663313432837 3.9096921347220377 0.017881 0.006215784305887186
4 exponential Chlorophyll 583.939026 -0.00834323144293947 y = 0.020355 * exp(-0.014251*x) 134 10.960663313432837 3.9096921347220377 0.017881 0.006215784305887186
5 power Chlorophyll 583.939026 -0.009289166222129941 y = 0.023939 * x^-0.136644 134 10.960663313432837 3.9096921347220377 0.017881 0.006215784305887186

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,588.138,0.007038900978221574,y = 0.018745 + -0.000132*x,134,10.960663313432837,3.9096921347220377,0.017294746268656718,0.006164975937402735
logarithmic,Chlorophyll,588.138,0.005079658860641656,y = 0.020131 + -0.001218*ln(x),134,10.960663313432837,3.9096921347220377,0.017294746268656718,0.006164975937402735
exponential,Chlorophyll,588.138,-0.008087990598099282,y = 0.020176 * exp(-0.016777*x),134,10.960663313432837,3.9096921347220377,0.017294746268656718,0.006164975937402735
power,Chlorophyll,588.138,-0.009554552395312665,y = 0.024503 * x^-0.162327,134,10.960663313432837,3.9096921347220377,0.017294746268656718,0.006164975937402735
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 588.138 0.007038900978221574 y = 0.018745 + -0.000132*x 134 10.960663313432837 3.9096921347220377 0.017294746268656718 0.006164975937402735
3 logarithmic Chlorophyll 588.138 0.005079658860641656 y = 0.020131 + -0.001218*ln(x) 134 10.960663313432837 3.9096921347220377 0.017294746268656718 0.006164975937402735
4 exponential Chlorophyll 588.138 -0.008087990598099282 y = 0.020176 * exp(-0.016777*x) 134 10.960663313432837 3.9096921347220377 0.017294746268656718 0.006164975937402735
5 power Chlorophyll 588.138 -0.009554552395312665 y = 0.024503 * x^-0.162327 134 10.960663313432837 3.9096921347220377 0.017294746268656718 0.006164975937402735

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,592.341003,0.005528079261697849,y = 0.017838 + -0.000118*x,134,10.960663313432837,3.9096921347220377,0.016543097014925373,0.006212725389009627
logarithmic,Chlorophyll,592.341003,0.003887007195125136,y = 0.019044 + -0.001073*ln(x),134,10.960663313432837,3.9096921347220377,0.016543097014925373,0.006212725389009627
exponential,Chlorophyll,592.341003,-0.011813537096786675,y = 0.019386 * exp(-0.017528*x),134,10.960663313432837,3.9096921347220377,0.016543097014925373,0.006212725389009627
power,Chlorophyll,592.341003,-0.012846809152319283,y = 0.023741 * x^-0.169433,134,10.960663313432837,3.9096921347220377,0.016543097014925373,0.006212725389009627
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 592.341003 0.005528079261697849 y = 0.017838 + -0.000118*x 134 10.960663313432837 3.9096921347220377 0.016543097014925373 0.006212725389009627
3 logarithmic Chlorophyll 592.341003 0.003887007195125136 y = 0.019044 + -0.001073*ln(x) 134 10.960663313432837 3.9096921347220377 0.016543097014925373 0.006212725389009627
4 exponential Chlorophyll 592.341003 -0.011813537096786675 y = 0.019386 * exp(-0.017528*x) 134 10.960663313432837 3.9096921347220377 0.016543097014925373 0.006212725389009627
5 power Chlorophyll 592.341003 -0.012846809152319283 y = 0.023741 * x^-0.169433 134 10.960663313432837 3.9096921347220377 0.016543097014925373 0.006212725389009627

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,596.546997,0.003794780064093062,y = 0.016713 + -0.000101*x,134,10.960663313432837,3.9096921347220377,0.015607044776119405,0.00640171329313859
logarithmic,Chlorophyll,596.546997,0.0025823661966439815,y = 0.017707 + -0.000901*ln(x),134,10.960663313432837,3.9096921347220377,0.015607044776119405,0.00640171329313859
exponential,Chlorophyll,596.546997,-0.014874157713247849,y = 0.018368 * exp(-0.018321*x),134,10.960663313432837,3.9096921347220377,0.015607044776119405,0.00640171329313859
power,Chlorophyll,596.546997,-0.015374647488444415,y = 0.022702 * x^-0.177115,134,10.960663313432837,3.9096921347220377,0.015607044776119405,0.00640171329313859
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 596.546997 0.003794780064093062 y = 0.016713 + -0.000101*x 134 10.960663313432837 3.9096921347220377 0.015607044776119405 0.00640171329313859
3 logarithmic Chlorophyll 596.546997 0.0025823661966439815 y = 0.017707 + -0.000901*ln(x) 134 10.960663313432837 3.9096921347220377 0.015607044776119405 0.00640171329313859
4 exponential Chlorophyll 596.546997 -0.014874157713247849 y = 0.018368 * exp(-0.018321*x) 134 10.960663313432837 3.9096921347220377 0.015607044776119405 0.00640171329313859
5 power Chlorophyll 596.546997 -0.015374647488444415 y = 0.022702 * x^-0.177115 134 10.960663313432837 3.9096921347220377 0.015607044776119405 0.00640171329313859

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,600.755981,0.0031611200601100453,y = 0.015616 + -0.000092*x,134,10.960663313432837,3.9096921347220377,0.014608059701492537,0.006395783738002828
logarithmic,Chlorophyll,600.755981,0.002151138099984129,y = 0.016523 + -0.000822*ln(x),134,10.960663313432837,3.9096921347220377,0.014608059701492537,0.006395783738002828
exponential,Chlorophyll,600.755981,-0.015732414466808953,y = 0.017258 * exp(-0.018983*x),134,10.960663313432837,3.9096921347220377,0.014608059701492537,0.006395783738002828
power,Chlorophyll,600.755981,-0.016109249860633446,y = 0.021535 * x^-0.184339,134,10.960663313432837,3.9096921347220377,0.014608059701492537,0.006395783738002828
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 600.755981 0.0031611200601100453 y = 0.015616 + -0.000092*x 134 10.960663313432837 3.9096921347220377 0.014608059701492537 0.006395783738002828
3 logarithmic Chlorophyll 600.755981 0.002151138099984129 y = 0.016523 + -0.000822*ln(x) 134 10.960663313432837 3.9096921347220377 0.014608059701492537 0.006395783738002828
4 exponential Chlorophyll 600.755981 -0.015732414466808953 y = 0.017258 * exp(-0.018983*x) 134 10.960663313432837 3.9096921347220377 0.014608059701492537 0.006395783738002828
5 power Chlorophyll 600.755981 -0.016109249860633446 y = 0.021535 * x^-0.184339 134 10.960663313432837 3.9096921347220377 0.014608059701492537 0.006395783738002828

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,604.968994,0.002398045183009123,y = 0.014883 + -0.000082*x,134,10.960663313432837,3.9096921347220377,0.013985902985074627,0.0065333725432655055
logarithmic,Chlorophyll,604.968994,0.001603534119833716,y = 0.015675 + -0.000725*ln(x),134,10.960663313432837,3.9096921347220377,0.013985902985074627,0.0065333725432655055
power,Chlorophyll,604.968994,-0.019789876685375907,y = 0.021361 * x^-0.202172,134,10.960663313432837,3.9096921347220377,0.013985902985074627,0.0065333725432655055
exponential,Chlorophyll,604.968994,-0.019848091450597183,y = 0.016749 * exp(-0.020787*x),134,10.960663313432837,3.9096921347220377,0.013985902985074627,0.0065333725432655055
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 604.968994 0.002398045183009123 y = 0.014883 + -0.000082*x 134 10.960663313432837 3.9096921347220377 0.013985902985074627 0.0065333725432655055
3 logarithmic Chlorophyll 604.968994 0.001603534119833716 y = 0.015675 + -0.000725*ln(x) 134 10.960663313432837 3.9096921347220377 0.013985902985074627 0.0065333725432655055
4 power Chlorophyll 604.968994 -0.019789876685375907 y = 0.021361 * x^-0.202172 134 10.960663313432837 3.9096921347220377 0.013985902985074627 0.0065333725432655055
5 exponential Chlorophyll 604.968994 -0.019848091450597183 y = 0.016749 * exp(-0.020787*x) 134 10.960663313432837 3.9096921347220377 0.013985902985074627 0.0065333725432655055

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,609.184998,0.0026364151647212397,y = 0.014491 + -0.000087*x,134,10.960663313432837,3.9096921347220377,0.013541022388059702,0.006602440257226493
logarithmic,Chlorophyll,609.184998,0.001802623235843237,y = 0.015351 + -0.000777*ln(x),134,10.960663313432837,3.9096921347220377,0.013541022388059702,0.006602440257226493
exponential,Chlorophyll,609.184998,-0.02173372426195974,y = 0.016508 * exp(-0.022851*x),134,10.960663313432837,3.9096921347220377,0.013541022388059702,0.006602440257226493
power,Chlorophyll,609.184998,-0.021740201254617064,y = 0.021605 * x^-0.222988,134,10.960663313432837,3.9096921347220377,0.013541022388059702,0.006602440257226493
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 609.184998 0.0026364151647212397 y = 0.014491 + -0.000087*x 134 10.960663313432837 3.9096921347220377 0.013541022388059702 0.006602440257226493
3 logarithmic Chlorophyll 609.184998 0.001802623235843237 y = 0.015351 + -0.000777*ln(x) 134 10.960663313432837 3.9096921347220377 0.013541022388059702 0.006602440257226493
4 exponential Chlorophyll 609.184998 -0.02173372426195974 y = 0.016508 * exp(-0.022851*x) 134 10.960663313432837 3.9096921347220377 0.013541022388059702 0.006602440257226493
5 power Chlorophyll 609.184998 -0.021740201254617064 y = 0.021605 * x^-0.222988 134 10.960663313432837 3.9096921347220377 0.013541022388059702 0.006602440257226493

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,613.403992,0.002856835284101855,y = 0.014122 + -0.000091*x,134,10.960663313432837,3.9096921347220377,0.013127970149253732,0.006635524455917487
logarithmic,Chlorophyll,613.403992,0.0019870205661061124,y = 0.015038 + -0.000820*ln(x),134,10.960663313432837,3.9096921347220377,0.013127970149253732,0.006635524455917487
power,Chlorophyll,613.403992,-0.028809677197195516,y = 0.022780 * x^-0.263141,134,10.960663313432837,3.9096921347220377,0.013127970149253732,0.006635524455917487
exponential,Chlorophyll,613.403992,-0.02909727099411552,y = 0.016581 * exp(-0.026956*x),134,10.960663313432837,3.9096921347220377,0.013127970149253732,0.006635524455917487
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 613.403992 0.002856835284101855 y = 0.014122 + -0.000091*x 134 10.960663313432837 3.9096921347220377 0.013127970149253732 0.006635524455917487
3 logarithmic Chlorophyll 613.403992 0.0019870205661061124 y = 0.015038 + -0.000820*ln(x) 134 10.960663313432837 3.9096921347220377 0.013127970149253732 0.006635524455917487
4 power Chlorophyll 613.403992 -0.028809677197195516 y = 0.022780 * x^-0.263141 134 10.960663313432837 3.9096921347220377 0.013127970149253732 0.006635524455917487
5 exponential Chlorophyll 613.403992 -0.02909727099411552 y = 0.016581 * exp(-0.026956*x) 134 10.960663313432837 3.9096921347220377 0.013127970149253732 0.006635524455917487

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,617.627014,0.0029411042399954956,y = 0.013748 + -0.000092*x,134,10.960663313432837,3.9096921347220377,0.012741731343283583,0.006619138380331145
logarithmic,Chlorophyll,617.627014,0.0020597681456059336,y = 0.014681 + -0.000832*ln(x),134,10.960663313432837,3.9096921347220377,0.012741731343283583,0.006619138380331145
power,Chlorophyll,617.627014,-0.02980562740210102,y = 0.022702 * x^-0.275804,134,10.960663313432837,3.9096921347220377,0.012741731343283583,0.006619138380331145
exponential,Chlorophyll,617.627014,-0.030009751236651283,y = 0.016267 * exp(-0.028218*x),134,10.960663313432837,3.9096921347220377,0.012741731343283583,0.006619138380331145
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 617.627014 0.0029411042399954956 y = 0.013748 + -0.000092*x 134 10.960663313432837 3.9096921347220377 0.012741731343283583 0.006619138380331145
3 logarithmic Chlorophyll 617.627014 0.0020597681456059336 y = 0.014681 + -0.000832*ln(x) 134 10.960663313432837 3.9096921347220377 0.012741731343283583 0.006619138380331145
4 power Chlorophyll 617.627014 -0.02980562740210102 y = 0.022702 * x^-0.275804 134 10.960663313432837 3.9096921347220377 0.012741731343283583 0.006619138380331145
5 exponential Chlorophyll 617.627014 -0.030009751236651283 y = 0.016267 * exp(-0.028218*x) 134 10.960663313432837 3.9096921347220377 0.012741731343283583 0.006619138380331145

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,621.853027,0.002549517816160085,y = 0.013405 + -0.000087*x,134,10.960663313432837,3.9096921347220377,0.012447716417910447,0.006761993519104926
logarithmic,Chlorophyll,621.853027,0.0017633821329291477,y = 0.014281 + -0.000787*ln(x),134,10.960663313432837,3.9096921347220377,0.012447716417910447,0.006761993519104926
power,Chlorophyll,621.853027,-0.03557395594809787,y = 0.023522 * x^-0.304801,134,10.960663313432837,3.9096921347220377,0.012447716417910447,0.006761993519104926
exponential,Chlorophyll,621.853027,-0.0360883361973503,y = 0.016274 * exp(-0.031185*x),134,10.960663313432837,3.9096921347220377,0.012447716417910447,0.006761993519104926
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 621.853027 0.002549517816160085 y = 0.013405 + -0.000087*x 134 10.960663313432837 3.9096921347220377 0.012447716417910447 0.006761993519104926
3 logarithmic Chlorophyll 621.853027 0.0017633821329291477 y = 0.014281 + -0.000787*ln(x) 134 10.960663313432837 3.9096921347220377 0.012447716417910447 0.006761993519104926
4 power Chlorophyll 621.853027 -0.03557395594809787 y = 0.023522 * x^-0.304801 134 10.960663313432837 3.9096921347220377 0.012447716417910447 0.006761993519104926
5 exponential Chlorophyll 621.853027 -0.0360883361973503 y = 0.016274 * exp(-0.031185*x) 134 10.960663313432837 3.9096921347220377 0.012447716417910447 0.006761993519104926

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,626.083008,0.00243086769672618,y = 0.013228 + -0.000086*x,134,10.960663313432837,3.9096921347220377,0.01228736567164179,0.006808151575409212
logarithmic,Chlorophyll,626.083008,0.0016770114876123454,y = 0.014087 + -0.000773*ln(x),134,10.960663313432837,3.9096921347220377,0.01228736567164179,0.006808151575409212
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 626.083008 0.00243086769672618 y = 0.013228 + -0.000086*x 134 10.960663313432837 3.9096921347220377 0.01228736567164179 0.006808151575409212
3 logarithmic Chlorophyll 626.083008 0.0016770114876123454 y = 0.014087 + -0.000773*ln(x) 134 10.960663313432837 3.9096921347220377 0.01228736567164179 0.006808151575409212

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,630.315979,0.0020507276873319435,y = 0.013084 + -0.000080*x,134,10.960663313432837,3.9096921347220377,0.012202574626865673,0.0069447202176291635
logarithmic,Chlorophyll,630.315979,0.0014098383321846653,y = 0.013886 + -0.000723*ln(x),134,10.960663313432837,3.9096921347220377,0.012202574626865673,0.0069447202176291635
power,Chlorophyll,630.315979,-0.037502977238619506,y = 0.023711 * x^-0.319128,134,10.960663313432837,3.9096921347220377,0.012202574626865673,0.0069447202176291635
exponential,Chlorophyll,630.315979,-0.03824118768398388,y = 0.016114 * exp(-0.032602*x),134,10.960663313432837,3.9096921347220377,0.012202574626865673,0.0069447202176291635
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 630.315979 0.0020507276873319435 y = 0.013084 + -0.000080*x 134 10.960663313432837 3.9096921347220377 0.012202574626865673 0.0069447202176291635
3 logarithmic Chlorophyll 630.315979 0.0014098383321846653 y = 0.013886 + -0.000723*ln(x) 134 10.960663313432837 3.9096921347220377 0.012202574626865673 0.0069447202176291635
4 power Chlorophyll 630.315979 -0.037502977238619506 y = 0.023711 * x^-0.319128 134 10.960663313432837 3.9096921347220377 0.012202574626865673 0.0069447202176291635
5 exponential Chlorophyll 630.315979 -0.03824118768398388 y = 0.016114 * exp(-0.032602*x) 134 10.960663313432837 3.9096921347220377 0.012202574626865673 0.0069447202176291635

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,634.552002,0.0017288451024077833,y = 0.012968 + -0.000074*x,134,10.960663313432837,3.9096921347220377,0.012159492537313433,0.006937426491471543
logarithmic,Chlorophyll,634.552002,0.0011589143811774338,y = 0.013684 + -0.000654*ln(x),134,10.960663313432837,3.9096921347220377,0.012159492537313433,0.006937426491471543
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 634.552002 0.0017288451024077833 y = 0.012968 + -0.000074*x 134 10.960663313432837 3.9096921347220377 0.012159492537313433 0.006937426491471543
3 logarithmic Chlorophyll 634.552002 0.0011589143811774338 y = 0.013684 + -0.000654*ln(x) 134 10.960663313432837 3.9096921347220377 0.012159492537313433 0.006937426491471543

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,638.791992,0.0011243091081014622,y = 0.012803 + -0.000061*x,134,10.960663313432837,3.9096921347220377,0.012136574626865673,0.007088601297076063
logarithmic,Chlorophyll,638.791992,0.0007004467304244644,y = 0.013348 + -0.000520*ln(x),134,10.960663313432837,3.9096921347220377,0.012136574626865673,0.007088601297076063
power,Chlorophyll,638.791992,-0.039341503691473934,y = 0.023270 * x^-0.314552,134,10.960663313432837,3.9096921347220377,0.012136574626865673,0.007088601297076063
exponential,Chlorophyll,638.791992,-0.040722297966500065,y = 0.015930 * exp(-0.032288*x),134,10.960663313432837,3.9096921347220377,0.012136574626865673,0.007088601297076063
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 638.791992 0.0011243091081014622 y = 0.012803 + -0.000061*x 134 10.960663313432837 3.9096921347220377 0.012136574626865673 0.007088601297076063
3 logarithmic Chlorophyll 638.791992 0.0007004467304244644 y = 0.013348 + -0.000520*ln(x) 134 10.960663313432837 3.9096921347220377 0.012136574626865673 0.007088601297076063
4 power Chlorophyll 638.791992 -0.039341503691473934 y = 0.023270 * x^-0.314552 134 10.960663313432837 3.9096921347220377 0.012136574626865673 0.007088601297076063
5 exponential Chlorophyll 638.791992 -0.040722297966500065 y = 0.015930 * exp(-0.032288*x) 134 10.960663313432837 3.9096921347220377 0.012136574626865673 0.007088601297076063

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,643.034973,0.0006784732036110297,y = 0.012527 + -0.000048*x,134,10.960663313432837,3.9096921347220377,0.012004380597014924,0.007158811687218512
logarithmic,Chlorophyll,643.034973,0.0003810729347989428,y = 0.012907 + -0.000387*ln(x),134,10.960663313432837,3.9096921347220377,0.012004380597014924,0.007158811687218512
power,Chlorophyll,643.034973,-0.02081846389883313,y = 0.018994 * x^-0.223479,134,10.960663313432837,3.9096921347220377,0.012004380597014924,0.007158811687218512
exponential,Chlorophyll,643.034973,-0.02135362421636633,y = 0.014510 * exp(-0.022936*x),134,10.960663313432837,3.9096921347220377,0.012004380597014924,0.007158811687218512
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 643.034973 0.0006784732036110297 y = 0.012527 + -0.000048*x 134 10.960663313432837 3.9096921347220377 0.012004380597014924 0.007158811687218512
3 logarithmic Chlorophyll 643.034973 0.0003810729347989428 y = 0.012907 + -0.000387*ln(x) 134 10.960663313432837 3.9096921347220377 0.012004380597014924 0.007158811687218512
4 power Chlorophyll 643.034973 -0.02081846389883313 y = 0.018994 * x^-0.223479 134 10.960663313432837 3.9096921347220377 0.012004380597014924 0.007158811687218512
5 exponential Chlorophyll 643.034973 -0.02135362421636633 y = 0.014510 * exp(-0.022936*x) 134 10.960663313432837 3.9096921347220377 0.012004380597014924 0.007158811687218512

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,647.281006,0.0003862335627651259,y = 0.012126 + -0.000037*x,134,10.960663313432837,3.9096921347220377,0.01172576119402985,0.007268962283181486
logarithmic,Chlorophyll,647.281006,0.00018807939298448595,y = 0.012369 + -0.000276*ln(x),134,10.960663313432837,3.9096921347220377,0.01172576119402985,0.007268962283181486
power,Chlorophyll,647.281006,-0.01877601035356702,y = 0.017959 * x^-0.209287,134,10.960663313432837,3.9096921347220377,0.01172576119402985,0.007268962283181486
exponential,Chlorophyll,647.281006,-0.019328048239278806,y = 0.013958 * exp(-0.021494*x),134,10.960663313432837,3.9096921347220377,0.01172576119402985,0.007268962283181486
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 647.281006 0.0003862335627651259 y = 0.012126 + -0.000037*x 134 10.960663313432837 3.9096921347220377 0.01172576119402985 0.007268962283181486
3 logarithmic Chlorophyll 647.281006 0.00018807939298448595 y = 0.012369 + -0.000276*ln(x) 134 10.960663313432837 3.9096921347220377 0.01172576119402985 0.007268962283181486
4 power Chlorophyll 647.281006 -0.01877601035356702 y = 0.017959 * x^-0.209287 134 10.960663313432837 3.9096921347220377 0.01172576119402985 0.007268962283181486
5 exponential Chlorophyll 647.281006 -0.019328048239278806 y = 0.013958 * exp(-0.021494*x) 134 10.960663313432837 3.9096921347220377 0.01172576119402985 0.007268962283181486

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,651.531006,0.00013536784274881253,y = 0.011403 + -0.000022*x,134,10.960663313432837,3.9096921347220377,0.011164671641791043,0.007310371385073625
logarithmic,Chlorophyll,651.531006,3.4274085199070825e-05,y = 0.011441 + -0.000119*ln(x),134,10.960663313432837,3.9096921347220377,0.011164671641791043,0.007310371385073625
power,Chlorophyll,651.531006,-0.01999886130480988,y = 0.017201 * x^-0.213892,134,10.960663313432837,3.9096921347220377,0.011164671641791043,0.007310371385073625
exponential,Chlorophyll,651.531006,-0.02080973971468425,y = 0.013316 * exp(-0.022113*x),134,10.960663313432837,3.9096921347220377,0.011164671641791043,0.007310371385073625
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 651.531006 0.00013536784274881253 y = 0.011403 + -0.000022*x 134 10.960663313432837 3.9096921347220377 0.011164671641791043 0.007310371385073625
3 logarithmic Chlorophyll 651.531006 3.4274085199070825e-05 y = 0.011441 + -0.000119*ln(x) 134 10.960663313432837 3.9096921347220377 0.011164671641791043 0.007310371385073625
4 power Chlorophyll 651.531006 -0.01999886130480988 y = 0.017201 * x^-0.213892 134 10.960663313432837 3.9096921347220377 0.011164671641791043 0.007310371385073625
5 exponential Chlorophyll 651.531006 -0.02080973971468425 y = 0.013316 * exp(-0.022113*x) 134 10.960663313432837 3.9096921347220377 0.011164671641791043 0.007310371385073625

View File

@ -0,0 +1,5 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,655.784973,6.712523797403058e-05,y = 0.010412 + -0.000016*x,134,10.960663313432837,3.9096921347220377,0.010241910447761193,0.007414076922911311
logarithmic,Chlorophyll,655.784973,7.939365778253382e-06,y = 0.010377 + -0.000058*ln(x),134,10.960663313432837,3.9096921347220377,0.010241910447761193,0.007414076922911311
power,Chlorophyll,655.784973,-0.02451200929710562,y = 0.017204 * x^-0.257829,134,10.960663313432837,3.9096921347220377,0.010241910447761193,0.007414076922911311
exponential,Chlorophyll,655.784973,-0.025546357658017715,y = 0.012631 * exp(-0.026616*x),134,10.960663313432837,3.9096921347220377,0.010241910447761193,0.007414076922911311
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 655.784973 6.712523797403058e-05 y = 0.010412 + -0.000016*x 134 10.960663313432837 3.9096921347220377 0.010241910447761193 0.007414076922911311
3 logarithmic Chlorophyll 655.784973 7.939365778253382e-06 y = 0.010377 + -0.000058*ln(x) 134 10.960663313432837 3.9096921347220377 0.010241910447761193 0.007414076922911311
4 power Chlorophyll 655.784973 -0.02451200929710562 y = 0.017204 * x^-0.257829 134 10.960663313432837 3.9096921347220377 0.010241910447761193 0.007414076922911311
5 exponential Chlorophyll 655.784973 -0.025546357658017715 y = 0.012631 * exp(-0.026616*x) 134 10.960663313432837 3.9096921347220377 0.010241910447761193 0.007414076922911311

View File

@ -0,0 +1,3 @@
regression_method,x_variable,y_variable,r_squared,equation,sample_size,x_mean,x_std,y_mean,y_std
linear,Chlorophyll,660.041016,2.3065421406842646e-05,y = 0.009045 + -0.000009*x,134,10.960663313432837,3.9096921347220377,0.008946089552238806,0.007372050533373144
logarithmic,Chlorophyll,660.041016,8.478475440609756e-07,y = 0.008902 + 0.000019*ln(x),134,10.960663313432837,3.9096921347220377,0.008946089552238806,0.007372050533373144
1 regression_method x_variable y_variable r_squared equation sample_size x_mean x_std y_mean y_std
2 linear Chlorophyll 660.041016 2.3065421406842646e-05 y = 0.009045 + -0.000009*x 134 10.960663313432837 3.9096921347220377 0.008946089552238806 0.007372050533373144
3 logarithmic Chlorophyll 660.041016 8.478475440609756e-07 y = 0.008902 + 0.000019*ln(x) 134 10.960663313432837 3.9096921347220377 0.008946089552238806 0.007372050533373144

Some files were not shown because too many files have changed in this diff Show More