CTPv 0.1.0__py3-none-any.whl
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.
- CTPv/Camera/Intrinsics.py +205 -0
- CTPv/Camera/__init__.py +0 -0
- CTPv/Plucker/Line.py +526 -0
- CTPv/Plucker/__init__.py +0 -0
- CTPv/Transformation/TransformationMatrix.py +381 -0
- CTPv/Transformation/__init__.py +0 -0
- CTPv/__init__.py +0 -0
- ctpv-0.1.0.dist-info/METADATA +474 -0
- ctpv-0.1.0.dist-info/RECORD +12 -0
- ctpv-0.1.0.dist-info/WHEEL +5 -0
- ctpv-0.1.0.dist-info/licenses/LICENSE +7 -0
- ctpv-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,474 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: CTPv
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: A toolbox of camera, Plücker, and transformation utilities
|
5
|
+
Author: Rhys Evans & Seppe Sels
|
6
|
+
Author-email: Rhys Evans & Seppe Sels <rhys.evans@uantwerpen.be>
|
7
|
+
License: MIT
|
8
|
+
Requires-Python: >=3.10
|
9
|
+
Description-Content-Type: text/markdown
|
10
|
+
License-File: LICENSE
|
11
|
+
Requires-Dist: numpy
|
12
|
+
Requires-Dist: matplotlib
|
13
|
+
Requires-Dist: scipy
|
14
|
+
Requires-Dist: scikit-learn
|
15
|
+
Requires-Dist: open3d
|
16
|
+
Dynamic: author
|
17
|
+
Dynamic: license-file
|
18
|
+
Dynamic: requires-python
|
19
|
+
|
20
|
+
**core\_toolbox\_python**
|
21
|
+
A lightweight Python toolbox providing utilities for camera intrinsics, Plücker‐line representations, and 3D transformation matrices. This package is organized into three submodules:
|
22
|
+
|
23
|
+
* **Camera.Intrinsics**: Classes for intrinsic camera matrices (Matlab/OpenCV conventions), radial distortion, ray generation, and JSON serialization.
|
24
|
+
* **Plucker.Line**: A `Line` class to represent 3D lines (start/end points or Plücker coordinates), intersection computations, line fitting, and basic plotting utilities.
|
25
|
+
* **Transformation.TransformationMatrix**: A 4×4 rigid‐body transformation class with support for Euler angles (radians/degrees), quaternions, Bundler‐format I/O, JSON serialization, inversion, chaining, and plotting (matplotlib/Open3D).
|
26
|
+
|
27
|
+
---
|
28
|
+
|
29
|
+
## Table of Contents
|
30
|
+
|
31
|
+
1. [Features](#features)
|
32
|
+
2. [Requirements](#requirements)
|
33
|
+
3. [Installation](#installation)
|
34
|
+
4. [Module Overview](#module-overview)
|
35
|
+
|
36
|
+
* [Camera.Intrinsics](#cameraintrinsics)
|
37
|
+
* [Plucker.Line](#pluckerline)
|
38
|
+
* [Transformation.TransformationMatrix](#transformationtransformationmatrix)
|
39
|
+
5. [Usage Examples](#usage-examples)
|
40
|
+
6. [Development & Contributing](#development--contributing)
|
41
|
+
7. [License](#license)
|
42
|
+
|
43
|
+
---
|
44
|
+
|
45
|
+
## Features
|
46
|
+
|
47
|
+
* **Intrinsics & Distortion**
|
48
|
+
|
49
|
+
* Create and manipulate camera intrinsic matrices in both Matlab and OpenCV formats.
|
50
|
+
* Store and serialize radial‐distortion coefficients.
|
51
|
+
* Compute focal length in millimeters (if pixel size is known).
|
52
|
+
* Compute perspective (field‐of‐view) angles.
|
53
|
+
* Generate per‐pixel rays as Plücker‐line objects.
|
54
|
+
* Save/load intrinsic parameters to/from JSON.
|
55
|
+
|
56
|
+
* **Plücker‐Line Representation**
|
57
|
+
|
58
|
+
* Represent a set of 3D rays or line segments via Plücker coordinates.
|
59
|
+
* Compute shortest‐distance intersections between two sets of lines.
|
60
|
+
* Fit a line to a cloud of 3D points (including placeholder methods for RANSAC, to be implemented).
|
61
|
+
* Compute angles between two lines.
|
62
|
+
* Basic 3D plotting of lines (matplotlib).
|
63
|
+
|
64
|
+
* **Transformation Matrices**
|
65
|
+
|
66
|
+
* Encapsulate a 4×4 rigid transformation (rotation + translation).
|
67
|
+
* Get/set translation (`.T`) and rotation (`.R`) as 3×3 matrix.
|
68
|
+
* Get/set Euler angles in radians (`.angles`) or degrees (`.angles_degree`) via SciPy.
|
69
|
+
* Get/set quaternion (`.quaternion`) for the rotation.
|
70
|
+
* Apply transformation to point clouds.
|
71
|
+
* Invert transformations, chain multiple transformations with `@`.
|
72
|
+
* Save/load transformations in JSON.
|
73
|
+
* Save/load Bundler v0.3 camera entries for MeshLab (single‐camera mode).
|
74
|
+
* Plot coordinate frames in 3D (matplotlib, or Open3D if available).
|
75
|
+
|
76
|
+
---
|
77
|
+
|
78
|
+
## Requirements
|
79
|
+
|
80
|
+
* Python ≥ 3.7
|
81
|
+
* NumPy
|
82
|
+
* Matplotlib
|
83
|
+
* SciPy (especially `scipy.spatial.transform.Rotation`)
|
84
|
+
* scikit‐learn (for any future line‐fitting routines)
|
85
|
+
|
86
|
+
*(All dependencies are declared in `pyproject.toml` or `setup.py` under `dependencies`.)*
|
87
|
+
|
88
|
+
---
|
89
|
+
|
90
|
+
## Installation
|
91
|
+
|
92
|
+
1. **Clone the repository**
|
93
|
+
|
94
|
+
```bash
|
95
|
+
git clone https://github.com/yourusername/core_toolbox_python.git
|
96
|
+
cd core_toolbox_python
|
97
|
+
```
|
98
|
+
|
99
|
+
2. **Build a wheel (PEP 517)**
|
100
|
+
|
101
|
+
```bash
|
102
|
+
python -m pip install --upgrade pip
|
103
|
+
pip install build
|
104
|
+
python -m build --wheel
|
105
|
+
```
|
106
|
+
|
107
|
+
A `.whl` file will appear under `dist/`.
|
108
|
+
|
109
|
+
3. **Install from the local wheel**
|
110
|
+
|
111
|
+
```bash
|
112
|
+
pip install dist/core_toolbox_python-0.1.0-py3-none-any.whl
|
113
|
+
```
|
114
|
+
|
115
|
+
4. **Or install in editable/development mode**
|
116
|
+
|
117
|
+
```bash
|
118
|
+
pip install -e .
|
119
|
+
```
|
120
|
+
|
121
|
+
This lets you modify source code and have changes reflected immediately.
|
122
|
+
|
123
|
+
---
|
124
|
+
|
125
|
+
## Module Overview
|
126
|
+
|
127
|
+
### Camera.Intrinsics
|
128
|
+
|
129
|
+
**File**: `core_toolbox_python/Camera/Intrinsics.py`
|
130
|
+
|
131
|
+
* **Class `RadialDistortion`**
|
132
|
+
|
133
|
+
* Holds distortion coefficients `k1, k2, k3`.
|
134
|
+
* `set_from_list([k1, k2, k3])`: assign three‐element coefficient list.
|
135
|
+
|
136
|
+
* **Class `IntrinsicMatrix`**
|
137
|
+
|
138
|
+
* Attributes:
|
139
|
+
|
140
|
+
* `fx, fy, cx, cy, s` (standard pinhole‐camera parameters).
|
141
|
+
* `width, height` (image resolution).
|
142
|
+
* `pixel_size` (in millimeters, e.g. sensor pixel pitch).
|
143
|
+
* `RadialDistortion`: an instance of `RadialDistortion`.
|
144
|
+
* `.info`: optional metadata (e.g. camera/lens ID).
|
145
|
+
|
146
|
+
* **Properties**:
|
147
|
+
|
148
|
+
* `.MatlabIntrinsics` (getter/setter): 3×3 matrix in Matlab convention (⎡fx s 0; 0 fy 0; cx cy 1⎤).
|
149
|
+
* `.OpenCVIntrinsics` (getter/setter): 3×3 matrix in OpenCV convention (⎡fx 0 cx; 0 fy cy; 0 0 1⎤).
|
150
|
+
* `.focal_length_mm`: returns `(fx ⋅ pixel_size, fy ⋅ pixel_size)`.
|
151
|
+
* `.PerspectiveAngle` (getter/setter): horizontal or vertical field‐of‐view (degrees) based on `width/height` vs `fx,fy`.
|
152
|
+
|
153
|
+
* **Methods**:
|
154
|
+
|
155
|
+
* `.CameraParams2Intrinsics(CameraParams)`: load intrinsics from an external camera‐parameters object (e.g. if you have a `CameraParams.IntrinsicMatrix` & `CameraParams.ImageSize`).
|
156
|
+
* `.Intrinsics2CameraParams()`: return a dictionary `{IntrinsicMatrix: […], ImageSize: […], RadialDistortion: …}`.
|
157
|
+
* `.ScaleIntrinsics(s)`: multiply `fx, fy, cx, cy, width, height` by scale ` s`.
|
158
|
+
* `.generate_rays() → Line`: produce a `Line` object where each row corresponds to a 3D ray originating from pixel centers; uses radial‐undistortion (if defined).
|
159
|
+
* `.save_intrinsics_to_json(filename)`: write a JSON file containing OpenCV intrinsics, distortion, resolution, pixel size, and `info`.
|
160
|
+
* `.load_intrinsics_from_json(filename)`: read JSON file and populate intrinsics, distortion, `width, height, pixel_size, info`.
|
161
|
+
|
162
|
+
* **Example** (at bottom of file):
|
163
|
+
|
164
|
+
```python
|
165
|
+
if __name__ == "__main__":
|
166
|
+
I = IntrinsicMatrix()
|
167
|
+
I.info = "testCamera"
|
168
|
+
I.fx = I.fy = 1770
|
169
|
+
I.width, I.height = 1440, 1080
|
170
|
+
I.cx, I.cy = 685, 492
|
171
|
+
I.RadialDistortion.set_from_list([-0.5, 0.18, 0])
|
172
|
+
I.save_intrinsics_to_json("test.json")
|
173
|
+
rays = I.generate_rays() # Plücker‐line set
|
174
|
+
I2 = IntrinsicMatrix().load_intrinsics_from_json("test.json")
|
175
|
+
# … compute intersections, etc.
|
176
|
+
```
|
177
|
+
|
178
|
+
---
|
179
|
+
|
180
|
+
### Plucker.Line
|
181
|
+
|
182
|
+
**File**: `core_toolbox_python/Plucker/Line.py`
|
183
|
+
|
184
|
+
* **Function `intersection_between_2_lines(L1, L2)`**
|
185
|
+
|
186
|
+
* Computes closest‐point midpoints and shortest distances between each corresponding pair of rays in two `Line` objects.
|
187
|
+
* Inputs:
|
188
|
+
|
189
|
+
* `L1`, `L2`: each a `Line` instance with `Ps` (start points) and `V` (direction vectors).
|
190
|
+
* Returns:
|
191
|
+
|
192
|
+
* `Points`: an `(N, 3)` array of midpoints between ray *i* from `L1` and ray *i* from `L2`.
|
193
|
+
* `distances`: an `(N,)` array of shortest distances.
|
194
|
+
|
195
|
+
* **Class `Line`**
|
196
|
+
|
197
|
+
* **Attributes**:
|
198
|
+
|
199
|
+
* `Ps`: `(N, 3)` array of start (origin) points of each line/ray.
|
200
|
+
* `Pe`: `(N, 3)` array of end points (so direction = `Pe − Ps`).
|
201
|
+
|
202
|
+
* **Properties**:
|
203
|
+
|
204
|
+
* `.V` (getter): normalized direction vectors for each ray (`(Pe − Ps)` normalized row‐wise).
|
205
|
+
* `.V` (setter): sets `Pe = Ps + new_direction`.
|
206
|
+
* `.Plucker` (getter): concatenates direction `V` and moment `U=Ps×(Ps+V)` into a `(N,6)` array.
|
207
|
+
* `.Plucker` (setter): given a `(N,6)` array, recovers `Ps` and `V` via cross‐product inversion.
|
208
|
+
* `.Plucker2` (alternative Plücker ordering): stores `(moment = Ps×Pe ∥ direction=Pe−Ps)`.
|
209
|
+
|
210
|
+
* **Methods**:
|
211
|
+
|
212
|
+
* `.GetAngle()`: returns the angle (in degrees) between each ray and the world‐Z unit vector.
|
213
|
+
* `.TransformLines(H)`: applies a `TransformationMatrix` `H` to both `Ps` and `Pe`.
|
214
|
+
* `.plot(limits=None, colors=None, …)`: wide‐ranging helper that draws as many lines as you like in 3D (within bounds).
|
215
|
+
* `.PlotLine(colori='g', linewidth=2)`: simpler per‐line plotting (downsamples if >500 rays).
|
216
|
+
* `.FindXYZNearestLine(XYZ)`: given a single 3D point cloud `XYZ`, returns the index of the ray that is closest.
|
217
|
+
* `.FitLine(XYZ)`: placeholder for least‐squares fit to 3D points (calls `_fitline3d`).
|
218
|
+
* `.FitLineRansac(XYZ, t=10)`: placeholder for RANSAC line fit (calls `_ransac_fit_line`).
|
219
|
+
* `.NormaliseLine()`: project all line origins so that `z=0`.
|
220
|
+
* `.DistanceLinePoint(XYZ)`: shortest distance from each line to each query point in `XYZ`.
|
221
|
+
* `.Lenght()`: length of each line segment (`‖Pe−Ps‖`).
|
222
|
+
* `@staticmethod FromStartEnd(start, end)`: build a `Line` from start/end points.
|
223
|
+
* `@staticmethod FromPlucker(VU)`: build a `Line` given a `(N,6)` Plücker array.
|
224
|
+
* **Internal helpers**: `_normalize_vectors`, `_is_within_bounds`, `_downsample`, `_fitline3d`, `_ransac_fit_line`, `_homogeneous_transform`, etc. (some are stubs for future extension).
|
225
|
+
* `.AngleBetweenLines(L1, L2)`: returns angle (radians, degrees) between two `Line` objects (single‐ray version).
|
226
|
+
* `.GenerateRay(I, uv)`: generate rays passing through pixel coordinates `uv` using intrinsics `I`.
|
227
|
+
|
228
|
+
* **Example** (at bottom of file):
|
229
|
+
|
230
|
+
```python
|
231
|
+
if __name__ == "__main__":
|
232
|
+
L = Line()
|
233
|
+
L.Ps = np.array([[1,1,0]])
|
234
|
+
L.Pe = np.array([[2,1,0]])
|
235
|
+
print(L.V) # direction vector
|
236
|
+
L.PlotLine()
|
237
|
+
L2 = Line()
|
238
|
+
L2.Ps, L2.Pe = np.array([[0,0,0]]), np.array([[20,20,0]])
|
239
|
+
_, hoek = L.AngleBetweenLines(L, L2)
|
240
|
+
print("Angle between lines:", hoek)
|
241
|
+
```
|
242
|
+
|
243
|
+
---
|
244
|
+
|
245
|
+
### Transformation.TransformationMatrix
|
246
|
+
|
247
|
+
**File**: `core_toolbox_python/Transformation/TransformationMatrix.py`
|
248
|
+
|
249
|
+
* **Class `TransformationMatrix`**
|
250
|
+
|
251
|
+
* Internally stores a 4×4 homogeneous transform `self.H` (initialized to identity).
|
252
|
+
|
253
|
+
* **Attributes**:
|
254
|
+
|
255
|
+
* `.H`: 4×4 NumPy array.
|
256
|
+
* `.info`: a two‐element list of arbitrary metadata (e.g. camera ID, timestamp).
|
257
|
+
* `.units`: string indicating units (default `"mm"`).
|
258
|
+
|
259
|
+
* **Properties**:
|
260
|
+
|
261
|
+
* `.T` (getter/setter): get/set the translation vector (3×1).
|
262
|
+
* `.R` (getter/setter): get/set the 3×3 rotation submatrix.
|
263
|
+
* `.angles` (getter/setter): Euler angles in radians (XYZ convention) via `scipy.spatial.transform.Rotation`.
|
264
|
+
* `.angles_degree` (getter/setter): Euler angles in degrees.
|
265
|
+
* `.quaternion` (getter/setter): quaternion `[x, y, z, w]` representation of the rotation.
|
266
|
+
|
267
|
+
* **Methods**:
|
268
|
+
|
269
|
+
* `.transform(points)`: apply the 4×4 transform to an `(N,3)` or `(3,)` array of 3D points, returning transformed `(N,3)`.
|
270
|
+
* `.invert()`: invert the transformation in‐place, swap and invert `H`, and reverse the `info` list.
|
271
|
+
* `.save_bundler_file(output_file, intrinsics=None)`: write a Bundler v0.3‐style camera entry (single camera, zero points) to a text file—storing focal length, distortion (set to zero), rotation rows, and translation vector. If `intrinsics` is `None`, a default intrinsic matrix is used (example values).
|
272
|
+
* `.load_bundler_file(filename)`: read a Bundler file (ignore first three lines), load rotation (3×3) and translation (3×1) back into `H`.
|
273
|
+
* `.plot(scale=1.0)`: visualize this transformation as a 3D coordinate frame (matplotlib).
|
274
|
+
* `.plot_open3d(scale=1.0)`: visualize using Open3D’s `TriangleMesh.create_coordinate_frame`; requires `open3d` installed.
|
275
|
+
* `.copy()`: return a deep copy of this `TransformationMatrix`.
|
276
|
+
* `.load_from_json(filename)`: read `H`, `info`, `units` from a JSON file.
|
277
|
+
* `.save_to_json(filename)`: write `H`, `info`, `units` to JSON.
|
278
|
+
* `__matmul__(self, other)`: allow chaining two transformations `T_combined = T1 @ T2` (i.e. matrix multiply). The combined `info` is taken as `[self.info[0], other.info[-1]]` by default.
|
279
|
+
* `__repr__`: printable representation of the 4×4 matrix.
|
280
|
+
|
281
|
+
* **Example** (at bottom of file):
|
282
|
+
|
283
|
+
```python
|
284
|
+
if __name__ == "__main__":
|
285
|
+
T1 = TransformationMatrix()
|
286
|
+
T1.T = [0, 10, 0]
|
287
|
+
T1.angles_degree = [0, 30, 0]
|
288
|
+
T1.save_bundler_file("test.out")
|
289
|
+
print("T1:\n", T1)
|
290
|
+
print("Quaternion:", T1.quaternion)
|
291
|
+
T1.plot()
|
292
|
+
|
293
|
+
T2 = T1.copy()
|
294
|
+
T2.invert()
|
295
|
+
T2.plot()
|
296
|
+
T_combined = T1 @ T2
|
297
|
+
print("Combined:\n", T_combined)
|
298
|
+
```
|
299
|
+
|
300
|
+
---
|
301
|
+
|
302
|
+
## Usage Examples
|
303
|
+
|
304
|
+
Below are some minimal snippets illustrating how to import and use the package once installed.
|
305
|
+
|
306
|
+
### 1. Reading/Writing Intrinsics
|
307
|
+
|
308
|
+
```python
|
309
|
+
from core_toolbox_python.Camera.Intrinsics import IntrinsicMatrix, RadialDistortion
|
310
|
+
|
311
|
+
# Create an intrinsic matrix
|
312
|
+
I = IntrinsicMatrix()
|
313
|
+
I.fx = 1200
|
314
|
+
I.fy = 1200
|
315
|
+
I.cx = 640
|
316
|
+
I.cy = 360
|
317
|
+
I.width = 1280
|
318
|
+
I.height = 720
|
319
|
+
I.pixel_size = 0.0034 # e.g. 3.4 µm
|
320
|
+
I.RadialDistortion.set_from_list([0.01, -0.001, 0.0])
|
321
|
+
|
322
|
+
# Compute OpenCV format
|
323
|
+
K_opencv = I.OpenCVIntrinsics
|
324
|
+
print("OpenCV Intrinsics:\n", K_opencv)
|
325
|
+
|
326
|
+
# Save to JSON
|
327
|
+
I.save_intrinsics_to_json("camera_intrinsics.json")
|
328
|
+
|
329
|
+
# Load back
|
330
|
+
I2 = IntrinsicMatrix().load_intrinsics_from_json("camera_intrinsics.json")
|
331
|
+
print("Loaded fx, fy:", I2.fx, I2.fy)
|
332
|
+
```
|
333
|
+
|
334
|
+
### 2. Generating Rays & Line Intersections
|
335
|
+
|
336
|
+
```python
|
337
|
+
from core_toolbox_python.Camera.Intrinsics import IntrinsicMatrix
|
338
|
+
from core_toolbox_python.Plucker.Line import intersection_between_2_lines
|
339
|
+
|
340
|
+
# Suppose we have two camera poses, project rays, and compute their closest‐point intersections
|
341
|
+
|
342
|
+
# Camera 1 intrinsics
|
343
|
+
I1 = IntrinsicMatrix()
|
344
|
+
I1.fx = I1.fy = 1000
|
345
|
+
I1.cx, I1.cy = 320, 240
|
346
|
+
I1.width, I1.height = 640, 480
|
347
|
+
I1.pixel_size = 0.0025
|
348
|
+
# … set radial distortion if needed …
|
349
|
+
|
350
|
+
# Camera 2 intrinsics (shifted horizontally by 1 unit)
|
351
|
+
I2 = IntrinsicMatrix()
|
352
|
+
I2.fx = I2.fy = 1000
|
353
|
+
I2.cx, I2.cy = 320, 240
|
354
|
+
I2.width, I2.height = 640, 480
|
355
|
+
I2.pixel_size = 0.0025
|
356
|
+
|
357
|
+
# Generate full‐image rays from each camera (Plücker‐line sets)
|
358
|
+
rays1 = I1.generate_rays()
|
359
|
+
rays2 = I2.generate_rays()
|
360
|
+
|
361
|
+
# Compute midpoint & distances between corresponding rays
|
362
|
+
points_mid, distances = intersection_between_2_lines(rays1, rays2)
|
363
|
+
print("Mean distance between ray pairs:", distances.mean())
|
364
|
+
```
|
365
|
+
|
366
|
+
### 3. Creating & Transforming 3D Geometry
|
367
|
+
|
368
|
+
```python
|
369
|
+
from core_toolbox_python.Transformation.TransformationMatrix import TransformationMatrix
|
370
|
+
import numpy as np
|
371
|
+
|
372
|
+
# Define a transformation: translate by [1,2,3], rotate 45° about Z
|
373
|
+
T = TransformationMatrix()
|
374
|
+
T.T = [1, 2, 3]
|
375
|
+
T.angles_degree = [0, 0, 45]
|
376
|
+
|
377
|
+
# Transform a set of points
|
378
|
+
points = np.array([[0,0,0], [1,0,0], [0,1,0]])
|
379
|
+
points_transformed = T.transform(points)
|
380
|
+
print("Transformed points:\n", points_transformed)
|
381
|
+
|
382
|
+
# Inverse transform
|
383
|
+
T_inv = T.copy()
|
384
|
+
T_inv.invert()
|
385
|
+
restored = T_inv.transform(points_transformed)
|
386
|
+
print("Restored (should match original):\n", restored)
|
387
|
+
|
388
|
+
# Save to JSON
|
389
|
+
T.save_to_json("transform.json")
|
390
|
+
T2 = TransformationMatrix().load_from_json("transform.json")
|
391
|
+
|
392
|
+
# Chain transformations
|
393
|
+
T_comb = T @ T2 # (applies T first, then T2)
|
394
|
+
```
|
395
|
+
|
396
|
+
### 4. Visualization
|
397
|
+
|
398
|
+
```python
|
399
|
+
import matplotlib.pyplot as plt
|
400
|
+
from core_toolbox_python.Plucker.Line import Line
|
401
|
+
|
402
|
+
# Plotting a single ray
|
403
|
+
L = Line()
|
404
|
+
L.Ps = np.array([[0, 0, 0]])
|
405
|
+
L.Pe = np.array([[1, 1, 1]])
|
406
|
+
L.PlotLine(colori='r')
|
407
|
+
|
408
|
+
# Plot a coordinate frame
|
409
|
+
from core_toolbox_python.Transformation.TransformationMatrix import TransformationMatrix
|
410
|
+
T = TransformationMatrix()
|
411
|
+
T.T = [0, 0, 0]
|
412
|
+
T.angles_degree = [30, 45, 60]
|
413
|
+
T.plot(scale=1.0)
|
414
|
+
plt.show()
|
415
|
+
```
|
416
|
+
|
417
|
+
---
|
418
|
+
|
419
|
+
### Development & Contributing
|
420
|
+
|
421
|
+
1. **Clone & install in “editable” mode**
|
422
|
+
```bash
|
423
|
+
git clone https://github.com/yourusername/core_toolbox_python.git
|
424
|
+
cd core_toolbox_python
|
425
|
+
pip install -e .
|
426
|
+
```
|
427
|
+
|
428
|
+
2. **Make changes on a feature branch**
|
429
|
+
|
430
|
+
* Create a new branch off `main` (or `develop`).
|
431
|
+
|
432
|
+
```bash
|
433
|
+
git checkout -b feature/my_update
|
434
|
+
```
|
435
|
+
* Implement or update functionality as needed (e.g., fill in placeholder methods, add examples, fix bugs).
|
436
|
+
|
437
|
+
3. **Run tests & verify locally**
|
438
|
+
|
439
|
+
* If you add new functionality, include or update any unit tests.
|
440
|
+
* Make sure existing examples and import statements continue to work.
|
441
|
+
|
442
|
+
4. **Tag-based release workflow**
|
443
|
+
|
444
|
+
* CI is configured to build wheels **only when a Git tag is pushed**.
|
445
|
+
* Once your branch is reviewed and merged into `main`, create a new lightweight or annotated tag following semantic versioning:
|
446
|
+
|
447
|
+
```bash
|
448
|
+
git checkout main
|
449
|
+
git pull origin main
|
450
|
+
git tag -a vX.Y.Z -m "Release vX.Y.Z"
|
451
|
+
git push origin vX.Y.Z
|
452
|
+
```
|
453
|
+
* Pushing that tag will trigger the GitHub Actions workflow to build wheels for all platforms and upload them as artifacts.
|
454
|
+
|
455
|
+
5. **Submit a Pull Request**
|
456
|
+
|
457
|
+
* Push your feature branch to the remote repository.
|
458
|
+
|
459
|
+
```bash
|
460
|
+
git push origin feature/my_update
|
461
|
+
```
|
462
|
+
* Open a Pull Request against `main`, describing your changes. Once approved and merged, follow the tag‐based release step above.
|
463
|
+
|
464
|
+
6. **After a successful tag build**
|
465
|
+
|
466
|
+
* Download platform‐specific wheel artifacts from the “Artifacts” section in the GitHub Actions run.
|
467
|
+
* Optionally, publish wheels to PyPI (you can use `twine upload dist/*` after downloading and verifying).
|
468
|
+
|
469
|
+
Thank you for contributing! If you have questions or need assistance, please open an issue or reach out directly.\`\`\`
|
470
|
+
---
|
471
|
+
|
472
|
+
## License
|
473
|
+
|
474
|
+
This project is distributed under the MIT License. See [LICENSE](LICENSE) for details.
|
@@ -0,0 +1,12 @@
|
|
1
|
+
CTPv/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
CTPv/Camera/Intrinsics.py,sha256=jYjTYOJMP978KlDH-XTZg6Sy7t2ICE_74q4EM3q88eU,6369
|
3
|
+
CTPv/Camera/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
+
CTPv/Plucker/Line.py,sha256=nxDKdSgLinN_kxCpAPoR472IX3Ib9-P-eNR1kwPVMHI,16568
|
5
|
+
CTPv/Plucker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
+
CTPv/Transformation/TransformationMatrix.py,sha256=k_n2Joq7sqfAXdoaFTGw-WIOUALsOv0iJ1MWKRtlqkY,12687
|
7
|
+
CTPv/Transformation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
+
ctpv-0.1.0.dist-info/licenses/LICENSE,sha256=HBhyqBIYiZbUP-uyGVPbBdjguM7XuuEGCVnBnud3kpM,1078
|
9
|
+
ctpv-0.1.0.dist-info/METADATA,sha256=ozfEx564pTQCgZOSaHHATolDX861raOWqPqxuM2NyfI,17275
|
10
|
+
ctpv-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
11
|
+
ctpv-0.1.0.dist-info/top_level.txt,sha256=4XT7Ark0McReh1zScVddxURLS_h3KP9djFII02cqPsQ,5
|
12
|
+
ctpv-0.1.0.dist-info/RECORD,,
|
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright 2025 UAntwerp InViLab research group
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1 @@
|
|
1
|
+
CTPv
|