ds_msp.models¶
The seven camera models, each implementing the CameraModel contract. Pick by FOV
and required accuracy — see Choosing a camera model.
Double Sphere¶
ds_msp.models.DoubleSphereModel ¶
Double Sphere camera (Usenko et al. 2018). Satisfies CameraModel.
Source code in ds_msp/models/double_sphere.py
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | |
distortion
property
¶
Distortion tail [xi, alpha] (sphere offset, perspective blend).
params
property
¶
Flat parameter vector [fx, fy, cx, cy, xi, alpha], see param_names.
from_dict
classmethod
¶
from_params
classmethod
¶
Build from a flat [fx, fy, cx, cy, xi, alpha] vector.
initialize_from_correspondences ¶
Seed fx,fy,cx,cy from K_seed; seed xi=0 and solve alpha linearly
(reduces to the UCM closed form since xi=0 collapses both spheres into one).
Source code in ds_msp/models/double_sphere.py
param_bounds
classmethod
¶
Optimizer bounds: xi in [-1, 1], alpha in (0, 1), focal/center wide-open.
Source code in ds_msp/models/double_sphere.py
project ¶
Project camera-frame points to pixels via the two-sphere composition.
The Double Sphere model is what makes this model's family distinct: a
point is first re-centered onto a unit sphere shifted by xi along
-Z (z1 = z + xi*d1), then perspective-divided from a second point
blended between that shifted sphere and the pinhole plane by
alpha. Composing two spheres (rather than one, as in UCMModel)
is what lets this closed-form model reach fields of view beyond 180°
(Usenko et al. 2018, Sec. 3).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
P
|
(ndarray, shape(..., 3))
|
Camera-frame points (meters), +Z forward. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
uv |
(ndarray, shape(..., 2))
|
Projected pixel coordinates |
valid |
(ndarray, shape(...))
|
Projectability mask. |
References
Usenko, V., Demmel, N., Cremers, D. "The Double Sphere Camera Model." 3DV 2018 (projection; see Eq. 43-45 for the validity half-space).
Examples:
A point behind the pinhole plane (z < 0) can still be valid —
this is the wide-FOV behavior the two-sphere composition exists for:
>>> import numpy as np
>>> from ds_msp.models import DoubleSphereModel
>>> m = DoubleSphereModel.sample()
>>> uv, valid = m.project(np.array([[1.0, 0.0, -0.3]]))
>>> bool(valid[0])
True
Source code in ds_msp/models/double_sphere.py
project_jacobian ¶
Project with analytic derivatives (no autodiff, no finite differences).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
P
|
(ndarray, shape(..., 3))
|
Camera-frame points (meters), +Z forward. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
uv |
(ndarray, shape(..., 2))
|
Projected pixel coordinates, identical to |
J_point |
(ndarray, shape(..., 2, 3))
|
|
J_param |
(ndarray, shape(..., 2, 6))
|
|
valid |
(ndarray, shape(...))
|
Projectability mask, identical condition to |
References
Usenko, V., Demmel, N., Cremers, D. "The Double Sphere Camera Model." 3DV 2018
(closed-form Jacobian derived from the projection above; verified here by
finite-difference check, relative error <= 1e-6, see pytest -m jac).
Examples:
>>> import numpy as np
>>> from ds_msp.models import DoubleSphereModel
>>> m = DoubleSphereModel.sample()
>>> uv, J_point, J_param, valid = m.project_jacobian(np.array([[0.0, 0.0, 1.0]]))
>>> J_point.shape, J_param.shape
((1, 2, 3), (1, 2, 6))
Source code in ds_msp/models/double_sphere.py
sample
classmethod
¶
Realistic instance for contract testing (the bundled calibration).
to_dict ¶
Serialize to {"model": "ds", "fx": ..., ..., "alpha": ...}.
unproject ¶
Unproject pixels to unit bearing rays (closed form).
Inverts the two-sphere composition analytically (no iteration): first
recovers the point on the shifted sphere from the normalized pixel,
then un-shifts by xi. See ds_msp.models.ds_math.ds_unproject
for the exact algebra.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
uv
|
(ndarray, shape(..., 2))
|
Pixel coordinates |
required |
Returns:
| Name | Type | Description |
|---|---|---|
rays |
(ndarray, shape(..., 3))
|
Unit-norm camera-frame bearing vectors, +Z forward. |
valid |
(ndarray, shape(...))
|
|
References
Usenko, V., Demmel, N., Cremers, D. "The Double Sphere Camera Model." 3DV 2018 (closed-form unprojection).
Examples:
>>> import numpy as np
>>> from ds_msp.models import DoubleSphereModel
>>> m = DoubleSphereModel.sample()
>>> rays, valid = m.unproject(np.array([[m.cx, m.cy]]))
>>> np.round(rays, 4)
array([[0., 0., 1.]])
Source code in ds_msp/models/double_sphere.py
Double Sphere⁺ (DS⁺)¶
ds_msp.models.DSPlusModel ¶
DS+ (UCM core + division radial + 2-axis tilt). Satisfies CameraModel.
Source code in ds_msp/models/dsplus.py
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | |
from_dict
classmethod
¶
from_params
classmethod
¶
initialize_from_correspondences ¶
Seed fx,fy,cx,cy from K_seed; solve alpha linearly (same UCM
closed form as UCMModel); zero the radial/tilt terms.
Source code in ds_msp/models/dsplus.py
param_bounds
classmethod
¶
Optimizer bounds: alpha in (0, 1), tilt/radial terms modestly bounded.
Source code in ds_msp/models/dsplus.py
project ¶
Project camera-frame points through 4 closed-form-invertible stages.
DS+ replaces Double Sphere's xi shift (the proven near-null
direction for the target lens, see the module docstring) with a UCM
sphere core followed by two extra closed-form stages: a Fitzgibbon
division-model radial layer and a 2-axis Scheimpflug tilt homography,
so the composed map stays fully closed-form invertible end to end::
pixel = K . H_tau . D_lambda . S_alpha(bearing)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
P
|
(ndarray, shape(..., 3))
|
Camera-frame points (meters), +Z forward. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
uv |
(ndarray, shape(..., 2))
|
Projected pixel coordinates |
valid |
(ndarray, shape(...))
|
|
References
UCM core: Geyer, C., Daniilidis, K. "A Unifying Theory for Central
Panoramic Systems." ECCV 2000; Mei, C., Rives, P. ICRA 2007.
Division radial layer: Fitzgibbon, A. "Simultaneous linear estimation
of multiple view geometry and lens distortion." CVPR 2001.
Tilt homography: cf. OpenCV CALIB_TILTED_MODEL. Staged
composition and Jacobian are this repo's own extension — see
ds_msp/models/dsplus_math.py and
ADR-0005.
Examples:
>>> import numpy as np
>>> from ds_msp.models import DSPlusModel
>>> m = DSPlusModel.sample()
>>> uv, valid = m.project(np.array([[0.0, 0.0, 1.0]]))
>>> np.round(uv, 2)
array([[949.18, 518.81]])
Source code in ds_msp/models/dsplus.py
project_jacobian ¶
Project with analytic derivatives via the chain rule through all 4 stages.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
P
|
(ndarray, shape(..., 3))
|
Camera-frame points (meters), +Z forward. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
uv |
(ndarray, shape(..., 2))
|
Projected pixel coordinates, identical to |
J_point |
(ndarray, shape(..., 2, 3))
|
|
J_param |
(ndarray, shape(..., 2, 9))
|
|
valid |
(ndarray, shape(...))
|
Projectability mask, identical condition to |
Examples:
>>> import numpy as np
>>> from ds_msp.models import DSPlusModel
>>> m = DSPlusModel.sample()
>>> uv, J_point, J_param, valid = m.project_jacobian(np.array([[0.0, 0.0, 1.0]]))
>>> J_point.shape, J_param.shape
((1, 2, 3), (1, 2, 9))
Source code in ds_msp/models/dsplus.py
sample
classmethod
¶
Realistic instance for contract testing (the bundled calibration).
to_dict ¶
Serialize to {"model": "dsplus", "fx": ..., ..., "tau_y": ...}.
unproject ¶
Unproject pixels to unit bearing rays (closed form, no iteration).
Inverts the 4-stage chain in reverse (K^-1, tilt inverse, then a
quadratic/quartic radical to invert the division-model radial layer,
then the UCM closed form). See
ds_msp.models.dsplus_math.dsplus_unproject and
ds_msp.models.dsplus_math._invert_division.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
uv
|
(ndarray, shape(..., 2))
|
Pixel coordinates |
required |
Returns:
| Name | Type | Description |
|---|---|---|
rays |
(ndarray, shape(..., 3))
|
Unit-norm camera-frame bearing vectors, +Z forward. |
valid |
(ndarray, shape(...))
|
|
Examples:
>>> import numpy as np
>>> from ds_msp.models import DSPlusModel
>>> m = DSPlusModel.sample()
>>> rays, valid = m.unproject(np.array([[m.cx, m.cy]]))
>>> np.round(rays, 4)
array([[0., 0., 1.]])
Source code in ds_msp/models/dsplus.py
Extended Unified Camera Model (EUCM)¶
ds_msp.models.EUCMModel ¶
Enhanced UCM (Khomutenko et al. 2016). Satisfies CameraModel.
Source code in ds_msp/models/eucm.py
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | |
distortion
property
¶
Distortion tail [alpha, beta] (perspective blend, ellipse-radius weight).
from_dict
classmethod
¶
from_params
classmethod
¶
initialize_from_correspondences ¶
Seed fx,fy,cx,cy from K_seed; fix beta=1 and solve alpha linearly
(the UCM closed form; beta=1 reduces EUCM to UCM).
Source code in ds_msp/models/eucm.py
param_bounds
classmethod
¶
Optimizer bounds: alpha in (0, 1), beta in (0, 10].
Source code in ds_msp/models/eucm.py
project ¶
Project camera-frame points via an ellipse-radius-weighted UCM sphere.
EUCM generalizes the Unified Camera Model (UCMModel) with a second
parameter beta that reweights the radial term inside the sphere
distance, d = sqrt(beta*(x^2+y^2) + z^2), before the same
alpha-blended perspective division. This extra degree of freedom
(decoupling the radial and axial curvature of the projection surface)
is what lets EUCM fit distortion profiles a single-sphere UCM cannot.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
P
|
(ndarray, shape(..., 3))
|
Camera-frame points (meters), +Z forward. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
uv |
(ndarray, shape(..., 2))
|
Projected pixel coordinates |
valid |
(ndarray, shape(...))
|
|
References
Khomutenko, B., Garcia, G., Martinet, P. "An Enhanced Unified Camera Model for Omnidirectional Cameras." IEEE RA-L 2016.
Examples:
>>> import numpy as np
>>> from ds_msp.models import EUCMModel
>>> m = EUCMModel.sample()
>>> uv, valid = m.project(np.array([[0.0, 0.0, 1.0]]))
>>> np.round(uv, 2)
array([[949.18, 518.81]])
Source code in ds_msp/models/eucm.py
project_jacobian ¶
Project with analytic derivatives (no autodiff, no finite differences).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
P
|
(ndarray, shape(..., 3))
|
Camera-frame points (meters), +Z forward. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
uv |
(ndarray, shape(..., 2))
|
Projected pixel coordinates, identical to |
J_point |
(ndarray, shape(..., 2, 3))
|
|
J_param |
(ndarray, shape(..., 2, 6))
|
|
valid |
(ndarray, shape(...))
|
Projectability mask, identical condition to |
Examples:
>>> import numpy as np
>>> from ds_msp.models import EUCMModel
>>> m = EUCMModel.sample()
>>> uv, J_point, J_param, valid = m.project_jacobian(np.array([[0.0, 0.0, 1.0]]))
>>> J_point.shape, J_param.shape
((1, 2, 3), (1, 2, 6))
Source code in ds_msp/models/eucm.py
sample
classmethod
¶
to_dict ¶
Serialize to {"model": "eucm", "fx": ..., ..., "beta": ...}.
unproject ¶
Unproject pixels to unit bearing rays (closed form).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
uv
|
(ndarray, shape(..., 2))
|
Pixel coordinates |
required |
Returns:
| Name | Type | Description |
|---|---|---|
rays |
(ndarray, shape(..., 3))
|
Unit-norm camera-frame bearing vectors, +Z forward. |
valid |
(ndarray, shape(...))
|
|
Examples:
>>> import numpy as np
>>> from ds_msp.models import EUCMModel
>>> m = EUCMModel.sample()
>>> rays, valid = m.unproject(np.array([[m.cx, m.cy]]))
>>> np.round(rays, 4)
array([[0., 0., 1.]])
Source code in ds_msp/models/eucm.py
Kannala-Brandt (KB)¶
ds_msp.models.KannalaBrandtModel ¶
Kannala-Brandt / equidistant fisheye. Satisfies CameraModel.
K and distortion ([k1,k2,k3,k4]) plug directly into cv2.fisheye.
Source code in ds_msp/models/kb.py
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | |
distortion
property
¶
Odd-power angle-polynomial coefficients [k1, k2, k3, k4] (OpenCV order).
from_dict
classmethod
¶
from_params
classmethod
¶
Build from a flat [fx, fy, cx, cy, k1, k2, k3, k4] vector.
initialize_from_correspondences ¶
Seed fx,fy,cx,cy from K_seed; solve k1..k4 by linear least squares
(ru - theta is linear in the odd powers of theta).
Source code in ds_msp/models/kb.py
param_bounds
classmethod
¶
Optimizer bounds: each k_i in [-1, 1], focal/center wide-open.
Source code in ds_msp/models/kb.py
project ¶
Project camera-frame points via the equidistant angle-polynomial map.
Kannala-Brandt is distinct in operating on the incidence angle rather
than a sphere: it computes theta = atan2(r, z) (the angle off the
optical axis) and maps it through an odd-power polynomial
theta_d = theta + k1*theta^3 + k2*theta^5 + k3*theta^7 +
k4*theta^9, then scales the direction (x, y)/r by
theta_d / r. With k1..k4 = 0 this reduces to the ideal
equidistant fisheye r = f*theta.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
P
|
(ndarray, shape(..., 3))
|
Camera-frame points (meters), +Z forward. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
uv |
(ndarray, shape(..., 2))
|
Projected pixel coordinates |
valid |
(ndarray, shape(...))
|
|
References
Kannala, J., Brandt, S. S. "A Generic Camera Model and Calibration
Method for Conventional, Wide-Angle, and Fish-Eye Lenses." IEEE
TPAMI 2006. K and distortion plug directly into
cv2.fisheye.projectPoints.
Examples:
>>> import numpy as np
>>> from ds_msp.models import KannalaBrandtModel
>>> m = KannalaBrandtModel.sample()
>>> uv, valid = m.project(np.array([[0.0, 0.0, 1.0]]))
>>> np.round(uv, 2)
array([[320., 240.]])
Source code in ds_msp/models/kb.py
project_jacobian ¶
Project with analytic derivatives (no autodiff, no finite differences).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
P
|
(ndarray, shape(..., 3))
|
Camera-frame points (meters), +Z forward. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
uv |
(ndarray, shape(..., 2))
|
Projected pixel coordinates, identical to |
J_point |
(ndarray, shape(..., 2, 3))
|
|
J_param |
(ndarray, shape(..., 2, 8))
|
|
valid |
(ndarray, shape(...))
|
Projectability mask, identical condition to |
References
Kannala, J., Brandt, S. S. IEEE TPAMI 2006 (closed-form Jacobian
derived from the forward map; verified here by finite-difference
check, relative error <= 1e-6, see pytest -m jac).
Examples:
>>> import numpy as np
>>> from ds_msp.models import KannalaBrandtModel
>>> m = KannalaBrandtModel.sample()
>>> uv, J_point, J_param, valid = m.project_jacobian(np.array([[0.0, 0.0, 1.0]]))
>>> J_point.shape, J_param.shape
((1, 2, 3), (1, 2, 8))
Source code in ds_msp/models/kb.py
sample
classmethod
¶
Realistic instance for contract testing (a narrower-FOV KB lens).
to_dict ¶
Serialize to {"model": "kb", "fx": ..., ..., "k4": ...}.
unproject ¶
Unproject pixels to unit bearing rays via Newton-Raphson.
Inverts theta_d(theta) = ru for theta with 10 fixed Newton
iterations (no closed form exists for a degree-9 polynomial), then
builds the ray from (sin(theta), cos(theta)) and the pixel's
angular direction. See ds_msp.models.kb_math.kb_unproject.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
uv
|
(ndarray, shape(..., 2))
|
Pixel coordinates |
required |
Returns:
| Name | Type | Description |
|---|---|---|
rays |
(ndarray, shape(..., 3))
|
Unit-norm camera-frame bearing vectors, +Z forward. |
valid |
(ndarray, shape(...))
|
|
Examples:
>>> import numpy as np
>>> from ds_msp.models import KannalaBrandtModel
>>> m = KannalaBrandtModel.sample()
>>> rays, valid = m.unproject(np.array([[m.cx, m.cy]]))
>>> np.round(rays, 4)
array([[0., 0., 1.]])
Source code in ds_msp/models/kb.py
OCam / Scaramuzza¶
ds_msp.models.OCamModel ¶
Scaramuzza polynomial omni-camera. Satisfies CameraModel.
Parameters: centre (cx, cy), affine (c, d, e), world polynomial (a0..a4).
Has no native fx/fy; K exposes a pinhole-equivalent focal ~ |a0|.
Source code in ds_msp/models/ocam.py
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | |
K
property
¶
Pinhole-equivalent 3x3 intrinsic matrix; focal is |a0| (OCam has no native fx/fy).
distortion
property
¶
Distortion tail [c, d, e, a0, a1, a2, a3, a4] (affine + world polynomial).
from_dict
classmethod
¶
from_params
classmethod
¶
initialize_from_correspondences ¶
Seed cx,cy from K_seed; fix the affine to identity and solve
a0..a4 by linear least squares against the observed world-polynomial values.
Source code in ds_msp/models/ocam.py
param_bounds
classmethod
¶
Optimizer bounds: c in (0, 10], d, e in [-1, 1], a0 < 0 (forward-facing focal sign).
Source code in ds_msp/models/ocam.py
project ¶
Project camera-frame points via the Scaramuzza world polynomial.
OCam has no closed-form projection: instead of a distortion formula
applied to a normalized ray, it solves for the radial image distance
rho satisfying w(rho) + m*rho = 0 by Newton iteration, where
w is a degree-4 "world" polynomial in rho / R_REF and
m = Z / sqrt(X^2 + Y^2). The 2x2 affine stretch [[c, d], [e,
1]] is then applied to model sensor non-squareness / skew before
translation by the principal point. This general polynomial radial
profile (rather than a fixed functional form) is what lets OCam fit
distortion curves other closed-form models cannot.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
P
|
(ndarray, shape(..., 3))
|
Camera-frame points (meters), +Z forward. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
uv |
(ndarray, shape(..., 2))
|
Projected pixel coordinates |
valid |
(ndarray, shape(...))
|
|
References
Scaramuzza, D., Martinelli, A., Siegwart, R. "A Toolbox for Easily Calibrating Omnidirectional Cameras." IROS 2006.
Examples:
>>> import numpy as np
>>> from ds_msp.models import OCamModel
>>> m = OCamModel.sample()
>>> uv, valid = m.project(np.array([[0.0, 0.0, 1.0]]))
>>> np.round(uv, 2)
array([[320., 240.]])
Source code in ds_msp/models/ocam.py
project_jacobian ¶
Project with analytic derivatives via the implicit function theorem.
rho is defined implicitly by w(rho) + m*rho = 0; its
derivatives w.r.t. both the 3D point and the polynomial coefficients
are obtained without differentiating through the Newton loop, via
the implicit function theorem (drho = -dF / (dF/drho)).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
P
|
(ndarray, shape(..., 3))
|
Camera-frame points (meters), +Z forward. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
uv |
(ndarray, shape(..., 2))
|
Projected pixel coordinates, identical to |
J_point |
(ndarray, shape(..., 2, 3))
|
|
J_param |
(ndarray, shape(..., 2, 10))
|
|
valid |
(ndarray, shape(...))
|
Projectability mask, identical condition to |
References
Scaramuzza, D., Martinelli, A., Siegwart, R. IROS 2006 (Jacobian is
this repo's own derivation via the implicit function theorem;
verified by finite-difference check, relative error <= 1e-6, see
pytest -m jac).
Examples:
>>> import numpy as np
>>> from ds_msp.models import OCamModel
>>> m = OCamModel.sample()
>>> uv, J_point, J_param, valid = m.project_jacobian(np.array([[0.0, 0.0, 1.0]]))
>>> J_point.shape, J_param.shape
((1, 2, 3), (1, 2, 10))
Source code in ds_msp/models/ocam.py
sample
classmethod
¶
Realistic instance for contract testing (a synthetic omni-camera).
Polynomial argument is normalized by R_REF=100, so a2..a4
are O(1).
Source code in ds_msp/models/ocam.py
to_dict ¶
Serialize to {"model": "ocam", "cx": ..., ..., "a4": ...}.
unproject ¶
Unproject pixels to unit bearing rays (direct polynomial evaluation).
Inverts the affine stretch linearly, then evaluates the world
polynomial w(rho) directly (no root-finding needed in this
direction) to form ray = normalize([x, y, -w(rho)]). See
ds_msp.models.ocam_math.ocam_unproject.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
uv
|
(ndarray, shape(..., 2))
|
Pixel coordinates |
required |
Returns:
| Name | Type | Description |
|---|---|---|
rays |
(ndarray, shape(..., 3))
|
Unit-norm camera-frame bearing vectors, +Z forward. |
valid |
(ndarray, shape(...))
|
|
Examples:
>>> import numpy as np
>>> from ds_msp.models import OCamModel
>>> m = OCamModel.sample()
>>> rays, valid = m.unproject(np.array([[m.cx, m.cy]]))
>>> np.round(rays, 4)
array([[0., 0., 1.]])
Source code in ds_msp/models/ocam.py
Radial-Tangential (RadTan / OpenCV pinhole)¶
ds_msp.models.RadTanModel ¶
Pinhole with radial-tangential distortion. Satisfies CameraModel.
distortion returns [k1, k2, p1, p2, k3] (OpenCV order) for direct use
with cv2.projectPoints / cv2.undistortPoints. Narrow-FOV: only models
rays with z > 0.
Source code in ds_msp/models/radtan.py
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | |
from_dict
classmethod
¶
from_params
classmethod
¶
initialize_from_correspondences ¶
Seed fx,fy,cx,cy from K_seed; zero all distortion coefficients.
Source code in ds_msp/models/radtan.py
param_bounds
classmethod
¶
Optimizer bounds: radial/tangential terms modestly bounded, focal/center wide-open.
Source code in ds_msp/models/radtan.py
project ¶
Project camera-frame points via the classic Brown-Conrady model.
The pinhole projects onto the normalized plane (a=x/z, b=y/z)
and applies polynomial radial distortion (k1, k2, k3 on
r2=a^2+b^2) plus tangential distortion (p1, p2, modeling lens
decentering). Unlike the other 7 models in this package, RadTan does
not attempt to represent fisheye FOV: it is only valid for
z > 0 and cannot represent rays at or beyond 90° off-axis.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
P
|
(ndarray, shape(..., 3))
|
Camera-frame points (meters), +Z forward. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
uv |
(ndarray, shape(..., 2))
|
Projected pixel coordinates |
valid |
(ndarray, shape(...))
|
|
References
Brown, D. C. "Decentering Distortion of Lenses." Photogrammetric
Engineering, 1966 (tangential terms); OpenCV
distCoeffs = [k1, k2, p1, p2, k3] convention, see
cv2.projectPoints.
Examples:
>>> import numpy as np
>>> from ds_msp.models import RadTanModel
>>> m = RadTanModel.sample()
>>> uv, valid = m.project(np.array([[0.0, 0.0, 1.0]]))
>>> np.round(uv, 2)
array([[320., 240.]])
Source code in ds_msp/models/radtan.py
project_jacobian ¶
Project with analytic derivatives (no autodiff, no finite differences).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
P
|
(ndarray, shape(..., 3))
|
Camera-frame points (meters), +Z forward. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
uv |
(ndarray, shape(..., 2))
|
Projected pixel coordinates, identical to |
J_point |
(ndarray, shape(..., 2, 3))
|
|
J_param |
(ndarray, shape(..., 2, 9))
|
|
valid |
(ndarray, shape(...))
|
Projectability mask, identical condition to |
Examples:
>>> import numpy as np
>>> from ds_msp.models import RadTanModel
>>> m = RadTanModel.sample()
>>> uv, J_point, J_param, valid = m.project_jacobian(np.array([[0.0, 0.0, 1.0]]))
>>> J_point.shape, J_param.shape
((1, 2, 3), (1, 2, 9))
Source code in ds_msp/models/radtan.py
sample
classmethod
¶
Realistic instance for contract testing (a narrow-FOV pinhole lens).
to_dict ¶
Serialize to {"model": "radtan", "fx": ..., ..., "k3": ...}.
unproject ¶
Unproject pixels to unit bearing rays via fixed-point distortion inversion.
Runs 20 fixed-point iterations of the standard OpenCV-style inverse (no closed form exists for the Brown-Conrady distortion), then re-distorts the recovered normalized coordinates to check consistency with the input.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
uv
|
(ndarray, shape(..., 2))
|
Pixel coordinates |
required |
Returns:
| Name | Type | Description |
|---|---|---|
rays |
(ndarray, shape(..., 3))
|
Unit-norm camera-frame bearing vectors, +Z forward. |
valid |
(ndarray, shape(...))
|
|
Examples:
>>> import numpy as np
>>> from ds_msp.models import RadTanModel
>>> m = RadTanModel.sample()
>>> rays, valid = m.unproject(np.array([[m.cx, m.cy]]))
>>> np.round(rays, 4)
array([[0., 0., 1.]])
Source code in ds_msp/models/radtan.py
Unified Camera Model (UCM)¶
ds_msp.models.UCMModel ¶
Unified Camera Model (single sphere). Satisfies CameraModel.
Source code in ds_msp/models/ucm.py
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | |
distortion
property
¶
Distortion tail [alpha] (perspective blend between sphere and plane).
from_dict
classmethod
¶
from_params
classmethod
¶
initialize_from_correspondences ¶
Seed fx,fy,cx,cy from K_seed; solve alpha by linear least squares
from unit-ray/pixel correspondences.
Source code in ds_msp/models/ucm.py
param_bounds
classmethod
¶
Optimizer bounds: alpha in (0, 1), focal/center wide-open.
Source code in ds_msp/models/ucm.py
project ¶
Project camera-frame points via the single unit-sphere composition.
UCM re-centers the point onto a single unit sphere (radius
d = sqrt(x^2+y^2+z^2)), then perspective-divides from a point
blended between the sphere's surface and the pinhole plane by
alpha: den = alpha*d + (1-alpha)*z. It is the one-sphere,
one-parameter special case of DoubleSphereModel (xi=0).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
P
|
(ndarray, shape(..., 3))
|
Camera-frame points (meters), +Z forward. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
uv |
(ndarray, shape(..., 2))
|
Projected pixel coordinates |
valid |
(ndarray, shape(...))
|
|
References
Geyer, C., Daniilidis, K. "A Unifying Theory for Central Panoramic Systems." ECCV 2000; Mei, C., Rives, P. "Single View Point Omnidirectional Camera Calibration from Planar Grids." ICRA 2007.
Examples:
>>> import numpy as np
>>> from ds_msp.models import UCMModel
>>> m = UCMModel.sample()
>>> uv, valid = m.project(np.array([[0.0, 0.0, 1.0]]))
>>> np.round(uv, 2)
array([[949.18, 518.81]])
Source code in ds_msp/models/ucm.py
project_jacobian ¶
Project with analytic derivatives (no autodiff, no finite differences).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
P
|
(ndarray, shape(..., 3))
|
Camera-frame points (meters), +Z forward. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
uv |
(ndarray, shape(..., 2))
|
Projected pixel coordinates, identical to |
J_point |
(ndarray, shape(..., 2, 3))
|
|
J_param |
(ndarray, shape(..., 2, 5))
|
|
valid |
(ndarray, shape(...))
|
Projectability mask, identical condition to |
References
Geyer, C., Daniilidis, K. ECCV 2000; Mei, C., Rives, P. ICRA 2007
(closed-form Jacobian derived from the forward map; verified here by
finite-difference check, relative error <= 1e-6, see pytest -m jac).
Examples:
>>> import numpy as np
>>> from ds_msp.models import UCMModel
>>> m = UCMModel.sample()
>>> uv, J_point, J_param, valid = m.project_jacobian(np.array([[0.0, 0.0, 1.0]]))
>>> J_point.shape, J_param.shape
((1, 2, 3), (1, 2, 5))
Source code in ds_msp/models/ucm.py
sample
classmethod
¶
to_dict ¶
Serialize to {"model": "ucm", "fx": ..., ..., "alpha": ...}.
unproject ¶
Unproject pixels to unit bearing rays (closed form).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
uv
|
(ndarray, shape(..., 2))
|
Pixel coordinates |
required |
Returns:
| Name | Type | Description |
|---|---|---|
rays |
(ndarray, shape(..., 3))
|
Unit-norm camera-frame bearing vectors, +Z forward. |
valid |
(ndarray, shape(...))
|
|
Examples:
>>> import numpy as np
>>> from ds_msp.models import UCMModel
>>> m = UCMModel.sample()
>>> rays, valid = m.unproject(np.array([[m.cx, m.cy]]))
>>> np.round(rays, 4)
array([[0., 0., 1.]])