Python Interface
Several attempts have been made to make this module easily callable from python. At this time, we recommend using the python package JuliaCall. Simply install juliacall alongside numpy using your favorite method, for instance
uv add juliacall
uv add numpyand use juliacall to install RunwayLib and the PythonCall extension which enables the python API.
from juliacall import Main as jl
jl.Pkg.add(url="http://github.com/RomeoV/RunwayLib.jl") # will be registered soonYou only need to do this once. Now you should be able to use RunwayLib from python like so:
import numpy as np
from juliacall import Main as jl
jl.seval("using RunwayLib, PythonCall")
jl.seval("import RunwayLib: px, m")
points2d = [
jl.ProjectionPoint(2284.8, 619.32)*jl.px,
jl.ProjectionPoint(2355.2, 620.90)*jl.px,
jl.ProjectionPoint(2399.5, 903.30)*jl.px,
jl.ProjectionPoint(2252.4, 904.09)*jl.px,
]
points3d = [
jl.WorldPoint(1600, 15, -8)*jl.m,
jl.WorldPoint(1600, -15, -8)*jl.m,
jl.WorldPoint(0, -15, 0)*jl.m,
jl.WorldPoint(0, 15, 0)*jl.m,
]
intrinsic_matrix = np.array(
[
[-7311.8, 0.0, 2032.3],
[0.0, -7311.8, 1707.4],
[0.0, 0.0, 1.0],
]
)
camconf = jl.CameraMatrix[jl.Symbol("offset")](
intrinsic_matrix, jl.px(2048.0), jl.px(1024.0),
)
jl.seval("using RunwayLib.Unitful: ustrip, rad")
line_pts = [
(points3d[1], points3d[2]), # near left, far left, according to points3d
(points3d[0], points3d[3]) # near right, far right, according to points3d
];
observed_lines = [
# these are bogus numbers for illustration purposes only
jl.Line(
jl.px(2000.0),
jl.rad(np.deg2rad(1))
),
jl.Line(
jl.px(2000.0),
jl.rad(np.deg2rad(-1))
)
];
res_jl = jl.estimatepose6dof(
jl.PointFeatures(points3d, points2d, camconf),
jl.LineFeatures(line_pts, observed_lines, camconf)
)
pos = np.asarray(jl.broadcast(jl.ustrip, res_jl.pos)) # or `np.array(..., copy=None)`
rot = np.asarray(res_jl.rot)
# Smoke test assertions
assert pos.shape == (3,), f"Expected position shape (3,), got {pos.shape}"
assert rot.shape == (3, 3), f"Expected rotation shape (3, 3), got {rot.shape}"
print(f"✓ Smoke test passed! Position: {pos}, Rotation shape: {rot.shape}")
Notice that we can also directly wrap np.array for WorldPoint and the other, e.g.:
points2d_np = [
np.array([2284.8, 619.32]),
np.array([2355.2, 620.90]),
np.array([2399.5, 903.30]),
np.array([2252.4, 904.09]),
]
point2d = [jl.ProjectionPoint(p) for p in points2d_np]