【问题标题】:Querying multiple points on a bivariate spline in the B-spline basis在 B 样条基础上查询双变量样条上的多个点
【发布时间】:2017-10-27 21:11:40
【问题描述】:

我需要构建一个 3D B-spline 表面并在各种参数坐标下对其进行多次采样。我找到的最接近的解决方案是使用bisplev,它期望tck 输入由bsplprep 计算。不幸的是,我不能使用 tck 组件,因为它会产生一个通过控制点的表面,而我想要的是在 B-spline basis 中计算的表面。所以我手动构造了tck 输入bsplev 可以用来产生所需的表面。

不幸的是,如果不使用 2 个嵌套循环,我无法弄清楚如何做到这一点:每个 uv 查询一个,每个空间组件一个。后者是可以接受的,但前者在处理非常大的查询数组时非常慢。

代码如下:

import numpy as np
import scipy.interpolate as si

def bivariate_bspline(cv,u,v,uCount,vCount,uDegree,vDegree):
    # cv = grid of control vertices
    # u,v = list of u,v component queries
    # uCount, vCount = number of control points along the u and v directions
    # uDegree, vDegree = curve degree along the u and v directions
    
    uMax = uCount-uDegree # Max u parameter
    vMax = vCount-vDegree # Max v parameter
    
    # Calculate knot vectors for both u and v
    u_kv = np.clip(np.arange(uCount+uDegree+1)-uDegree,0,uCount-uDegree) # knot vector in the u direction
    v_kv = np.clip(np.arange(vCount+vDegree+1)-vDegree,0,vCount-vDegree) # knot vector in the v direction
    
    # Compute queries
    position = np.empty((u.shape[0], cv.shape[1]))
    for i in xrange(cv.shape[1]):
        tck = (u_kv, v_kv, cv[:,i], uDegree,vDegree)
        
        for j in xrange(u.shape[0]):
            position[j,i] = si.bisplev(u[j],v[j], tck)

    return position

测试:

# A test grid of control vertices
cv = np.array([[-0.5       , -0.  ,        0.5       ],
               [-0.5       , -0.  ,        0.33333333],
               [-0.5       , -0.  ,        0.        ],
               [-0.5       ,  0.  ,       -0.33333333],
               [-0.5       ,  0.  ,       -0.5       ],
               [-0.16666667,  1.  ,        0.5       ],
               [-0.16666667, -0.  ,        0.33333333],
               [-0.16666667,  0.5 ,        0.        ],
               [-0.16666667,  0.5 ,       -0.33333333],
               [-0.16666667,  0.  ,       -0.5       ],
               [ 0.16666667, -0.  ,        0.5       ],
               [ 0.16666667, -0.  ,        0.33333333],
               [ 0.16666667, -0.  ,        0.        ],
               [ 0.16666667,  0.  ,       -0.33333333],
               [ 0.16666667,  0.  ,       -0.5       ],
               [ 0.5       , -0.  ,        0.5       ],
               [ 0.5       , -0.  ,        0.33333333],
               [ 0.5       , -0.5 ,        0.        ],
               [ 0.5       ,  0.  ,       -0.33333333],
               [ 0.5       ,  0.  ,       -0.5       ]])

uCount = 4
vCount = 5
uDegree = 3
vDegree = 3

n = 10**4 # make 10k random queries
u = np.random.random(n) * (uCount-uDegree) 
v = np.random.random(n) * (vCount-vDegree) 
bivariate_bspline(cv,u,v,uCount,vCount,uDegree,vDegree) # will return n correct samples on a b-spline basis surface

速度测试:

import cProfile
cProfile.run('bivariate_bspline(cv,u,v,uCount,vCount,uDegree,vDegree)') # 0.929 seconds

因此,对于 10k 个样本,将近 1 秒,其中 bisplev 调用占用了大部分计算时间,因为每个空间组件都调用了 10k 次。

我确实尝试用一个 bisplev 调用替换 for j in xrange(u.shape[0]): 循环,一次性给它 u 和 v 数组,但这会在 scipy\interpolate\_fitpack_impl.py", line 1048, in bisplev 引发 ValueError: Invalid input data

问题

有没有办法摆脱这两者,或者至少摆脱 uv 查询循环并在单个矢量化操作中执行所有 uv 查询?

【问题讨论】:

  • 如果您尝试si.bisplev(u, v, tck),会出现什么问题? bisplev 方法应该接受数组。
  • @Desire 它在scipy\interpolate\_fitpack_impl.py", line 1048, in bisplev raise ValueError("Invalid input data") 引发ValueError("Invalid input data")

标签: python numpy scipy


【解决方案1】:

简答:替换

for i in xrange(cv.shape[1]):
    tck = (u_kv, v_kv, cv[:,i], uDegree,vDegree)
    for j in xrange(u.shape[0]):
        position[j,i] = si.bisplev(u[j],v[j], tck)

for i in xrange(cv.shape[1]):
    position[:, i] = si.dfitpack.bispeu(u_kv, v_kv, cv[:,i], uDegree, vDegree, u, v)[0]

说明

bisplev 确实接受数组为si.bisplev(u, v, tck),但它将它们解释为定义 xy 网格。因此,uv 必须按升序排序,并且将对所有对 (u[j], v[k]) 执行评估,输出是一个二维数组值。这不是你想要的;将评估的数量平方可能很糟糕,并且从返回的 2D 数组中提取您实际想要的值并不容易(它们不一定在对角线上,因为您的 u, v 开始时没有排序)。

call method of SmoothBivariateSpline 包含一个布尔参数grid,将其设置为False 使其仅评估(u[j], v[j]) 对处的样条。向量 u, v 不再需要排序,但现在它们必须具有相同的大小。

但是您正在准备自己的tck。这提出了两种方法:寻求用手工制作的 tck 实例化SmoothBivariateSpline;或阅读its call method 的源代码并在参数grid 设置为False 时执行它的操作。我选择了后一种方法。

【讨论】:

  • 谢谢你!!!巨大的性能提升!除非有办法也摆脱每个空间维度的循环,否则这会赢!
猜你喜欢
  • 2013-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-20
  • 2014-12-16
  • 2015-09-27
  • 1970-01-01
相关资源
最近更新 更多