camera-client 0.3.0__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {camera_client-0.3.0/camera_client.egg-info → camera_client-0.3.2}/PKG-INFO +20 -12
- {camera_client-0.3.0 → camera_client-0.3.2}/README.md +19 -11
- camera_client-0.3.2/camera_client/__init__.py +5 -0
- {camera_client-0.3.0 → camera_client-0.3.2}/camera_client/camera_network.py +55 -25
- {camera_client-0.3.0 → camera_client-0.3.2}/camera_client/error_model.py +6 -0
- {camera_client-0.3.0 → camera_client-0.3.2/camera_client.egg-info}/PKG-INFO +20 -12
- {camera_client-0.3.0 → camera_client-0.3.2}/pyproject.toml +1 -1
- camera_client-0.3.0/camera_client/__init__.py +0 -5
- {camera_client-0.3.0 → camera_client-0.3.2}/LICENSE +0 -0
- {camera_client-0.3.0 → camera_client-0.3.2}/MANIFEST.in +0 -0
- {camera_client-0.3.0 → camera_client-0.3.2}/camera_client/__main__.py +0 -0
- {camera_client-0.3.0 → camera_client-0.3.2}/camera_client/client.py +0 -0
- {camera_client-0.3.0 → camera_client-0.3.2}/camera_client/loading.py +0 -0
- {camera_client-0.3.0 → camera_client-0.3.2}/camera_client/script.py +0 -0
- {camera_client-0.3.0 → camera_client-0.3.2}/camera_client/triangulation.py +0 -0
- {camera_client-0.3.0 → camera_client-0.3.2}/camera_client.egg-info/SOURCES.txt +0 -0
- {camera_client-0.3.0 → camera_client-0.3.2}/camera_client.egg-info/dependency_links.txt +0 -0
- {camera_client-0.3.0 → camera_client-0.3.2}/camera_client.egg-info/entry_points.txt +0 -0
- {camera_client-0.3.0 → camera_client-0.3.2}/camera_client.egg-info/requires.txt +0 -0
- {camera_client-0.3.0 → camera_client-0.3.2}/camera_client.egg-info/top_level.txt +0 -0
- {camera_client-0.3.0 → camera_client-0.3.2}/requirements.txt +0 -0
- {camera_client-0.3.0 → camera_client-0.3.2}/setup.cfg +0 -0
- {camera_client-0.3.0 → camera_client-0.3.2}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: camera-client
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Python SDK for camera calibration and projection transformations - handle lens distortion, coordinate transformations, and 3D ray casting with symbolic expressions.
|
|
5
5
|
Author-email: Alexander Abramov <extremal.ru@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -133,9 +133,9 @@ net = CameraNetwork(cameras)
|
|
|
133
133
|
|
|
134
134
|
### Spatial covariance
|
|
135
135
|
|
|
136
|
-
`get_covariance` computes 3x3 spatial covariance matrices for 3D points
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
`get_covariance` computes 3x3 spatial covariance matrices for 3D points —
|
|
137
|
+
both per-camera and fused across all visible cameras in a single call.
|
|
138
|
+
Returns a `NetworkCovariance` object.
|
|
139
139
|
|
|
140
140
|
```python
|
|
141
141
|
points = np.array([
|
|
@@ -143,15 +143,15 @@ points = np.array([
|
|
|
143
143
|
[18.0, 6.0, 1.5],
|
|
144
144
|
])
|
|
145
145
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
#
|
|
146
|
+
result = net.get_covariance(points, detection_sigma=0.01)
|
|
147
|
+
|
|
148
|
+
# Per-camera covariance (None if camera doesn't see the point)
|
|
149
|
+
cov_cam = result[1177][0] # camera 1177, point 0
|
|
149
150
|
|
|
150
151
|
# Fused covariance from all visible cameras (information fusion)
|
|
151
|
-
|
|
152
|
-
# covs_fused[i] is (3, 3) fused covariance, or None if not visible to any camera
|
|
152
|
+
cov_fused = result.fused[0] # fused, point 0 (or None if no camera sees it)
|
|
153
153
|
|
|
154
|
-
for i, cov in enumerate(
|
|
154
|
+
for i, cov in enumerate(result.fused):
|
|
155
155
|
if cov is not None:
|
|
156
156
|
stds = np.sqrt(np.linalg.eigvalsh(cov))
|
|
157
157
|
print(f"Point {i}: σ = {stds[0]:.3f}m, {stds[1]:.3f}m, {stds[2]:.3f}m")
|
|
@@ -236,12 +236,20 @@ Out-of-bounds points return NaN. Height `h` can be a scalar or per-point (N,) ar
|
|
|
236
236
|
| Method | Description |
|
|
237
237
|
|--------|-------------|
|
|
238
238
|
| `CameraNetwork(cameras)` | Create network from list of `CameraProjection` instances |
|
|
239
|
-
| `get_covariance(points, ...)` |
|
|
240
|
-
| `get_covariance(points, camera_id=id, ...)` | Per-camera 3x3 covariance (no fusion, no visibility check) |
|
|
239
|
+
| `get_covariance(points, ...)` | Returns `NetworkCovariance` with per-camera and fused 3x3 covariances |
|
|
241
240
|
| `triangulate(observations, ...)` | 3D point + covariance from `{camera_id: src_point}` observations |
|
|
242
241
|
|
|
243
242
|
Common parameters: `detection_sigma` (float), `sigma_binding` (float), `use_efov` (bool), `n_sigma` (float).
|
|
244
243
|
|
|
244
|
+
### `NetworkCovariance`
|
|
245
|
+
|
|
246
|
+
| Access | Description |
|
|
247
|
+
|--------|-------------|
|
|
248
|
+
| `result[camera_id]` | List of N per-camera covariances (3x3 or None) |
|
|
249
|
+
| `result.fused` | List of N fused covariances (3x3 or None) |
|
|
250
|
+
| `result.camera_ids` | List of all camera IDs in the network |
|
|
251
|
+
| `result.visible_camera_ids(i=0)` | List of camera IDs that see point i |
|
|
252
|
+
|
|
245
253
|
### `triangulation` module
|
|
246
254
|
|
|
247
255
|
| Function | Description |
|
|
@@ -103,9 +103,9 @@ net = CameraNetwork(cameras)
|
|
|
103
103
|
|
|
104
104
|
### Spatial covariance
|
|
105
105
|
|
|
106
|
-
`get_covariance` computes 3x3 spatial covariance matrices for 3D points
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
`get_covariance` computes 3x3 spatial covariance matrices for 3D points —
|
|
107
|
+
both per-camera and fused across all visible cameras in a single call.
|
|
108
|
+
Returns a `NetworkCovariance` object.
|
|
109
109
|
|
|
110
110
|
```python
|
|
111
111
|
points = np.array([
|
|
@@ -113,15 +113,15 @@ points = np.array([
|
|
|
113
113
|
[18.0, 6.0, 1.5],
|
|
114
114
|
])
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
#
|
|
116
|
+
result = net.get_covariance(points, detection_sigma=0.01)
|
|
117
|
+
|
|
118
|
+
# Per-camera covariance (None if camera doesn't see the point)
|
|
119
|
+
cov_cam = result[1177][0] # camera 1177, point 0
|
|
119
120
|
|
|
120
121
|
# Fused covariance from all visible cameras (information fusion)
|
|
121
|
-
|
|
122
|
-
# covs_fused[i] is (3, 3) fused covariance, or None if not visible to any camera
|
|
122
|
+
cov_fused = result.fused[0] # fused, point 0 (or None if no camera sees it)
|
|
123
123
|
|
|
124
|
-
for i, cov in enumerate(
|
|
124
|
+
for i, cov in enumerate(result.fused):
|
|
125
125
|
if cov is not None:
|
|
126
126
|
stds = np.sqrt(np.linalg.eigvalsh(cov))
|
|
127
127
|
print(f"Point {i}: σ = {stds[0]:.3f}m, {stds[1]:.3f}m, {stds[2]:.3f}m")
|
|
@@ -206,12 +206,20 @@ Out-of-bounds points return NaN. Height `h` can be a scalar or per-point (N,) ar
|
|
|
206
206
|
| Method | Description |
|
|
207
207
|
|--------|-------------|
|
|
208
208
|
| `CameraNetwork(cameras)` | Create network from list of `CameraProjection` instances |
|
|
209
|
-
| `get_covariance(points, ...)` |
|
|
210
|
-
| `get_covariance(points, camera_id=id, ...)` | Per-camera 3x3 covariance (no fusion, no visibility check) |
|
|
209
|
+
| `get_covariance(points, ...)` | Returns `NetworkCovariance` with per-camera and fused 3x3 covariances |
|
|
211
210
|
| `triangulate(observations, ...)` | 3D point + covariance from `{camera_id: src_point}` observations |
|
|
212
211
|
|
|
213
212
|
Common parameters: `detection_sigma` (float), `sigma_binding` (float), `use_efov` (bool), `n_sigma` (float).
|
|
214
213
|
|
|
214
|
+
### `NetworkCovariance`
|
|
215
|
+
|
|
216
|
+
| Access | Description |
|
|
217
|
+
|--------|-------------|
|
|
218
|
+
| `result[camera_id]` | List of N per-camera covariances (3x3 or None) |
|
|
219
|
+
| `result.fused` | List of N fused covariances (3x3 or None) |
|
|
220
|
+
| `result.camera_ids` | List of all camera IDs in the network |
|
|
221
|
+
| `result.visible_camera_ids(i=0)` | List of camera IDs that see point i |
|
|
222
|
+
|
|
215
223
|
### `triangulation` module
|
|
216
224
|
|
|
217
225
|
| Function | Description |
|
|
@@ -31,6 +31,37 @@ def _points_in_polygon(points_xy, polygon_xy):
|
|
|
31
31
|
return np.bitwise_xor.reduce(crosses, axis=1)
|
|
32
32
|
|
|
33
33
|
|
|
34
|
+
class NetworkCovariance:
|
|
35
|
+
"""Result of CameraNetwork.get_covariance().
|
|
36
|
+
|
|
37
|
+
Access per-camera covariance lists by camera_id:
|
|
38
|
+
result[1177] — list of N covariance matrices (or None) for camera 1177
|
|
39
|
+
|
|
40
|
+
Access fused covariance:
|
|
41
|
+
result.fused — list of N fused covariance matrices (or None)
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def __init__(self, cameras, fused):
|
|
45
|
+
self._cameras = cameras # dict {camera_id: [cov_or_none, ...]}
|
|
46
|
+
self.fused = fused # list [cov_or_none, ...]
|
|
47
|
+
|
|
48
|
+
def __getitem__(self, camera_id):
|
|
49
|
+
return self._cameras[camera_id]
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def camera_ids(self):
|
|
53
|
+
return list(self._cameras.keys())
|
|
54
|
+
|
|
55
|
+
def visible_camera_ids(self, point_index=0):
|
|
56
|
+
"""Return list of camera_ids that see the given point."""
|
|
57
|
+
return [cid for cid, covs in self._cameras.items() if covs[point_index] is not None]
|
|
58
|
+
|
|
59
|
+
def __repr__(self):
|
|
60
|
+
n = len(self.fused)
|
|
61
|
+
n_visible = sum(1 for c in self.fused if c is not None)
|
|
62
|
+
return f"NetworkCovariance(points={n}, visible={n_visible}, cameras={self.camera_ids})"
|
|
63
|
+
|
|
64
|
+
|
|
34
65
|
class CameraNetwork:
|
|
35
66
|
"""A network of cameras with spatial covariance models.
|
|
36
67
|
|
|
@@ -88,52 +119,49 @@ class CameraNetwork:
|
|
|
88
119
|
visible.append(cid)
|
|
89
120
|
return visible
|
|
90
121
|
|
|
91
|
-
def get_covariance(self, points, detection_sigma=0.0, sigma_binding=0.0,
|
|
92
|
-
|
|
93
|
-
"""Compute covariance for 3D points.
|
|
122
|
+
def get_covariance(self, points, detection_sigma=0.0, sigma_binding=0.0, use_efov=True):
|
|
123
|
+
"""Compute per-camera and fused covariance for 3D points.
|
|
94
124
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
125
|
+
Visibility is always checked:
|
|
126
|
+
- use_efov=True (default): point's xy projection must fall inside the
|
|
127
|
+
camera's ground EFOV polygon
|
|
128
|
+
- use_efov=False: point must project onto valid image area
|
|
98
129
|
|
|
99
130
|
Args:
|
|
100
131
|
points: (N, 3) array of 3D points [x, y, z]
|
|
101
132
|
detection_sigma: detection uncertainty (fraction of image width)
|
|
102
133
|
sigma_binding: spatial binding uncertainty in meters
|
|
103
134
|
use_efov: if True, use EFOV ground polygons for visibility;
|
|
104
|
-
if False, use image projection bounds
|
|
105
|
-
camera_id: if set, compute covariance from this camera only
|
|
135
|
+
if False, use image projection bounds
|
|
106
136
|
|
|
107
137
|
Returns:
|
|
108
|
-
|
|
109
|
-
|
|
138
|
+
NetworkCovariance with:
|
|
139
|
+
result[camera_id] — list of N per-camera covariances (or None)
|
|
140
|
+
result.fused — list of N fused covariances (or None)
|
|
110
141
|
"""
|
|
111
142
|
points = np.asarray(points, dtype=np.float64)
|
|
112
143
|
if points.ndim != 2 or points.shape[1] != 3:
|
|
113
144
|
raise ValueError(f"Expected (N, 3) array, got shape {points.shape}")
|
|
114
145
|
|
|
115
146
|
N = len(points)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if camera_id is not None:
|
|
119
|
-
cov_model = self.covariances[camera_id]
|
|
120
|
-
for i in range(N):
|
|
121
|
-
result[i] = cov_model.get_covariance(points[i], detection_sigma, sigma_binding)
|
|
122
|
-
return result
|
|
147
|
+
per_camera = {cid: [None] * N for cid in self.cameras}
|
|
148
|
+
fused = [None] * N
|
|
123
149
|
|
|
124
150
|
for i in range(N):
|
|
125
151
|
p = points[i]
|
|
126
152
|
visible_ids = self._visible_camera_ids(p, use_efov)
|
|
127
|
-
if not visible_ids:
|
|
128
|
-
continue
|
|
129
153
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
154
|
+
covs_for_fusion = []
|
|
155
|
+
for cid in visible_ids:
|
|
156
|
+
cov = self.covariances[cid].get_covariance(p, detection_sigma, sigma_binding)
|
|
157
|
+
if cov is not None:
|
|
158
|
+
per_camera[cid][i] = cov
|
|
159
|
+
covs_for_fusion.append(cov)
|
|
160
|
+
|
|
161
|
+
if covs_for_fusion:
|
|
162
|
+
fused[i] = triangulation.fuse_covariances(covs_for_fusion)
|
|
135
163
|
|
|
136
|
-
return
|
|
164
|
+
return NetworkCovariance(per_camera, fused)
|
|
137
165
|
|
|
138
166
|
def triangulate(self, observations, detection_sigma=0.0, sigma_binding=0.0, n_sigma=3.0):
|
|
139
167
|
"""Triangulate a 3D point from observations in multiple cameras.
|
|
@@ -187,6 +215,8 @@ class CameraNetwork:
|
|
|
187
215
|
cov = self.covariances[cid].get_covariance(
|
|
188
216
|
p_on_ray, detection_sigma, sigma_binding
|
|
189
217
|
)
|
|
218
|
+
if cov is None:
|
|
219
|
+
return None
|
|
190
220
|
ray_points.append(p_on_ray)
|
|
191
221
|
ray_covs.append(cov)
|
|
192
222
|
|
|
@@ -197,6 +197,9 @@ class CameraSpatialCovariance:
|
|
|
197
197
|
p: 3D point [x, y, z]
|
|
198
198
|
detection_sigma: detection uncertainty (fraction of image width)
|
|
199
199
|
sigma_binding: spatial binding uncertainty in meters
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
(3, 3) covariance matrix, or None if the point is outside the image
|
|
200
203
|
"""
|
|
201
204
|
p = np.asarray(p, dtype=np.float64)
|
|
202
205
|
cam = self.camera
|
|
@@ -204,6 +207,9 @@ class CameraSpatialCovariance:
|
|
|
204
207
|
ctd = cam.gnd_to_ctd(p.reshape(1, 3))[0]
|
|
205
208
|
x_ctd, y_ctd = float(ctd[0]), float(ctd[1])
|
|
206
209
|
|
|
210
|
+
if not (0 <= x_ctd < cam.im_width and 0 <= y_ctd < cam.im_height):
|
|
211
|
+
return None
|
|
212
|
+
|
|
207
213
|
d = np.linalg.norm(p - self.key_point)
|
|
208
214
|
e_ray = cam.ctd_to_ray(np.array([[x_ctd, y_ctd]]))[0]
|
|
209
215
|
J = cam.ctd_to_ray_jacobian(x_ctd, y_ctd)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: camera-client
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Python SDK for camera calibration and projection transformations - handle lens distortion, coordinate transformations, and 3D ray casting with symbolic expressions.
|
|
5
5
|
Author-email: Alexander Abramov <extremal.ru@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -133,9 +133,9 @@ net = CameraNetwork(cameras)
|
|
|
133
133
|
|
|
134
134
|
### Spatial covariance
|
|
135
135
|
|
|
136
|
-
`get_covariance` computes 3x3 spatial covariance matrices for 3D points
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
`get_covariance` computes 3x3 spatial covariance matrices for 3D points —
|
|
137
|
+
both per-camera and fused across all visible cameras in a single call.
|
|
138
|
+
Returns a `NetworkCovariance` object.
|
|
139
139
|
|
|
140
140
|
```python
|
|
141
141
|
points = np.array([
|
|
@@ -143,15 +143,15 @@ points = np.array([
|
|
|
143
143
|
[18.0, 6.0, 1.5],
|
|
144
144
|
])
|
|
145
145
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
#
|
|
146
|
+
result = net.get_covariance(points, detection_sigma=0.01)
|
|
147
|
+
|
|
148
|
+
# Per-camera covariance (None if camera doesn't see the point)
|
|
149
|
+
cov_cam = result[1177][0] # camera 1177, point 0
|
|
149
150
|
|
|
150
151
|
# Fused covariance from all visible cameras (information fusion)
|
|
151
|
-
|
|
152
|
-
# covs_fused[i] is (3, 3) fused covariance, or None if not visible to any camera
|
|
152
|
+
cov_fused = result.fused[0] # fused, point 0 (or None if no camera sees it)
|
|
153
153
|
|
|
154
|
-
for i, cov in enumerate(
|
|
154
|
+
for i, cov in enumerate(result.fused):
|
|
155
155
|
if cov is not None:
|
|
156
156
|
stds = np.sqrt(np.linalg.eigvalsh(cov))
|
|
157
157
|
print(f"Point {i}: σ = {stds[0]:.3f}m, {stds[1]:.3f}m, {stds[2]:.3f}m")
|
|
@@ -236,12 +236,20 @@ Out-of-bounds points return NaN. Height `h` can be a scalar or per-point (N,) ar
|
|
|
236
236
|
| Method | Description |
|
|
237
237
|
|--------|-------------|
|
|
238
238
|
| `CameraNetwork(cameras)` | Create network from list of `CameraProjection` instances |
|
|
239
|
-
| `get_covariance(points, ...)` |
|
|
240
|
-
| `get_covariance(points, camera_id=id, ...)` | Per-camera 3x3 covariance (no fusion, no visibility check) |
|
|
239
|
+
| `get_covariance(points, ...)` | Returns `NetworkCovariance` with per-camera and fused 3x3 covariances |
|
|
241
240
|
| `triangulate(observations, ...)` | 3D point + covariance from `{camera_id: src_point}` observations |
|
|
242
241
|
|
|
243
242
|
Common parameters: `detection_sigma` (float), `sigma_binding` (float), `use_efov` (bool), `n_sigma` (float).
|
|
244
243
|
|
|
244
|
+
### `NetworkCovariance`
|
|
245
|
+
|
|
246
|
+
| Access | Description |
|
|
247
|
+
|--------|-------------|
|
|
248
|
+
| `result[camera_id]` | List of N per-camera covariances (3x3 or None) |
|
|
249
|
+
| `result.fused` | List of N fused covariances (3x3 or None) |
|
|
250
|
+
| `result.camera_ids` | List of all camera IDs in the network |
|
|
251
|
+
| `result.visible_camera_ids(i=0)` | List of camera IDs that see point i |
|
|
252
|
+
|
|
245
253
|
### `triangulation` module
|
|
246
254
|
|
|
247
255
|
| Function | Description |
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "camera-client"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.2"
|
|
8
8
|
description = "Python SDK for camera calibration and projection transformations - handle lens distortion, coordinate transformations, and 3D ray casting with symbolic expressions."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.7"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|