# Python API Usage The `uLib` Python package is split into two sub-modules mirroring the C++ library: | Sub-module | Contents | |---|---| | `uLib.Core` | Low-level utilities: `Object`, `Timer`, `Options`, `TypeRegister` | | `uLib.Math` | Geometry, grids, voxel images, ray-tracing, image filters | ```python import uLib # Sub-modules are accessible as attributes uLib.Core # core utilities uLib.Math # mathematical structures ``` --- ## uLib.Core ### Object Base class for uLib objects; exposed to Python for type-hierarchy purposes. ```python obj = uLib.Core.Object() copy = obj.DeepCopy() ``` ### Timer Precision wall-clock timer. ```python import time timer = uLib.Core.Timer() timer.Start() time.sleep(0.5) elapsed = timer.StopWatch() # returns elapsed seconds as float print(f"Elapsed: {elapsed:.3f} s") ``` ### Options Wraps Boost.ProgramOptions for INI-style configuration files. ```python opt = uLib.Core.Options("My Program") opt.parse_config_file("config.ini") # load settings n = opt.count("my_key") # check if key exists opt.save_config_file("out.ini") ``` --- ## uLib.Math – Linear Algebra The math module exposes Eigen3 vectors and matrices as well-typed Python objects with NumPy interoperability. ### Fixed-size Vectors ```python import numpy as np import uLib # Construct from list v3 = uLib.Math.Vector3f([1.0, 2.0, 3.0]) print(v3[0], v3[1], v3[2]) # 1.0 2.0 3.0 # Construct from NumPy array arr = np.array([4.0, 5.0, 6.0], dtype=np.float32) v3b = uLib.Math.Vector3f(arr) # Zero-initialise v4d = uLib.Math.Vector4d() # all zeros # Available types # Vector1f / 2f / 3f / 4f (float32) # Vector1d / 2d / 3d / 4d (float64) # Vector1i / 2i / 3i / 4i (int32) ``` ### Fixed-size Matrices ```python # 2-by-2 float matrix m2f = uLib.Math.Matrix2f() m2f[0, 0] = 1; m2f[0, 1] = 2 m2f[1, 0] = 3; m2f[1, 1] = 4 # From list (row-major) m4f = uLib.Math.Matrix4f([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]) # From NumPy (2-D array) mat = np.eye(3, dtype=np.float32) m3f = uLib.Math.Matrix3f(mat) # Dynamic matrices mXf = uLib.Math.MatrixXf(4, 4) # 4×4 float, zeros ``` ### Homogeneous Types ```python # HPoint3f – a 3-D point in homogeneous coordinates (w = 1) p = uLib.Math.HPoint3f(1.0, 2.0, 3.0) # HVector3f – a free vector (w = 0) v = uLib.Math.HVector3f(0.0, 1.0, 0.0) # HLine3f – a parametric ray line = uLib.Math.HLine3f() line.origin = uLib.Math.HPoint3f(0, 0, 0) line.direction = uLib.Math.HVector3f(0, 0, 1) ``` --- ## uLib.Math – Transforms and Geometry ### AffineTransform A rigid-body / affine transform stored as a 4×4 matrix. ```python tf = uLib.Math.AffineTransform() tf.SetPosition([1.0, 0.0, 0.0]) # translate tf.Translate([0.0, 1.0, 0.0]) # cumulative translate tf.Scale([2.0, 2.0, 2.0]) # uniform scale tf.Rotate(uLib.Math.Vector3f([0, 0, 3.14159])) # Euler angles (rad) mat4 = tf.GetWorldMatrix() # 4×4 matrix pos = tf.GetPosition() # Vector3f ``` ### Geometry Inherits `AffineTransform`; converts points between world and local frames. ```python geo = uLib.Math.Geometry() geo.SetPosition([1.0, 1.0, 1.0]) world_pt = uLib.Math.Vector4f([2.0, 3.0, 2.0, 1.0]) local_pt = geo.GetLocalPoint(world_pt) back = geo.GetWorldPoint(local_pt) # back ≈ [2, 3, 2, 1] ``` ### ContainerBox An axis-aligned bounding box with an associated transform. ```python box = uLib.Math.ContainerBox() box.SetOrigin([-1.0, -1.0, -1.0]) box.SetSize([2.0, 2.0, 2.0]) print(box.GetSize()) # [2, 2, 2] ``` --- ## uLib.Math – Structured Grids ### StructuredGrid (3-D) A 3-D voxel grid (origin, spacing, and integer dimensions). ```python dims = uLib.Math.Vector3i([10, 10, 10]) grid = uLib.Math.StructuredGrid(dims) grid.SetSpacing([1.0, 1.0, 1.0]) grid.SetOrigin([0.0, 0.0, 0.0]) print(grid.GetSpacing()) # [1, 1, 1] print(grid.IsInsideBounds([5, 5, 5, 1])) # True idx = grid.Find([2.5, 2.5, 2.5]) # returns grid cell index ``` ### Structured2DGrid / Structured4DGrid ```python grid2d = uLib.Math.Structured2DGrid() grid2d.SetDims([100, 100]) grid2d.SetPhysicalSpace([0, 0], [1, 1]) print(grid2d.GetSpacing()) ``` --- ## uLib.Math – VoxImage `VoxImage` is a 3-D voxel volume where each cell stores a `Voxel` ( `.Value` + `.Count`). ```python dims = uLib.Math.Vector3i([20, 20, 20]) img = uLib.Math.VoxImage(dims) img.SetSpacing([0.5, 0.5, 0.5]) # Access by linear index img.SetValue(0, 42.0) print(img.GetValue(0)) # 42.0 # Access by 3-D index img.SetValue(uLib.Math.Vector3i([1, 1, 1]), 7.5) print(img.GetValue(uLib.Math.Vector3i([1, 1, 1]))) # 7.5 # Clipping / masking helpers cropped = img.clipImage(uLib.Math.Vector3i([2, 2, 2]), uLib.Math.Vector3i([18, 18, 18])) masked = img.maskImage(0.0, 100.0, 0.0) # mask outside [0, 100] # I/O img.ExportToVti("output.vti") img.ImportFromVti("output.vti") ``` ### Voxel (element type) ```python vox = uLib.Math.Voxel() vox.Value = 1.5 vox.Count = 3 data = img.Data() # returns the underlying Vector_Voxel vox0 = data[0] print(vox0.Value, vox0.Count) ``` --- ## uLib.Math – VoxRaytracer Performs ray-tracing through a `StructuredGrid` and returns per-voxel chord lengths. ```python import numpy as np import uLib grid = uLib.Math.StructuredGrid([10, 10, 10]) grid.SetSpacing([1.0, 1.0, 1.0]) grid.SetOrigin([0.0, 0.0, 0.0]) rt = uLib.Math.VoxRaytracer(grid) # Trace a ray between two homogeneous points (x, y, z, w=1) p1 = np.array([0.5, 0.5, -1.0, 1.0], dtype=np.float32) p2 = np.array([0.5, 0.5, 11.0, 1.0], dtype=np.float32) result = rt.TraceBetweenPoints(p1, p2) print("Voxels crossed:", result.Count()) print("Total length :", result.TotalLength()) elements = result.Data() for i in range(result.Count()): print(f" vox_id={elements[i].vox_id} L={elements[i].L:.4f}") ``` --- ## uLib.Math – Image Filters All filters share the same interface: construct with a kernel size, attach a `VoxImage`, optionally set parameters, then call `.Run()`. ```python import uLib dims = uLib.Math.Vector3i([10, 10, 10]) img = uLib.Math.VoxImage(dims) for i in range(10**3): img.SetValue(i, float(i)) kernel_dims = uLib.Math.Vector3i([3, 3, 3]) ``` ### Linear (Gaussian / Box) Filter ```python filt = uLib.Math.VoxFilterAlgorithmLinear(kernel_dims) filt.SetImage(img) filt.SetKernelNumericXZY([1.0] * 27) # uniform box kernel, length = product of dims filt.Run() ``` ### ABTrim Filter Applies alpha-beta trimming to remove outliers before averaging. ```python filt = uLib.Math.VoxFilterAlgorithmAbtrim(kernel_dims) filt.SetImage(img) filt.SetKernelNumericXZY([1.0] * 27) filt.SetABTrim(2, 2) # trim 2 low and 2 high values filt.Run() ``` ### Bilateral Filter Edge-preserving smoothing controlled by a spatial sigma (from the kernel shape) and an intensity sigma. ```python filt = uLib.Math.VoxFilterAlgorithmBilateral(kernel_dims) filt.SetImage(img) filt.SetKernelNumericXZY([1.0] * 27) filt.SetIntensitySigma(0.3) filt.Run() ``` ### Threshold Filter Zeros voxels below a threshold. ```python filt = uLib.Math.VoxFilterAlgorithmThreshold(kernel_dims) filt.SetImage(img) filt.SetKernelNumericXZY([1.0] * 27) filt.SetThreshold(0.5) filt.Run() ``` ### Median Filter ```python filt = uLib.Math.VoxFilterAlgorithmMedian(kernel_dims) filt.SetImage(img) filt.SetKernelNumericXZY([1.0] * 27) filt.Run() ``` --- ## uLib.Math – Accumulators Accumulators collect scalar samples and return a summary statistic. ```python # Arithmetic mean acc = uLib.Math.Accumulator_Mean_f() acc(10.0) acc(20.0) mean = acc() # 15.0 # Alpha-beta trimmed mean acc2 = uLib.Math.Accumulator_ABTrim_f() acc2.SetABTrim(0.1, 0.1) # trim bottom 10 % and top 10 % acc2 += 1.0 acc2 += 9999.0 # outlier acc2 += 5.0 result = acc2() # trimmed mean ≈ 3.0 ``` --- ## Dynamic Vectors (`uLib.Math.Vector_*`) Typed dynamic arrays backed by `uLib::Vector` with optional CUDA memory management. ```python # Integer vector vi = uLib.Math.Vector_i() vi.append(1); vi.append(2); vi.append(3) print(len(vi), vi[0]) # Float vector with CUDA management vf = uLib.Math.Vector_f() vf.append(1.5) vf.MoveToVRAM() # copy to GPU (no-op when CUDA is absent) vf.MoveToRAM() # copy back to CPU # Other types: Vector_ui, Vector_l, Vector_ul, Vector_d # Compound element types: Vector_Vector3f, Vector_Vector4f, Vector_Voxel … ```