格式统一
This commit is contained in:
@ -2761,12 +2761,85 @@ class ContentMapper:
|
||||
print(f" NoData={nodata_value}, 有效像元: {int(valid_mask.sum())}/{grid_content.size}")
|
||||
return output_tif_path
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# ★ 2026-07-01:共享空间上下文 — 63 个 CSV 只算一次网格/掩膜
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
def prepare_shared_context(self, sample_csv: str, shp_file=None,
|
||||
resolution=100, expand_ratio=0.05):
|
||||
"""从首个 CSV 预计算所有子进程共用的空间基准数据。
|
||||
|
||||
63 个水色指数 CSV 坐标完全一致,以下数据只算一次:
|
||||
- boundary_gdf (水域边界)
|
||||
- grid_xx, grid_yy (插值网格)
|
||||
- mask (水域掩膜布尔矩阵)
|
||||
- bounds (空间范围)
|
||||
|
||||
子进程直接从 shared_context 解包复用,跳过 ②③④⑥,直入 Kriging。
|
||||
|
||||
Returns:
|
||||
tuple: (grid_xx, grid_yy, mask, bounds, boundary_gdf)
|
||||
"""
|
||||
print(f"[共享上下文] 从 {Path(sample_csv).name} 预计算空间基准...")
|
||||
|
||||
# ② 读边界(只此一次)
|
||||
if shp_file is None:
|
||||
boundary_gdf = None
|
||||
else:
|
||||
boundary_gdf = self.read_boundary_shapefile(shp_file)
|
||||
|
||||
# ③ 边缘外扩(只此一次)—— 需要读第一个CSV获取坐标结构
|
||||
points_gdf = self.read_csv_data(sample_csv)
|
||||
points_gdf = self._expand_edge_points(
|
||||
points_gdf, boundary_gdf, resolution=resolution, expand_ratio=expand_ratio
|
||||
)
|
||||
|
||||
# ④ 计算网格几何
|
||||
if boundary_gdf is None:
|
||||
pts = np.column_stack((points_gdf['proj_x'], points_gdf['proj_y']))
|
||||
minx, maxx = pts[:, 0].min(), pts[:, 0].max()
|
||||
miny, maxy = pts[:, 1].min(), pts[:, 1].max()
|
||||
else:
|
||||
bnd = boundary_gdf.total_bounds
|
||||
minx, miny, maxx, maxy = bnd
|
||||
|
||||
width = maxx - minx
|
||||
height = maxy - miny
|
||||
minx -= width * expand_ratio
|
||||
maxx += width * expand_ratio
|
||||
miny -= height * expand_ratio
|
||||
maxy += height * expand_ratio
|
||||
|
||||
res = resolution / 111000.0 if self.output_crs == 'EPSG:4326' else resolution
|
||||
nx = max(int(width / res), 100)
|
||||
ny = max(int(height / res), 100)
|
||||
grid_x = np.linspace(minx, maxx, nx)
|
||||
grid_y = np.linspace(miny, maxy, ny)
|
||||
grid_xx, grid_yy = np.meshgrid(grid_x, grid_y)
|
||||
bounds = np.array([minx, miny, maxx, maxy])
|
||||
|
||||
print(f"[共享上下文] 网格: {nx}×{ny} = {nx*ny} 点")
|
||||
|
||||
# ⑥ 水域掩膜布尔矩阵(只此一次)
|
||||
mask = None
|
||||
if boundary_gdf is not None:
|
||||
mask_pts = np.column_stack((grid_xx.ravel(), grid_yy.ravel()))
|
||||
mask_gdf = gpd.GeoDataFrame(
|
||||
geometry=[Point(x, y) for x, y in mask_pts], crs=self.output_crs
|
||||
)
|
||||
mask = mask_gdf.within(boundary_gdf.unary_union).values.reshape(grid_xx.shape)
|
||||
print(f"[共享上下文] 水域掩膜: {int(mask.sum())}/{mask.size} 点在水域内")
|
||||
|
||||
return (grid_xx, grid_yy, mask, bounds, boundary_gdf)
|
||||
|
||||
|
||||
def process_data(self, csv_file, shp_file=None, output_file='content_map.png',
|
||||
resolution=100, show_sample_points=False, base_map_tif=None,
|
||||
use_distance_diffusion=True, max_diffusion_distance=None,
|
||||
diffusion_power=2, diffusion_n_neighbors=15, cmap=None,
|
||||
expand_ratio=0.05,
|
||||
output_format='tif'):
|
||||
output_format='tif',
|
||||
shared_context=None):
|
||||
"""
|
||||
主处理函数
|
||||
|
||||
@ -2778,56 +2851,72 @@ class ContentMapper:
|
||||
CSV文件路径
|
||||
shp_file : str, optional
|
||||
水域掩膜/边界文件路径(.shp / .dat / .bsq / .tif 等)。
|
||||
★★★ None 时跳过所有边界相关逻辑,插值仅基于采样点自然扩展 ★★★
|
||||
base_map_tif : str, optional
|
||||
TIF正射底图文件路径。如果提供,将在水域掩膜外显示底图
|
||||
use_distance_diffusion : bool, default=True
|
||||
是否使用距离扩散方法填充边界空白区域(shp_file=None 时无效)
|
||||
max_diffusion_distance : float, optional
|
||||
最大扩散距离(单位与坐标相同)。如果为None,自动计算为网格分辨率的5倍
|
||||
diffusion_power : float, default=2
|
||||
距离扩散的IDW幂参数,值越大,距离衰减越快
|
||||
diffusion_n_neighbors : int, default=15
|
||||
距离扩散使用的最近邻点数
|
||||
cmap : str, optional
|
||||
颜色映射。如果为None,将从CSV文件名或内容中自动识别参数并选择对应的colormap
|
||||
expand_ratio : float, default=0.05
|
||||
边界外扩比例(5%),用于从采样点范围外扩出图像边界
|
||||
output_format : str, default='tif'
|
||||
输出格式:'tif'(GeoTIFF)或 'png'(渲染图)
|
||||
shared_context : tuple, optional (2026-07-01 批量优化)
|
||||
由 prepare_shared_context() 返回的 (grid_xx, grid_yy, mask, bounds, boundary_gdf)。
|
||||
提供时跳过 读边界/边缘外扩/建网格/算掩膜,直入 Kriging 插值阶段。
|
||||
... (其他参数同上)
|
||||
"""
|
||||
try:
|
||||
# 自动识别参数名称并获取colormap
|
||||
if cmap is None:
|
||||
param_name = self._extract_param_name(csv_file)
|
||||
cmap = self._get_colormap(param_name)
|
||||
else:
|
||||
print(f"使用指定的颜色映射: {cmap}")
|
||||
|
||||
# 读取采样点数据
|
||||
points_gdf = self.read_csv_data(csv_file)
|
||||
|
||||
# ── Plan C: shp_file=None 时跳过所有水域掩膜逻辑 ───────────
|
||||
if shp_file is None:
|
||||
print("[Plan C] shp_file=None,跳过水域掩膜读取,插值不依赖边界约束")
|
||||
boundary_gdf = None
|
||||
# ── ★ 快速通道:复用预计算的共享上下文 ──
|
||||
if shared_context is not None:
|
||||
grid_xx, grid_yy, mask, bounds, boundary_gdf = shared_context
|
||||
# ③ 仍需边缘扩展(值相关),但跳过 ②④⑥
|
||||
points_gdf = self._expand_edge_points(
|
||||
points_gdf, boundary_gdf, resolution=resolution,
|
||||
expand_ratio=expand_ratio
|
||||
)
|
||||
# ⑤ 直接用共享网格执行 Kriging
|
||||
pts = np.column_stack((points_gdf['proj_x'], points_gdf['proj_y']))
|
||||
vals = points_gdf['content'].values
|
||||
grid_content = self._perform_interpolation(pts, vals, grid_xx, grid_yy)
|
||||
# ⑥ 复用共享掩膜裁剪
|
||||
if mask is not None:
|
||||
grid_content[~mask] = np.nan
|
||||
# 边界内 NaN 填充
|
||||
nan_mask = np.isnan(grid_content)
|
||||
within_nan = nan_mask & mask
|
||||
if np.any(within_nan):
|
||||
valid_m = ~nan_mask & mask
|
||||
if np.sum(valid_m) > 0:
|
||||
v_pts = np.column_stack((grid_xx[valid_m], grid_yy[valid_m]))
|
||||
v_vals = grid_content[valid_m]
|
||||
n_pts = np.column_stack((grid_xx[within_nan], grid_yy[within_nan]))
|
||||
try:
|
||||
from scipy.interpolate import griddata
|
||||
grid_content[within_nan] = griddata(
|
||||
v_pts, v_vals, n_pts, method='nearest'
|
||||
)
|
||||
except Exception:
|
||||
grid_content[within_nan] = np.nanmean(grid_content[mask])
|
||||
else:
|
||||
boundary_gdf = self.read_boundary_shapefile(shp_file)
|
||||
# ── 原有完整流程(单图模式)──────────
|
||||
if shp_file is None:
|
||||
print("[Plan C] shp_file=None,跳过水域掩膜读取")
|
||||
boundary_gdf = None
|
||||
else:
|
||||
boundary_gdf = self.read_boundary_shapefile(shp_file)
|
||||
|
||||
# 对边缘采样点进行外扩处理(boundary_gdf=None 时基于采样点自身范围外扩)
|
||||
points_gdf = self._expand_edge_points(
|
||||
points_gdf, boundary_gdf, resolution=resolution, expand_ratio=expand_ratio
|
||||
)
|
||||
points_gdf = self._expand_edge_points(
|
||||
points_gdf, boundary_gdf, resolution=resolution,
|
||||
expand_ratio=expand_ratio
|
||||
)
|
||||
|
||||
# 创建插值网格(boundary_gdf=None 时纯采样点插值,无掩膜裁剪)
|
||||
grid_xx, grid_yy, grid_content, bounds = self.create_interpolation_grid(
|
||||
points_gdf, boundary_gdf, resolution,
|
||||
expand_ratio=expand_ratio,
|
||||
use_distance_diffusion=use_distance_diffusion,
|
||||
max_diffusion_distance=max_diffusion_distance,
|
||||
diffusion_power=diffusion_power,
|
||||
diffusion_n_neighbors=diffusion_n_neighbors
|
||||
)
|
||||
grid_xx, grid_yy, grid_content, bounds = self.create_interpolation_grid(
|
||||
points_gdf, boundary_gdf, resolution,
|
||||
expand_ratio=expand_ratio,
|
||||
use_distance_diffusion=use_distance_diffusion,
|
||||
max_diffusion_distance=max_diffusion_distance,
|
||||
diffusion_power=diffusion_power,
|
||||
diffusion_n_neighbors=diffusion_n_neighbors
|
||||
)
|
||||
|
||||
# ── 按 output_format 分发落盘方式 ───────────────────────────
|
||||
if output_format == 'tif':
|
||||
|
||||
Reference in New Issue
Block a user