Python如何对二维形状进行重采样?工业机器轨迹计算场景
二维凸形曲线重采样的最优实现方案
针对你提到的二维凸形(闭合曲线)重采样需求,分两种核心场景给出落地实现,同时解释为什么时间序列工具不适合几何数据:
一、均匀弧长重采样(优先推荐)
核心逻辑
几何曲线的"均匀分布"指弧长维度的均匀,而非坐标空间的均匀。直接用时间序列插值会导致非圆曲线的点分布失衡(比如椭圆长轴点密、短轴点疏),正确步骤是:
- 计算原始点的累积弧长,把弧长作为曲线的参数
- 对x/y坐标做参数化样条插值(适配闭合曲线)
- 生成均匀间隔的弧长采样点,映射回坐标空间
代码实现
import numpy as np from scipy.interpolate import splprep, splev # 示例:原始25个点的椭圆凸形 theta = np.linspace(0, 2*np.pi, 25) x = 2*np.cos(theta) y = np.sin(theta) original_points = np.vstack((x, y)).T # 1. 计算每段弧长和累积弧长 dx = np.diff(x) dy = np.diff(y) seg_lengths = np.sqrt(dx**2 + dy**2) cum_length = np.concatenate(([0], np.cumsum(seg_lengths))) total_length = cum_length[-1] # 2. 生成1000个均匀弧长采样点 num_new_points = 1000 new_lengths = np.linspace(0, total_length, num_new_points) # 3. 闭合曲线参数化样条插值(s=0严格经过原始点) tck, u = splprep([x, y], s=0, per=1) # 把均匀弧长映射到样条参数u空间 new_u = np.interp(new_lengths, cum_length, u) new_x, new_y = splev(new_u, tck) # 最终重采样点集 resampled_points = np.vstack((new_x, new_y)).T
二、自适应密度重采样(尖锐处加密)
核心逻辑
针对圆角六边形这类有尖锐特征的凸形,需要在曲率大的区域(拐角)增加采样密度,步骤是:
- 通过样条导数计算原始曲线的曲率
- 生成与曲率成反比的采样间隔(曲率越大,间隔越小)
- 基于自适应间隔的弧长点做插值
代码实现
import numpy as np from scipy.interpolate import splprep, splev from scipy.ndimage import gaussian_filter1d # 复用原始点和累积弧长(来自上一段代码) x, y = original_points[:,0], original_points[:,1] cum_length = cum_length total_length = total_length # 1. 计算并平滑曲率(闭合曲线) tck, u = splprep([x, y], s=0, per=1) dx_du, dy_du = splev(u, tck, der=1) d2x_du2, d2y_du2 = splev(u, tck, der=2) # 曲率公式:k = |x’ y'' - x'' y’| / (x’² + y’²)^(3/2) curvature = np.abs(dx_du * d2y_du2 - d2x_du2 * dy_du) / (dx_du**2 + dy_du**2)**1.5 curvature_smoothed = gaussian_filter1d(curvature, sigma=1) # 2. 生成自适应采样间隔(曲率越大,间隔越小) min_step = total_length / 2000 # 最小间隔(保证尖锐处密度) max_step = total_length / 500 # 最大间隔(避免平坦区过密) # 调整系数100控制加密程度,按需修改 step_sizes = max_step / (1 + curvature_smoothed * 100) step_sizes = np.clip(step_sizes, min_step, max_step) # 3. 生成自适应弧长采样点 current_length = 0 new_lengths = [0] while current_length < total_length - min_step: idx = np.argmax(cum_length >= current_length) - 1 current_length += step_sizes[idx] new_lengths.append(current_length) new_lengths[-1] = total_length # 确保闭合 new_lengths = np.array(new_lengths) # 4. 插值得到最终点集 new_u = np.interp(new_lengths, cum_length, u) new_x, new_y = splev(new_u, tck) adaptive_resampled_points = np.vstack((new_x, new_y)).T
为什么不推荐scipy.signal.resample?
这个工具是为时间序列设计的傅里叶插值,假设数据是随时间均匀采样的周期信号。但几何曲线的核心参数是弧长而非时间:
- 直接对x/y分别重采样会导致弧长分布失衡(比如椭圆长轴点密、短轴点疏)
- 针对闭合曲线,傅里叶插值会引入不必要的边界失真
- 无法实现基于曲率的自适应密度调整
内容的提问来源于stack exchange,提问作者sokol07
相关产品推荐
相关产品推荐

