path
plantimager.controller.scanner.path Link
Path Generation for Plant Imaging Systems.
This module provides classes and functions for generating and manipulating 3D paths for plant imaging systems. It includes implementations for various path types such as circles, cylinders, and lines, as well as utilities for path manipulation.
Key Features: - Abstract representation of camera poses in 5D space (x, y, z, pan, tilt) - Path generation for common scanning patterns (circles, cylinders, lines) - Path manipulation and combination utilities - Support for calibration paths - Precise control over camera orientation at each path point
Usage Examples:
>>> from plantimager.controller.scanner.path import Circle, Pose
>>> # Create a circular path with 10 points
>>> center_x, center_y = 200, 200 # Center coordinates in mm
>>> height = 50 # Height in mm
>>> tilt = 0 # Camera tilt in degrees
>>> radius = 100 # Circle radius in mm
>>> n_points = 10 # Number of points in the circle
>>> circular_path = Circle(center_x, center_y, height, tilt, radius, n_points)
>>> # Access the first point in the path
>>> first_point = circular_path[0]
>>> print(f"First point: x={first_point.x}, y={first_point.y}, z={first_point.z}")
CalibrationPath Link
CalibrationPath(path, n_points_line)
Bases: Path
Creates a calibration path for the scanner.
This build two lines spanning the X & Y axes extent of the given path.
Notes
The calibration path is made of the path to calibrate, plus two linear paths, X & Y, in that order.
Takes the first PathElement
of the input path to calibrate as lines starting points
Takes the max distance to input path origin along x & y axes to create X & Y lines ending points.
Let x0, y0 & z0 be the first ElementPath
xyz position, then:
- line #1: (x0, y0, z0, max_dist(xi, x0), y0, z0)
- line #2: (x0, y0, z0, x0, max_dist(yi, y0), z0)
See Also
romiscan.tasks.colmap.use_calibrated_poses
Examples:
>>> from plantimager.controller.scanner.path import CalibrationPath
>>> from plantimager.controller.scanner.path import Circle
>>> circular_path = Circle(200, 200, 50, 0, 200, 9)
>>> n_points_line = 5
>>> calib_path = CalibrationPath(circular_path, n_points_line)
>>> calib_path
[x = 0.00, y = 200.00, z = 50.00, pan = 270.00, tilt = 0.00,
x = 0.00, y = 167.86, z = 50.00, pan = 270.00, tilt = 0.00,
x = 0.00, y = 135.72, z = 50.00, pan = 270.00, tilt = 0.00,
x = 0.00, y = 103.58, z = 50.00, pan = 270.00, tilt = 0.00,
x = 0.00, y = 71.44, z = 50.00, pan = 270.00, tilt = 0.00,
x = 0.00, y = 200.00, z = 50.00, pan = 270.00, tilt = 0.00,
x = 11.70, y = 200.00, z = 50.00, pan = 270.00, tilt = 0.00,
x = 23.40, y = 200.00, z = 50.00, pan = 270.00, tilt = 0.00,
x = 35.09, y = 200.00, z = 50.00, pan = 270.00, tilt = 0.00,
x = 46.79, y = 200.00, z = 50.00, pan = 270.00, tilt = 0.00,
x = 0.00, y = 200.00, z = 50.00, pan = 270.00, tilt = 0.00,
x = 46.79, y = 71.44, z = 50.00, pan = 310.00, tilt = 0.00,
x = 165.27, y = 3.04, z = 50.00, pan = 350.00, tilt = 0.00,
x = 300.00, y = 26.79, z = 50.00, pan = 30.00, tilt = 0.00,
x = 387.94, y = 131.60, z = 50.00, pan = 70.00, tilt = 0.00,
x = 387.94, y = 268.40, z = 50.00, pan = 110.00, tilt = 0.00,
x = 300.00, y = 373.21, z = 50.00, pan = 150.00, tilt = 0.00,
x = 165.27, y = 396.96, z = 50.00, pan = 190.00, tilt = 0.00,
x = 46.79, y = 328.56, z = 50.00, pan = 230.00, tilt = 0.00]
Parameters:
Name | Type | Description | Default |
---|---|---|---|
path
|
Path
|
A path to calibrate. |
required |
n_points_line
|
int
|
The number of points per line. |
required |
Source code in plantimager/controller/scanner/path.py
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 |
|
Circle Link
Circle(center_x, center_y, z, tilt, radius, n_points)
Bases: Path
Creates a circular path for the scanner.
Compute the x
, y
& pan
PathElement
values to create that circle.
Notes
The pan
is computed to always face the center of the circle.
If an iterable is given for tilt
, performs more than one camera acquisition at same xyz position.
Examples:
>>> from plantimager.controller.scanner.path import Circle
>>> circular_path = Circle(200, 200, 50, 0, 200, 9)
>>> circular_path
[x = 0.00, y = 200.00, z = 50.00, pan = 270.00, tilt = 0.00,
x = 46.79, y = 71.44, z = 50.00, pan = 310.00, tilt = 0.00,
x = 165.27, y = 3.04, z = 50.00, pan = 350.00, tilt = 0.00,
x = 300.00, y = 26.79, z = 50.00, pan = 30.00, tilt = 0.00,
x = 387.94, y = 131.60, z = 50.00, pan = 70.00, tilt = 0.00,
x = 387.94, y = 268.40, z = 50.00, pan = 110.00, tilt = 0.00,
x = 300.00, y = 373.21, z = 50.00, pan = 150.00, tilt = 0.00,
x = 165.27, y = 396.96, z = 50.00, pan = 190.00, tilt = 0.00,
x = 46.79, y = 328.56, z = 50.00, pan = 230.00, tilt = 0.00]
>>> circular_path = Circle(200, 200, 50, (0, 10), 200, 9)
>>> circular_path[:4] # print the first 4 position to show tilt change at given xyzp position
[x = 0.00, y = 200.00, z = 50.00, pan = 270.00, tilt = 0.00,
x = 0.00, y = 200.00, z = 50.00, pan = 270.00, tilt = 10.00,
x = 46.79, y = 71.44, z = 50.00, pan = 310.00, tilt = 0.00,
x = 46.79, y = 71.44, z = 50.00, pan = 310.00, tilt = 10.00]
Parameters:
Name | Type | Description | Default |
---|---|---|---|
center_x
|
length_mm
|
X-axis position, in millimeters, of the circle's center, relative to the origin. |
required |
center_y
|
length_mm
|
Y-axis position, in millimeters, of the circle's center, relative to the origin. |
required |
z
|
length_mm
|
Height at which to make the circle. |
required |
tilt
|
deg or list(deg)
|
Camera tilt(s), in degrees, to use for this circle. If an iterable is given, performs more than one camera acquisition at same xyz position. |
required |
radius
|
length_mm
|
Radius, in millimeters, of the circular path to create. |
required |
n_points
|
int
|
Number of points ( |
required |
Source code in plantimager/controller/scanner/path.py
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
|
Cylinder Link
Cylinder(center_x, center_y, z_range, tilt, radius, n_points, n_circles=2)
Bases: Path
Creates a z-axis aligned cylinder path for the scanner.
Makes as much circular paths as n_circles
within the given z range.
Notes
The pan
is computed to always face the center of the circle.
If an iterable is given for tilt
, performs more than one camera acquisition at same xyz position.
Examples:
>>> from plantimager.controller.scanner.path import Cylinder
>>> n_points = 9
>>> cylinder_path = Cylinder(200, 200, (0, 50), 0, 200, n_points, 2)
>>> cylinder_path[:2]
[x = 0.00, y = 200.00, z = 0.00, pan = 270.00, tilt = 0.00,
x = 46.79, y = 71.44, z = 0.00, pan = 310.00, tilt = 0.00]
>>> cylinder_path[n_points:2+n_points]
[x = 0.00, y = 200.00, z = 50.00, pan = 270.00, tilt = 0.00,
x = 46.79, y = 71.44, z = 50.00, pan = 310.00, tilt = 0.00]
Parameters:
Name | Type | Description | Default |
---|---|---|---|
center_x
|
length_mm
|
X-axis position, in millimeters, of the circle's center, relative to the origin. |
required |
center_y
|
length_mm
|
Y-axis position, in millimeters, of the circle's center, relative to the origin. |
required |
z_range
|
(length_mm, length_mm)
|
Height range, in millimeters, at which to make the cylinder. |
required |
tilt
|
deg or list of deg
|
Camera tilt(s), in degrees, to use for this circle. If an iterable is given, performs more than one camera acquisition at same xyz position. |
required |
radius
|
length_mm
|
Radius of the circular path to create. |
required |
n_points
|
int
|
Number of points ( |
required |
n_circles
|
int
|
Number of circular path to make within the cylinder, minimum value is 2. |
2
|
Source code in plantimager/controller/scanner/path.py
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
|
Line Link
Line(x_0, y_0, z_0, x_1, y_1, z_1, pan, tilt, n_points)
Bases: Path
Creates a linear path for the scanner.
Examples:
>>> from plantimager.controller.scanner.path import Line
>>> n_points = 2
>>> linear_path = Line(0, 0, 0, 10, 10, 0, 180, 0, n_points)
>>> linear_path
[x = 0.00, y = 0.00, z = 0.00, pan = 180.00, tilt = 0.00,
x = 10.00, y = 10.00, z = 0.00, pan = 180.00, tilt = 0.00]
Parameters:
Name | Type | Description | Default |
---|---|---|---|
x_0
|
length_mm
|
Line starting position, in millimeters for the x-axis. |
required |
y_0
|
length_mm
|
Line starting position, in millimeters for the y-axis. |
required |
z_0
|
length_mm
|
Line starting position, in millimeters for the z-axis. |
required |
x_1
|
length_mm
|
Line ending position, in millimeters for the x-axis. |
required |
y_1
|
length_mm
|
Line ending position, in millimeters for the y-axis. |
required |
z_1
|
length_mm
|
Line ending position, in millimeters for the z-axis. |
required |
pan
|
deg
|
Camera pan value, in degrees, to use for the linear path. |
required |
tilt
|
deg or list(deg)
|
Camera tilt(s), in degrees, to use for this circle. If an iterable is given, performs more than one camera acquisition at same xyz position. |
required |
n_points
|
int
|
Number of points used to create the linear path. |
required |
Source code in plantimager/controller/scanner/path.py
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 |
|
Path Link
Path()
Bases: list
A path is a list of PathElement
instances.
Examples:
>>> from plantimager.controller.scanner.path import PathElement
>>> elt = PathElement(0, 0, 0, 0, 0, True)
>>> from plantimager.controller.scanner.path import Path
>>> p = Path()
>>> type(p)
>>> p.append(elt)
>>> p2 = Path()
>>> p2.append(elt)
>>> p == p2
>>> p != p2
Source code in plantimager/controller/scanner/path.py
139 140 |
|
PathElement Link
PathElement(x=None, y=None, z=None, pan=None, tilt=None, exact_pose=True)
Bases: Pose
Singleton for a Path
class.
Examples:
>>> from plantimager.controller.scanner.path import PathElement
>>> elt = PathElement(50, 250, 80, 270, 0, True)
>>> print(elt)
Parameters:
Name | Type | Description | Default |
---|---|---|---|
x
|
length_mm
|
Relative distance, in millimeters, to the origin along the x-axis. |
None
|
y
|
length_mm
|
Relative distance, in millimeters, to the origin along the y-axis. |
None
|
z
|
length_mm
|
Relative distance, in millimeters, to the origin along the z-axis. |
None
|
pan
|
deg
|
Relative rotation, in degrees, to the origin along the xy-plane. |
None
|
tilt
|
deg
|
Relative rotation, in degrees, to the origin along the xy-plane. |
None
|
exact_pose
|
bool
|
If |
True
|
Source code in plantimager/controller/scanner/path.py
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
|
Pose Link
Pose(x=None, y=None, z=None, pan=None, tilt=None)
Bases: object
Abstract representation of a 'camera pose' as its 5D coordinates.
Examples:
>>> from plantimager.controller.scanner.path import Pose
>>> p = Pose(50, 250, 80, 270, 0)
>>> print(p)
Pose constructor.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
x
|
length_mm
|
Relative distance to the origin along the x-axis. |
None
|
y
|
length_mm
|
Relative distance to the origin along the y-axis. |
None
|
z
|
length_mm
|
Relative distance to the origin along the z-axis. |
None
|
pan
|
deg
|
Relative rotation to the origin along the xy-plane. |
None
|
tilt
|
deg
|
Relative rotation to the origin orthogonal to the xy-plane. |
None
|
Source code in plantimager/controller/scanner/path.py
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
|
circle Link
circle(center_x, center_y, radius, n_points)
Create a 2D circle of N points with given center and radius.
Pan orientations are also computed to always face the center of the circle.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
center_x
|
length_mm
|
Relative position of the circle center along the X-axis. |
required |
center_y
|
length_mm
|
Relative position of the circle center along the Y-axis. |
required |
radius
|
length_mm
|
Radius of the circle to create. |
required |
n_points
|
int
|
Number of points used to create the circle. |
required |
Returns:
Type | Description |
---|---|
list of length_mm
|
Sequence of x positions. |
list of length_mm
|
Sequence of y positions. |
list of deg
|
Sequence of pan orientations. |
Examples:
>>> from plantimager.controller.scanner.path import circle
>>> circle(10, 10, 5, 3)
([5.0, 12.5, 12.500000000000002],
[10.0, 5.669872981077806, 14.330127018922191],
[270.0, 29.999999999999986, 149.99999999999997])
Source code in plantimager/controller/scanner/path.py
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 |
|
line1d Link
line1d(start, stop, n_points)
Create a 1D line of N points between start and stop position (included).
Parameters:
Name | Type | Description | Default |
---|---|---|---|
start
|
length_mm
|
Line starting position, in millimeters. |
required |
stop
|
length_mm
|
Line ending position, in millimeters. |
required |
n_points
|
int
|
Number of points used to create the line of points. |
required |
Returns:
Type | Description |
---|---|
list of length_mm
|
Sequence of 1D positions. |
Examples:
>>> from plantimager.controller.scanner.path import line1d
>>> line1d(0,10,5)
[0.0, 2.5, 5.0, 7.5, 10.0]
Source code in plantimager/controller/scanner/path.py
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
|
line3d Link
line3d(x_0, y_0, z_0, x_1, y_1, z_1, n_points)
Create a 3D line of N points between start and stop position (included).
Parameters:
Name | Type | Description | Default |
---|---|---|---|
x_0
|
length_mm
|
Line starting position, in millimeters, for the x-axis. |
required |
y_0
|
length_mm
|
Line starting position, in millimeters, for the y-axis. |
required |
z_0
|
length_mm
|
Line starting position, in millimeters, for the z-axis. |
required |
x_1
|
length_mm
|
Line ending position, in millimeters, for the x-axis. |
required |
y_1
|
length_mm
|
Line ending position, in millimeters, for the y-axis. |
required |
z_1
|
length_mm
|
Line ending position, in millimeters, for the z-axis. |
required |
n_points
|
int
|
Number of points used to create the linear path. |
required |
Returns:
Type | Description |
---|---|
list of length_mm
|
Sequence of x positions. |
list of length_mm
|
Sequence of y positions. |
list of length_mm
|
Sequence of z positions. |
Examples:
>>> from plantimager.controller.scanner.path import line3d
>>> line3d(0, 0, 0, 10, 10, 10, 5)
([0.0, 2.5, 5.0, 7.5, 10.0],
[0.0, 2.5, 5.0, 7.5, 10.0],
[0.0, 2.5, 5.0, 7.5, 10.0])
Source code in plantimager/controller/scanner/path.py
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 |
|