fit_bspline_surface — 3D freeform op

• Data kinds: image2d × image2d × image2d → bspline_surface

• Call: import fullseye as fs; fs.ledger.fit_bspline_surface(x, y, z, kx=3, ky=3, smooth=None) (to call the implementation directly, import bspline_surf; bspline_surf.fit_bspline_surface(x, y, z, kx=3, ky=3, smooth=None); from the registry, ops3d.get("fit_bspline_surface"))

Usage

Least-squares fit a bicubic (default) B-spline surface to scattered (x, y, z) (bisplrep).

Parameters

x, y, z : array_like

Scattered sample coordinates and heights of equal count. Any shape is accepted; they are flattened to 1-D internally.

kx, ky : int

B-spline degree in the x/y direction (1=linear, 3=cubic). If the point count is less than (kx+1)*(ky+1)

the degree is lowered automatically (to avoid degeneracy).

smooth : float or None

Smoothing factor s. None is an automatic value based on the point count (_auto_surface_smooth).

0.0 passes through all points (interpolation-like = prone to overfitting); larger is smoother.

Returns

tck : list

[tx, ty, c, kx, ky]. Pass to eval_bspline_surface / surface_residual.

Raises

ValueError

If there are too few points even for a linear surface (m<4), the lengths of x/y/z differ, there are non-finite values,

or no approximation can be obtained because of FITPACK degeneracy from collinear or duplicate points.

Notes (verified against the implementation):

• The coordinate system is free: x, y are any planar coordinates (row/col or physical units), z is the height. The 3 arrays are flattened to 1-D with ravel, so grid input and scattered input are treated the same.

• Automatic degree lowering decrements the larger degree (kx on a tie) by 1 while (kx+1)*(ky+1) > m, and stops when both are 1. The lowering happens silently rather than as an exception, so check the actual degrees in the returned tck[3], tck[4].

• The automatic value for smooth=None is max(0, m - sqrt(2m)) (FITPACK's recommendation). The formula assumes a z noise variance of about 1, so data with small z units and a small residual sum of squares tend to be oversmoothed. In that case pass a small smooth explicitly.

• FITPACK warnings (iteration cut-off etc.) are swallowed and tck is returned. All exceptions are translated to ValueError, and an empty coefficient set also gives ValueError.

• Deterministic (no randomness).

• Downstream are eval_bspline_surface (evaluation) and surface_residual (deviation). If only global low-order waviness is needed there are fit_poly_surface / eval_poly_surface, but tck and the polynomial dict are not interchangeable.

References (sample data, literature)

• Sample-data catalog (download URLs / licences) — 2-D uses skimage.data (BSD/public domain) plus synthetic images; 3-D lists download URLs for real data sources (Stanford, PDS, …).

• Operator provenance and references — the sources of the research/methods this op family came from.

Runnable examples (verified samples that actually call this op)

• bspline_freeform — py -3.11 examples_3d/bspline_freeform.py

Ops the type connects to (they accept bspline_surface as input)

fuse_to_voxel · eval_bspline_surface · surface_residual

Same category (freeform)

eval_bspline_surface · surface_residual · fit_bspline_curve · eval_bspline_curve


*Provenance: bspline_surf.py — 3D operator registry. This per-op note is generated by tools/opdocs.py md (do not hand-edit).*

© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.