You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过质心、裁剪或其他方式筛选Shapely多边形?

筛选生命之花中的完整圆形区域

问题分析

你通过buffer生成圆形,经unary_union和polygonize拆分出所有重叠区域,且已去除细碎多边形。现在需要保留原点(0,0)的中心圆和第一层环绕的6个花瓣圆,这类区域的核心特征是:未被其他圆切割的完整圆形,面积与原始生成圆一致,质心与原始圆心几乎重合。

可行解决方案

1. 面积筛选法(最直接)

原始圆半径为2,理论面积为π*2²≈12.566。经过polygonize后的完整圆形区域面积会非常接近该值,而重叠区域面积必然更小。通过设置误差容忍度筛选:

# 原始圆的理论面积
target_area = np.pi * 2**2
# 面积误差容忍度
area_tolerance = 0.1

# 筛选面积接近目标值的多边形
final_filtered = [poly for poly in filtered_polys if abs(poly.area - target_area) < area_tolerance]

2. 质心+距离筛选法

若面积筛选存在误差,可结合质心位置判断:完整圆的质心与原始生成该圆的点几乎重合。先定义目标圆心列表,再计算多边形质心与这些点的距离,设置小阈值筛选:

# 定义需要保留的原始圆心(中心+第一层)
target_centers = [
    Point(0, 0),
    Point(2, 0), Point(-2, 0),
    Point(1, h), Point(-1, h),
    Point(1, -h), Point(-1, -h)
]

# 距离误差容忍度
distance_tolerance = 0.01

final_filtered = []
for poly in filtered_polys:
    poly_centroid = poly.centroid
    # 检查是否与任意目标圆心接近
    for center in target_centers:
        if poly_centroid.distance(center) < distance_tolerance:
            final_filtered.append(poly)
            break

修改后的完整代码

将上述筛选逻辑替换原代码中filtered_polys之后的部分即可:

import matplotlib.pyplot as plt
from shapely.geometry import Point, LineString
from shapely.ops import unary_union, polygonize

from matplotlib.pyplot import cm
import numpy as np


def plot_coords(coords, color):
    pts = list(coords)
    x, y = zip(*pts)
    plt.plot(x,y, color='k', linewidth=1)
    plt.fill_between(x, y, facecolor=color)


def plot_polys(polys, color):
    for poly, color in zip(polys, color):
        plot_coords(poly.exterior.coords, color)

x = 0
y = 0
h = 1.73205080757

points = [# center
          Point(x, y),
          #  first ring
          Point((x + 2), y),
          Point((x - 2), y),
          Point((x + 1), (y + h)),
          Point((x - 1), (y + h)),
          Point((x + 1), (y - h)),
          Point((x - 1), (y - h)),
          # second ring
          Point((x + 3), h),
          Point((x - 3), h),
          Point((x + 3), -h),
          Point((x - 3), -h),
          Point((x + 2), (h + h)),
          Point((x - 2), (h + h)),
          Point((x + 2), (-h + -h)),
          Point((x - 2), (-h + -h)),
          Point((x + 4), y),
          Point((x - 4), y),
          Point(x, (h + h)),
          Point(x, (-h + -h)),
          #third ring
          Point((x + 4), (h + h)),
          Point((x - 4), (h + h)),
          Point((x + 4), (-h + -h)),
          Point((x - 4), (-h + -h)),
          Point((x + 1), (h + h + h)),
          Point((x - 1), (h + h + h)),
          Point((x + 1), (-h + -h + -h)),
          Point((x - 1), (-h + -h + -h)),
          Point((x + 5), h),
          Point((x - 5), h),
          Point((x + 5), -h),
          Point((x - 5), -h)]

# buffer points to create circle polygons

circles = []
for point in points:
    circles.append(point.buffer(2))


# unary_union and polygonize to find overlaps

rings = [LineString(list(pol.exterior.coords)) for pol in circles]
union = unary_union(rings)
result_polys = [geom for geom in polygonize(union)]

# remove tiny sliver polygons
threshold = 0.01
filtered_polys = [polygon for polygon in result_polys if polygon.area > threshold]

# --- 新增筛选逻辑:保留完整圆形 ---
# 方法1:面积筛选(默认启用)
target_area = np.pi * 2**2
area_tolerance = 0.1
final_filtered = [poly for poly in filtered_polys if abs(poly.area - target_area) < area_tolerance]

# 或者用方法2:质心距离筛选(取消注释即可切换)
# target_centers = [
#     Point(0, 0),
#     Point(2, 0), Point(-2, 0),
#     Point(1, h), Point(-1, h),
#     Point(1, -h), Point(-1, -h)
# ]
# distance_tolerance = 0.01
# final_filtered = []
# for poly in filtered_polys:
#     poly_centroid = poly.centroid
#     for center in target_centers:
#         if poly_centroid.distance(center) < distance_tolerance:
#             final_filtered.append(poly)
#             break
# --- 筛选结束 ---

print("total polygons = " + str(len(result_polys)))
print("filtered polygons = " + str(len(filtered_polys)))
print("final selected polygons = " + str(len(final_filtered)))


colors = cm.viridis(np.linspace(0, 1, len(final_filtered)))


fig = plt.figure()
ax = fig.add_subplot()
fig.subplots_adjust(top=0.85)


plot_polys(final_filtered, colors)


ax.set_aspect('equal')
plt.show()

补充说明

  • 你之前尝试质心筛选未成功,大概率是未限定目标圆心范围或阈值设置不合理。上述质心方法明确指定了匹配的原始圆心,配合小阈值即可准确筛选。
  • snap()或clip_by_rect()更适合几何对齐或区域裁剪,对于当前筛选完整圆形的需求,面积+质心的组合方法更直接高效。

内容的提问来源于stack exchange,提问作者Doda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 12:24:20