如何使用Geopandas求解多几何对象集合的凸包或包络线
几何对象聚合求整体包络/凸包实现方案
你之前调用s.envelope得到单个多边形各自包络的问题,本质是没有先把需要聚合的多边形合并为一个几何集合,直接对GeoSeries逐元素计算导致的。以下是可直接落地的实现方案:
基础实现(全量/指定子集聚合)
核心逻辑是先用unary_union合并所有目标多边形为单个几何集合(天然支持不相交对象),再对整体计算包络/凸包,全量聚合和指定子集聚合逻辑完全通用:
import geopandas as gpd from shapely.geometry import Polygon from shapely.ops import unary_union # 你的示例数据生成代码 s = gpd.GeoSeries( [ Polygon([(4, 4), (4, 2),(2,2), (2, 4)]), Polygon([(8, 8), (8, 6),(6,6), (6, 8)]), Polygon([(6, 2), (8, 2),(8,4), (6, 4)]), Polygon([(2, 6), (2, 8),(4,8), (4, 6)]) ] ) sdf = gpd.GeoDataFrame(s.rename('geometry')).reset_index() # -------------------------- # 1、全量聚合所有多边形 # -------------------------- all_geoms = unary_union(sdf['geometry']) # 整体轴对齐包络(实现最简单,优先选择) total_envelope = all_geoms.envelope # 整体最小凸包(更贴合形状,可按需替换) total_convex_hull = all_geoms.convex_hull # -------------------------- # 2、指定子集聚合(比如选前2个正方形) # -------------------------- subset_geoms = unary_union(sdf.loc[sdf['index'].isin([0,1]), 'geometry']) subset_envelope = subset_geoms.envelope
扩展功能:按数量/面积阈值分组聚合
如果需要自定义单个包络容纳的多边形数量、或者设置最大面积阈值,可以配合聚类逻辑实现分组聚合,以下是按单组最大数量拆分的示例:
from sklearn.cluster import KMeans import numpy as np # 配置参数:单个包络最多容纳2个多边形 max_count_per_group = 2 # 提取每个多边形质心作为聚类特征 centroids = np.array(list(sdf['geometry'].apply(lambda x: [x.centroid.x, x.centroid.y]))) # 计算所需分组数 n_clusters = max(1, len(sdf) // max_count_per_group) # 聚类打分组标签 sdf['group'] = KMeans(n_clusters=n_clusters, random_state=0).fit_predict(centroids) # 按分组计算各自的整体包络 group_result = sdf.groupby('group')['geometry'].apply( lambda g: unary_union(g).envelope # 替换为.convex_hull即可计算凸包 ).reset_index().rename(columns={'geometry':'group_envelope'})
如果需要按面积阈值拆分,只要在生成每个分组包络后判断面积是否超过阈值,超过则进一步拆分为更小的分组即可。
示例效果
你给出的4个离散正方形原始效果如下:
全量聚合后的包络为左下角(2,2)到右上角(8,8)的矩形,和全量凸包结果一致。
内容的提问来源于stack exchange,提问作者Serge de Gosson de Varennes
相关产品推荐
相关产品推荐

