Clean up nanobind typing and source layout
This commit is contained in:
+1
-1
@@ -13,5 +13,5 @@ set(CMAKE_CXX_EXTENSIONS OFF)
|
|||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
# Add subdirectories
|
# Add subdirectories
|
||||||
add_subdirectory(rpt)
|
add_subdirectory(rpt_cpp)
|
||||||
add_subdirectory(bindings)
|
add_subdirectory(bindings)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ The current fork keeps the triangulation core, exposes it through `nanobind`, an
|
|||||||
Current package status:
|
Current package status:
|
||||||
|
|
||||||
- Python `>=3.10`
|
- Python `>=3.10`
|
||||||
- NumPy runtime dependency
|
- Runtime dependencies: NumPy, jaxtyping
|
||||||
- Current version: `0.2.0`
|
- Current version: `0.2.0`
|
||||||
|
|
||||||
## Current Capabilities
|
## Current Capabilities
|
||||||
@@ -54,6 +54,12 @@ Run the test suite:
|
|||||||
uv run pytest -q
|
uv run pytest -q
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Run static typing checks against the Python package:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run basedpyright
|
||||||
|
```
|
||||||
|
|
||||||
Build source and wheel artifacts:
|
Build source and wheel artifacts:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -62,6 +68,20 @@ uv build
|
|||||||
|
|
||||||
`run_container.sh` is still present in the repo, but it is a leftover helper script rather than the primary or best-supported development workflow.
|
`run_container.sh` is still present in the repo, but it is a leftover helper script rather than the primary or best-supported development workflow.
|
||||||
|
|
||||||
|
## Typing Workflow
|
||||||
|
|
||||||
|
The Python package ships a typed facade in `src/rpt` plus a checked-in stub for the compiled nanobind module at `src/rpt/_core.pyi`.
|
||||||
|
|
||||||
|
Refresh the extension stub after changing the bindings:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake --build build --target rpt_core_stub
|
||||||
|
cp build/bindings/rpt/_core.pyi src/rpt/_core.pyi
|
||||||
|
uv run basedpyright
|
||||||
|
```
|
||||||
|
|
||||||
|
`tests/test_typing_artifacts.py` checks that the checked-in `_core.pyi` matches the generated nanobind stub whenever the build artifact is available.
|
||||||
|
|
||||||
## Python API Overview
|
## Python API Overview
|
||||||
|
|
||||||
Typical triangulation flow:
|
Typical triangulation flow:
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ set_target_properties(rpt_core_ext PROPERTIES
|
|||||||
|
|
||||||
target_link_libraries(rpt_core_ext PRIVATE rpt_core)
|
target_link_libraries(rpt_core_ext PRIVATE rpt_core)
|
||||||
target_include_directories(rpt_core_ext PRIVATE
|
target_include_directories(rpt_core_ext PRIVATE
|
||||||
"${PROJECT_SOURCE_DIR}/rpt"
|
"${PROJECT_SOURCE_DIR}/rpt_cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
nanobind_add_stub(rpt_core_stub
|
nanobind_add_stub(rpt_core_stub
|
||||||
@@ -43,3 +43,4 @@ nanobind_add_stub(rpt_core_stub
|
|||||||
install(TARGETS rpt_core_ext LIBRARY DESTINATION rpt)
|
install(TARGETS rpt_core_ext LIBRARY DESTINATION rpt)
|
||||||
install(FILES "${RPT_PYTHON_PACKAGE_DIR}/__init__.pyi" DESTINATION rpt)
|
install(FILES "${RPT_PYTHON_PACKAGE_DIR}/__init__.pyi" DESTINATION rpt)
|
||||||
install(FILES "${RPT_PYTHON_PACKAGE_DIR}/_core.pyi" DESTINATION rpt)
|
install(FILES "${RPT_PYTHON_PACKAGE_DIR}/_core.pyi" DESTINATION rpt)
|
||||||
|
install(FILES "${RPT_PYTHON_PACKAGE_DIR}/py.typed" DESTINATION rpt)
|
||||||
|
|||||||
+8
-2
@@ -11,10 +11,16 @@ version = "0.2.0"
|
|||||||
description = "Rapid Pose Triangulation library with nanobind Python bindings"
|
description = "Rapid Pose Triangulation library with nanobind Python bindings"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
dependencies = ["numpy>=2.0"]
|
dependencies = [
|
||||||
|
"jaxtyping",
|
||||||
|
"numpy>=2.0",
|
||||||
|
]
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
dev = ["pytest>=8.3"]
|
dev = [
|
||||||
|
"basedpyright>=1.38.3",
|
||||||
|
"pytest>=8.3",
|
||||||
|
]
|
||||||
|
|
||||||
[tool.scikit-build]
|
[tool.scikit-build]
|
||||||
minimum-version = "build-system.requires"
|
minimum-version = "build-system.requires"
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"include": ["src"],
|
||||||
|
"ignore": ["src/rpt/_core.pyi"],
|
||||||
|
"failOnWarnings": false,
|
||||||
|
"pythonVersion": "3.10",
|
||||||
|
"reportMissingModuleSource": "none",
|
||||||
|
"executionEnvironments": [
|
||||||
|
{
|
||||||
|
"root": "tests",
|
||||||
|
"extraPaths": ["src"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
+18
-7
@@ -34,7 +34,15 @@ if TYPE_CHECKING:
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import numpy.typing as npt
|
import numpy.typing as npt
|
||||||
|
|
||||||
from ._helpers import CameraLike, CameraModelLike, DepthImageLike, Matrix3x3Like, PoseViewLike, VectorLike
|
from ._helpers import (
|
||||||
|
CameraLike,
|
||||||
|
CameraModelLike,
|
||||||
|
DepthImageLike,
|
||||||
|
Matrix3x3Like,
|
||||||
|
PoseViewLike,
|
||||||
|
TranslationVectorLike,
|
||||||
|
VectorLike,
|
||||||
|
)
|
||||||
|
|
||||||
PoseArray2D = npt.NDArray[np.float32]
|
PoseArray2D = npt.NDArray[np.float32]
|
||||||
PoseArray3D = npt.NDArray[np.float32]
|
PoseArray3D = npt.NDArray[np.float32]
|
||||||
@@ -64,22 +72,25 @@ def make_camera(
|
|||||||
K: "Matrix3x3Like",
|
K: "Matrix3x3Like",
|
||||||
DC: "VectorLike",
|
DC: "VectorLike",
|
||||||
R: "Matrix3x3Like",
|
R: "Matrix3x3Like",
|
||||||
T: "Sequence[Sequence[float]]",
|
T: "TranslationVectorLike",
|
||||||
width: int,
|
width: int,
|
||||||
height: int,
|
height: int,
|
||||||
model: "CameraModel | CameraModelLike",
|
model: "CameraModel | CameraModelLike",
|
||||||
) -> Camera:
|
) -> Camera:
|
||||||
"""Create an immutable camera and precompute its cached projection fields."""
|
"""Create an immutable camera and precompute its cached projection fields.
|
||||||
|
|
||||||
from ._helpers import _coerce_camera_model, _coerce_distortion
|
`T` may be a flat `[x, y, z]` vector or a nested translation matrix with shape `[1, 3]` or `[3, 1]`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from ._helpers import _coerce_camera_model, _coerce_distortion, _coerce_matrix3x3, _coerce_translation
|
||||||
|
|
||||||
camera_model = _coerce_camera_model(model)
|
camera_model = _coerce_camera_model(model)
|
||||||
return _make_camera(
|
return _make_camera(
|
||||||
name,
|
name,
|
||||||
K,
|
_coerce_matrix3x3(K, "K").tolist(),
|
||||||
_coerce_distortion(DC, camera_model),
|
_coerce_distortion(DC, camera_model),
|
||||||
R,
|
_coerce_matrix3x3(R, "R").tolist(),
|
||||||
T,
|
_coerce_translation(T).tolist(),
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
camera_model,
|
camera_model,
|
||||||
|
|||||||
+61
-20
@@ -5,25 +5,34 @@ import numpy as np
|
|||||||
import numpy.typing as npt
|
import numpy.typing as npt
|
||||||
|
|
||||||
from ._core import (
|
from ._core import (
|
||||||
AssociationReport,
|
AssociationReport as AssociationReport,
|
||||||
AssociationStatus,
|
AssociationStatus as AssociationStatus,
|
||||||
Camera,
|
Camera as Camera,
|
||||||
CameraModel,
|
CameraModel as CameraModel,
|
||||||
CoreProposalDebug,
|
CoreProposalDebug as CoreProposalDebug,
|
||||||
FinalPoseAssociationDebug,
|
FinalPoseAssociationDebug as FinalPoseAssociationDebug,
|
||||||
FullProposalDebug,
|
FullProposalDebug as FullProposalDebug,
|
||||||
GroupingDebug,
|
GroupingDebug as GroupingDebug,
|
||||||
MergeDebug,
|
MergeDebug as MergeDebug,
|
||||||
PairCandidate,
|
PairCandidate as PairCandidate,
|
||||||
PreviousPoseFilterDebug,
|
PreviousPoseFilterDebug as PreviousPoseFilterDebug,
|
||||||
PreviousPoseMatch,
|
PreviousPoseMatch as PreviousPoseMatch,
|
||||||
ProposalGroupDebug,
|
ProposalGroupDebug as ProposalGroupDebug,
|
||||||
TriangulationConfig,
|
TriangulationConfig as TriangulationConfig,
|
||||||
TriangulationOptions,
|
TriangulationOptions as TriangulationOptions,
|
||||||
TriangulationResult,
|
TriangulationResult as TriangulationResult,
|
||||||
TriangulationTrace,
|
TriangulationTrace as TriangulationTrace,
|
||||||
|
)
|
||||||
|
from ._helpers import (
|
||||||
|
CameraLike,
|
||||||
|
CameraModelLike,
|
||||||
|
DepthImageLike,
|
||||||
|
Matrix3x3Like,
|
||||||
|
PoseViewLike,
|
||||||
|
RoomParamsLike,
|
||||||
|
TranslationVectorLike,
|
||||||
|
VectorLike,
|
||||||
)
|
)
|
||||||
from ._helpers import CameraLike, CameraModelLike, DepthImageLike, Matrix3x3Like, PoseViewLike, RoomParamsLike, VectorLike
|
|
||||||
|
|
||||||
PoseArray2D: TypeAlias = npt.NDArray[np.float32]
|
PoseArray2D: TypeAlias = npt.NDArray[np.float32]
|
||||||
PoseArray3D: TypeAlias = npt.NDArray[np.float32]
|
PoseArray3D: TypeAlias = npt.NDArray[np.float32]
|
||||||
@@ -40,7 +49,7 @@ def make_camera(
|
|||||||
K: Matrix3x3Like,
|
K: Matrix3x3Like,
|
||||||
DC: VectorLike,
|
DC: VectorLike,
|
||||||
R: Matrix3x3Like,
|
R: Matrix3x3Like,
|
||||||
T: Sequence[Sequence[float]],
|
T: TranslationVectorLike,
|
||||||
width: int,
|
width: int,
|
||||||
height: int,
|
height: int,
|
||||||
model: CameraModel | CameraModelLike,
|
model: CameraModel | CameraModelLike,
|
||||||
@@ -155,4 +164,36 @@ def triangulate_with_report(
|
|||||||
) -> TriangulationResult: ...
|
) -> TriangulationResult: ...
|
||||||
|
|
||||||
|
|
||||||
__all__: list[str]
|
__all__ = [
|
||||||
|
"Camera",
|
||||||
|
"CameraModel",
|
||||||
|
"AssociationReport",
|
||||||
|
"AssociationStatus",
|
||||||
|
"apply_depth_offsets",
|
||||||
|
"FinalPoseAssociationDebug",
|
||||||
|
"TriangulationConfig",
|
||||||
|
"TriangulationOptions",
|
||||||
|
"TriangulationResult",
|
||||||
|
"CoreProposalDebug",
|
||||||
|
"FullProposalDebug",
|
||||||
|
"GroupingDebug",
|
||||||
|
"MergeDebug",
|
||||||
|
"PairCandidate",
|
||||||
|
"PreviousPoseFilterDebug",
|
||||||
|
"PreviousPoseMatch",
|
||||||
|
"ProposalGroupDebug",
|
||||||
|
"TriangulationTrace",
|
||||||
|
"build_pair_candidates",
|
||||||
|
"convert_cameras",
|
||||||
|
"filter_pairs_with_previous_poses",
|
||||||
|
"lift_depth_poses_to_world",
|
||||||
|
"make_camera",
|
||||||
|
"make_triangulation_config",
|
||||||
|
"merge_rgbd_views",
|
||||||
|
"pack_poses_2d",
|
||||||
|
"reconstruct_rgbd",
|
||||||
|
"sample_depth_for_poses",
|
||||||
|
"triangulate_debug",
|
||||||
|
"triangulate_poses",
|
||||||
|
"triangulate_with_report",
|
||||||
|
]
|
||||||
|
|||||||
@@ -0,0 +1,530 @@
|
|||||||
|
from collections.abc import Sequence
|
||||||
|
import enum
|
||||||
|
from typing import Annotated, overload
|
||||||
|
|
||||||
|
import numpy
|
||||||
|
from numpy.typing import NDArray
|
||||||
|
|
||||||
|
|
||||||
|
class CameraModel(enum.Enum):
|
||||||
|
PINHOLE = 0
|
||||||
|
|
||||||
|
FISHEYE = 1
|
||||||
|
|
||||||
|
class Camera:
|
||||||
|
"""Immutable camera calibration with precomputed projection cache fields."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self) -> str: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def K(self) -> list[list[float]]: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def DC(self) -> list[float]: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def R(self) -> list[list[float]]: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def T(self) -> list[list[float]]: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def width(self) -> int: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def height(self) -> int: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def model(self) -> CameraModel: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def invR(self) -> list[list[float]]: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def center(self) -> list[float]: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def newK(self) -> list[list[float]]: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def invK(self) -> list[list[float]]: ...
|
||||||
|
|
||||||
|
def __repr__(self) -> str: ...
|
||||||
|
|
||||||
|
class TriangulationOptions:
|
||||||
|
"""Score and grouping thresholds used by triangulation."""
|
||||||
|
|
||||||
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def min_match_score(self) -> float: ...
|
||||||
|
|
||||||
|
@min_match_score.setter
|
||||||
|
def min_match_score(self, arg: float, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def min_group_size(self) -> int: ...
|
||||||
|
|
||||||
|
@min_group_size.setter
|
||||||
|
def min_group_size(self, arg: int, /) -> None: ...
|
||||||
|
|
||||||
|
class TriangulationConfig:
|
||||||
|
"""Stable scene configuration used for triangulation."""
|
||||||
|
|
||||||
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cameras(self) -> list[Camera]: ...
|
||||||
|
|
||||||
|
@cameras.setter
|
||||||
|
def cameras(self, arg: Sequence[Camera], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def roomparams(self) -> list[list[float]]: ...
|
||||||
|
|
||||||
|
@roomparams.setter
|
||||||
|
def roomparams(self, arg: Sequence[Sequence[float]], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def joint_names(self) -> list[str]: ...
|
||||||
|
|
||||||
|
@joint_names.setter
|
||||||
|
def joint_names(self, arg: Sequence[str], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def options(self) -> TriangulationOptions: ...
|
||||||
|
|
||||||
|
@options.setter
|
||||||
|
def options(self, arg: TriangulationOptions, /) -> None: ...
|
||||||
|
|
||||||
|
class PairCandidate:
|
||||||
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def view1(self) -> int: ...
|
||||||
|
|
||||||
|
@view1.setter
|
||||||
|
def view1(self, arg: int, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def view2(self) -> int: ...
|
||||||
|
|
||||||
|
@view2.setter
|
||||||
|
def view2(self, arg: int, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def person1(self) -> int: ...
|
||||||
|
|
||||||
|
@person1.setter
|
||||||
|
def person1(self, arg: int, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def person2(self) -> int: ...
|
||||||
|
|
||||||
|
@person2.setter
|
||||||
|
def person2(self, arg: int, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def global_person1(self) -> int: ...
|
||||||
|
|
||||||
|
@global_person1.setter
|
||||||
|
def global_person1(self, arg: int, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def global_person2(self) -> int: ...
|
||||||
|
|
||||||
|
@global_person2.setter
|
||||||
|
def global_person2(self, arg: int, /) -> None: ...
|
||||||
|
|
||||||
|
class PreviousPoseMatch:
|
||||||
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def previous_pose_index(self) -> int: ...
|
||||||
|
|
||||||
|
@previous_pose_index.setter
|
||||||
|
def previous_pose_index(self, arg: int, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def previous_track_id(self) -> int: ...
|
||||||
|
|
||||||
|
@previous_track_id.setter
|
||||||
|
def previous_track_id(self, arg: int, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def score_view1(self) -> float: ...
|
||||||
|
|
||||||
|
@score_view1.setter
|
||||||
|
def score_view1(self, arg: float, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def score_view2(self) -> float: ...
|
||||||
|
|
||||||
|
@score_view2.setter
|
||||||
|
def score_view2(self, arg: float, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def matched_view1(self) -> bool: ...
|
||||||
|
|
||||||
|
@matched_view1.setter
|
||||||
|
def matched_view1(self, arg: bool, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def matched_view2(self) -> bool: ...
|
||||||
|
|
||||||
|
@matched_view2.setter
|
||||||
|
def matched_view2(self, arg: bool, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def kept(self) -> bool: ...
|
||||||
|
|
||||||
|
@kept.setter
|
||||||
|
def kept(self, arg: bool, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def decision(self) -> str: ...
|
||||||
|
|
||||||
|
@decision.setter
|
||||||
|
def decision(self, arg: str, /) -> None: ...
|
||||||
|
|
||||||
|
class PreviousPoseFilterDebug:
|
||||||
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def used_previous_poses(self) -> bool: ...
|
||||||
|
|
||||||
|
@used_previous_poses.setter
|
||||||
|
def used_previous_poses(self, arg: bool, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def matches(self) -> list[PreviousPoseMatch]: ...
|
||||||
|
|
||||||
|
@matches.setter
|
||||||
|
def matches(self, arg: Sequence[PreviousPoseMatch], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def kept_pair_indices(self) -> list[int]: ...
|
||||||
|
|
||||||
|
@kept_pair_indices.setter
|
||||||
|
def kept_pair_indices(self, arg: Sequence[int], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def kept_pairs(self) -> list[PairCandidate]: ...
|
||||||
|
|
||||||
|
@kept_pairs.setter
|
||||||
|
def kept_pairs(self, arg: Sequence[PairCandidate], /) -> None: ...
|
||||||
|
|
||||||
|
class CoreProposalDebug:
|
||||||
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pair_index(self) -> int: ...
|
||||||
|
|
||||||
|
@pair_index.setter
|
||||||
|
def pair_index(self, arg: int, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pair(self) -> PairCandidate: ...
|
||||||
|
|
||||||
|
@pair.setter
|
||||||
|
def pair(self, arg: PairCandidate, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def score(self) -> float: ...
|
||||||
|
|
||||||
|
@score.setter
|
||||||
|
def score(self, arg: float, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def kept(self) -> bool: ...
|
||||||
|
|
||||||
|
@kept.setter
|
||||||
|
def kept(self, arg: bool, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def drop_reason(self) -> str: ...
|
||||||
|
|
||||||
|
@drop_reason.setter
|
||||||
|
def drop_reason(self, arg: str, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pose_3d(self) -> Annotated[NDArray[numpy.float32], dict(shape=(None, 4), order='C')]: ...
|
||||||
|
|
||||||
|
class ProposalGroupDebug:
|
||||||
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def center(self) -> list[float]: ...
|
||||||
|
|
||||||
|
@center.setter
|
||||||
|
def center(self, arg: Sequence[float], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def proposal_indices(self) -> list[int]: ...
|
||||||
|
|
||||||
|
@proposal_indices.setter
|
||||||
|
def proposal_indices(self, arg: Sequence[int], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pose_3d(self) -> Annotated[NDArray[numpy.float32], dict(shape=(None, 4), order='C')]: ...
|
||||||
|
|
||||||
|
class GroupingDebug:
|
||||||
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def initial_groups(self) -> list[ProposalGroupDebug]: ...
|
||||||
|
|
||||||
|
@initial_groups.setter
|
||||||
|
def initial_groups(self, arg: Sequence[ProposalGroupDebug], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def duplicate_pair_drops(self) -> list[int]: ...
|
||||||
|
|
||||||
|
@duplicate_pair_drops.setter
|
||||||
|
def duplicate_pair_drops(self, arg: Sequence[int], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def groups(self) -> list[ProposalGroupDebug]: ...
|
||||||
|
|
||||||
|
@groups.setter
|
||||||
|
def groups(self, arg: Sequence[ProposalGroupDebug], /) -> None: ...
|
||||||
|
|
||||||
|
class FullProposalDebug:
|
||||||
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def source_core_proposal_index(self) -> int: ...
|
||||||
|
|
||||||
|
@source_core_proposal_index.setter
|
||||||
|
def source_core_proposal_index(self, arg: int, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pair(self) -> PairCandidate: ...
|
||||||
|
|
||||||
|
@pair.setter
|
||||||
|
def pair(self, arg: PairCandidate, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pose_3d(self) -> Annotated[NDArray[numpy.float32], dict(shape=(None, 4), order='C')]: ...
|
||||||
|
|
||||||
|
class MergeDebug:
|
||||||
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def group_proposal_indices(self) -> list[list[int]]: ...
|
||||||
|
|
||||||
|
@group_proposal_indices.setter
|
||||||
|
def group_proposal_indices(self, arg: Sequence[Sequence[int]], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def merged_poses(self) -> Annotated[NDArray[numpy.float32], dict(shape=(None, None, 4), order='C')]: ...
|
||||||
|
|
||||||
|
class AssociationStatus(enum.Enum):
|
||||||
|
MATCHED = 0
|
||||||
|
|
||||||
|
NEW = 1
|
||||||
|
|
||||||
|
AMBIGUOUS = 2
|
||||||
|
|
||||||
|
class AssociationReport:
|
||||||
|
"""Track-association summary for a tracked triangulation call."""
|
||||||
|
|
||||||
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pose_previous_indices(self) -> list[int]: ...
|
||||||
|
|
||||||
|
@pose_previous_indices.setter
|
||||||
|
def pose_previous_indices(self, arg: Sequence[int], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pose_previous_track_ids(self) -> list[int]: ...
|
||||||
|
|
||||||
|
@pose_previous_track_ids.setter
|
||||||
|
def pose_previous_track_ids(self, arg: Sequence[int], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pose_status(self) -> list[AssociationStatus]: ...
|
||||||
|
|
||||||
|
@pose_status.setter
|
||||||
|
def pose_status(self, arg: Sequence[AssociationStatus], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pose_candidate_previous_indices(self) -> list[list[int]]: ...
|
||||||
|
|
||||||
|
@pose_candidate_previous_indices.setter
|
||||||
|
def pose_candidate_previous_indices(self, arg: Sequence[Sequence[int]], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pose_candidate_previous_track_ids(self) -> list[list[int]]: ...
|
||||||
|
|
||||||
|
@pose_candidate_previous_track_ids.setter
|
||||||
|
def pose_candidate_previous_track_ids(self, arg: Sequence[Sequence[int]], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unmatched_previous_indices(self) -> list[int]: ...
|
||||||
|
|
||||||
|
@unmatched_previous_indices.setter
|
||||||
|
def unmatched_previous_indices(self, arg: Sequence[int], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unmatched_previous_track_ids(self) -> list[int]: ...
|
||||||
|
|
||||||
|
@unmatched_previous_track_ids.setter
|
||||||
|
def unmatched_previous_track_ids(self, arg: Sequence[int], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def new_pose_indices(self) -> list[int]: ...
|
||||||
|
|
||||||
|
@new_pose_indices.setter
|
||||||
|
def new_pose_indices(self, arg: Sequence[int], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ambiguous_pose_indices(self) -> list[int]: ...
|
||||||
|
|
||||||
|
@ambiguous_pose_indices.setter
|
||||||
|
def ambiguous_pose_indices(self, arg: Sequence[int], /) -> None: ...
|
||||||
|
|
||||||
|
class FinalPoseAssociationDebug:
|
||||||
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def final_pose_index(self) -> int: ...
|
||||||
|
|
||||||
|
@final_pose_index.setter
|
||||||
|
def final_pose_index(self, arg: int, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def source_core_proposal_indices(self) -> list[int]: ...
|
||||||
|
|
||||||
|
@source_core_proposal_indices.setter
|
||||||
|
def source_core_proposal_indices(self, arg: Sequence[int], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def source_pair_indices(self) -> list[int]: ...
|
||||||
|
|
||||||
|
@source_pair_indices.setter
|
||||||
|
def source_pair_indices(self, arg: Sequence[int], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def candidate_previous_indices(self) -> list[int]: ...
|
||||||
|
|
||||||
|
@candidate_previous_indices.setter
|
||||||
|
def candidate_previous_indices(self, arg: Sequence[int], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def candidate_previous_track_ids(self) -> list[int]: ...
|
||||||
|
|
||||||
|
@candidate_previous_track_ids.setter
|
||||||
|
def candidate_previous_track_ids(self, arg: Sequence[int], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def resolved_previous_index(self) -> int: ...
|
||||||
|
|
||||||
|
@resolved_previous_index.setter
|
||||||
|
def resolved_previous_index(self, arg: int, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def resolved_previous_track_id(self) -> int: ...
|
||||||
|
|
||||||
|
@resolved_previous_track_id.setter
|
||||||
|
def resolved_previous_track_id(self, arg: int, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def status(self) -> AssociationStatus: ...
|
||||||
|
|
||||||
|
@status.setter
|
||||||
|
def status(self, arg: AssociationStatus, /) -> None: ...
|
||||||
|
|
||||||
|
class TriangulationTrace:
|
||||||
|
"""
|
||||||
|
Full debug trace for triangulation, including pair, grouping, and association stages.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pairs(self) -> list[PairCandidate]: ...
|
||||||
|
|
||||||
|
@pairs.setter
|
||||||
|
def pairs(self, arg: Sequence[PairCandidate], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def previous_filter(self) -> PreviousPoseFilterDebug: ...
|
||||||
|
|
||||||
|
@previous_filter.setter
|
||||||
|
def previous_filter(self, arg: PreviousPoseFilterDebug, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def core_proposals(self) -> list[CoreProposalDebug]: ...
|
||||||
|
|
||||||
|
@core_proposals.setter
|
||||||
|
def core_proposals(self, arg: Sequence[CoreProposalDebug], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def grouping(self) -> GroupingDebug: ...
|
||||||
|
|
||||||
|
@grouping.setter
|
||||||
|
def grouping(self, arg: GroupingDebug, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def full_proposals(self) -> list[FullProposalDebug]: ...
|
||||||
|
|
||||||
|
@full_proposals.setter
|
||||||
|
def full_proposals(self, arg: Sequence[FullProposalDebug], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def merge(self) -> MergeDebug: ...
|
||||||
|
|
||||||
|
@merge.setter
|
||||||
|
def merge(self, arg: MergeDebug, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def association(self) -> AssociationReport: ...
|
||||||
|
|
||||||
|
@association.setter
|
||||||
|
def association(self, arg: AssociationReport, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def final_pose_associations(self) -> list[FinalPoseAssociationDebug]: ...
|
||||||
|
|
||||||
|
@final_pose_associations.setter
|
||||||
|
def final_pose_associations(self, arg: Sequence[FinalPoseAssociationDebug], /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def final_poses(self) -> Annotated[NDArray[numpy.float32], dict(shape=(None, None, 4), order='C')]: ...
|
||||||
|
|
||||||
|
class TriangulationResult:
|
||||||
|
"""
|
||||||
|
Tracked triangulation output containing poses and association metadata.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def association(self) -> AssociationReport: ...
|
||||||
|
|
||||||
|
@association.setter
|
||||||
|
def association(self, arg: AssociationReport, /) -> None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def poses_3d(self) -> Annotated[NDArray[numpy.float32], dict(shape=(None, None, 4), order='C')]: ...
|
||||||
|
|
||||||
|
def make_camera(name: str, K: Sequence[Sequence[float]], DC: Sequence[float], R: Sequence[Sequence[float]], T: Sequence[Sequence[float]], width: int, height: int, model: CameraModel) -> Camera: ...
|
||||||
|
|
||||||
|
def build_pair_candidates(poses_2d: Annotated[NDArray[numpy.float32], dict(shape=(None, None, None, 3), order='C', writable=False)], person_counts: Annotated[NDArray[numpy.uint32], dict(shape=(None,), order='C', writable=False)]) -> list[PairCandidate]: ...
|
||||||
|
|
||||||
|
def filter_pairs_with_previous_poses(poses_2d: Annotated[NDArray[numpy.float32], dict(shape=(None, None, None, 3), order='C', writable=False)], person_counts: Annotated[NDArray[numpy.uint32], dict(shape=(None,), order='C', writable=False)], config: TriangulationConfig, previous_poses_3d: Annotated[NDArray[numpy.float32], dict(shape=(None, None, 4), order='C', writable=False)], previous_track_ids: Annotated[NDArray[numpy.int64], dict(shape=(None,), order='C', writable=False)]) -> PreviousPoseFilterDebug: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def triangulate_debug(poses_2d: Annotated[NDArray[numpy.float32], dict(shape=(None, None, None, 3), order='C', writable=False)], person_counts: Annotated[NDArray[numpy.uint32], dict(shape=(None,), order='C', writable=False)], config: TriangulationConfig) -> TriangulationTrace: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def triangulate_debug(poses_2d: Annotated[NDArray[numpy.float32], dict(shape=(None, None, None, 3), order='C', writable=False)], person_counts: Annotated[NDArray[numpy.uint32], dict(shape=(None,), order='C', writable=False)], config: TriangulationConfig, previous_poses_3d: Annotated[NDArray[numpy.float32], dict(shape=(None, None, 4), order='C', writable=False)], previous_track_ids: Annotated[NDArray[numpy.int64], dict(shape=(None,), order='C', writable=False)]) -> TriangulationTrace: ...
|
||||||
|
|
||||||
|
def triangulate_poses(poses_2d: Annotated[NDArray[numpy.float32], dict(shape=(None, None, None, 3), order='C', writable=False)], person_counts: Annotated[NDArray[numpy.uint32], dict(shape=(None,), order='C', writable=False)], config: TriangulationConfig) -> Annotated[NDArray[numpy.float32], dict(shape=(None, None, 4), order='C')]: ...
|
||||||
|
|
||||||
|
def merge_rgbd_views(poses_3d: Annotated[NDArray[numpy.float32], dict(shape=(None, None, None, 4), order='C', writable=False)], person_counts: Annotated[NDArray[numpy.uint32], dict(shape=(None,), order='C', writable=False)], config: TriangulationConfig, max_distance: float = 0.5) -> Annotated[NDArray[numpy.float32], dict(shape=(None, None, 4), order='C')]: ...
|
||||||
|
|
||||||
|
def triangulate_with_report(poses_2d: Annotated[NDArray[numpy.float32], dict(shape=(None, None, None, 3), order='C', writable=False)], person_counts: Annotated[NDArray[numpy.uint32], dict(shape=(None,), order='C', writable=False)], config: TriangulationConfig, previous_poses_3d: Annotated[NDArray[numpy.float32], dict(shape=(None, None, 4), order='C', writable=False)], previous_track_ids: Annotated[NDArray[numpy.int64], dict(shape=(None,), order='C', writable=False)]) -> TriangulationResult: ...
|
||||||
+40
-12
@@ -1,34 +1,44 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
from typing import Literal, TypeAlias, TypedDict
|
from typing import Literal, TypeAlias, TypedDict
|
||||||
|
|
||||||
|
from jaxtyping import Float
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import numpy.typing as npt
|
import numpy.typing as npt
|
||||||
|
|
||||||
from ._core import Camera, CameraModel, TriangulationConfig, TriangulationOptions, make_camera
|
from ._core import Camera, CameraModel, TriangulationConfig, TriangulationOptions, make_camera as _make_camera
|
||||||
|
|
||||||
Matrix3x3Like: TypeAlias = Sequence[Sequence[float]]
|
Matrix3x3: TypeAlias = Float[np.ndarray, "3 3"]
|
||||||
VectorLike: TypeAlias = Sequence[float]
|
DistortionVector: TypeAlias = Float[np.ndarray, "coeffs"]
|
||||||
|
TranslationVector: TypeAlias = Float[np.ndarray, "3"]
|
||||||
|
TranslationColumn: TypeAlias = Float[np.ndarray, "3 1"]
|
||||||
|
TranslationRow: TypeAlias = Float[np.ndarray, "1 3"]
|
||||||
|
Matrix3x3Like: TypeAlias = Matrix3x3 | Sequence[Sequence[float]]
|
||||||
|
VectorLike: TypeAlias = DistortionVector | Sequence[float]
|
||||||
|
TranslationVectorLike: TypeAlias = (
|
||||||
|
TranslationVector | TranslationColumn | TranslationRow | Sequence[float] | Sequence[Sequence[float]]
|
||||||
|
)
|
||||||
RoomParamsLike: TypeAlias = npt.NDArray[np.generic] | Sequence[Sequence[float]]
|
RoomParamsLike: TypeAlias = npt.NDArray[np.generic] | Sequence[Sequence[float]]
|
||||||
PoseViewLike: TypeAlias = npt.NDArray[np.generic] | Sequence[Sequence[Sequence[float]]] | Sequence[Sequence[float]]
|
PoseViewLike: TypeAlias = npt.NDArray[np.generic] | Sequence[Sequence[Sequence[float]]] | Sequence[Sequence[float]]
|
||||||
DepthImageLike: TypeAlias = npt.NDArray[np.generic] | Sequence[Sequence[float]]
|
DepthImageLike: TypeAlias = npt.NDArray[np.generic] | Sequence[Sequence[float]]
|
||||||
|
|
||||||
|
|
||||||
class CameraDict(TypedDict, total=False):
|
class _CameraDictRequired(TypedDict):
|
||||||
name: str
|
name: str
|
||||||
K: Matrix3x3Like
|
K: Matrix3x3Like
|
||||||
DC: VectorLike
|
DC: VectorLike
|
||||||
R: Matrix3x3Like
|
R: Matrix3x3Like
|
||||||
T: Sequence[Sequence[float]]
|
T: TranslationVectorLike
|
||||||
width: int
|
width: int
|
||||||
height: int
|
height: int
|
||||||
|
|
||||||
|
|
||||||
|
class CameraDict(_CameraDictRequired, total=False):
|
||||||
type: Literal["pinhole", "fisheye"]
|
type: Literal["pinhole", "fisheye"]
|
||||||
model: Literal["pinhole", "fisheye"] | CameraModel
|
model: Literal["pinhole", "fisheye"] | CameraModel
|
||||||
|
|
||||||
|
|
||||||
CameraModelLike: TypeAlias = CameraModel | Literal["pinhole", "fisheye"]
|
CameraModelLike: TypeAlias = CameraModel | Literal["pinhole", "fisheye"]
|
||||||
CameraLike = Camera | CameraDict
|
CameraLike: TypeAlias = Camera | CameraDict
|
||||||
|
|
||||||
DEFAULT_DEPTH_OFFSETS_METERS: dict[str, float] = {
|
DEFAULT_DEPTH_OFFSETS_METERS: dict[str, float] = {
|
||||||
"nose": 0.005,
|
"nose": 0.005,
|
||||||
@@ -79,6 +89,24 @@ def _coerce_distortion(distortion: VectorLike, camera_model: CameraModel) -> tup
|
|||||||
return values
|
return values
|
||||||
|
|
||||||
|
|
||||||
|
def _coerce_matrix3x3(matrix: object, field_name: str) -> Matrix3x3:
|
||||||
|
array = np.asarray(matrix, dtype=np.float32)
|
||||||
|
if array.shape != (3, 3):
|
||||||
|
raise ValueError(f"{field_name} must have shape [3, 3].")
|
||||||
|
return np.ascontiguousarray(array, dtype=np.float32)
|
||||||
|
|
||||||
|
|
||||||
|
def _coerce_translation(translation: object) -> TranslationColumn:
|
||||||
|
array = np.asarray(translation, dtype=np.float32)
|
||||||
|
if array.shape == (3,):
|
||||||
|
array = array[:, np.newaxis]
|
||||||
|
elif array.shape == (1, 3):
|
||||||
|
array = array.T
|
||||||
|
if array.shape != (3, 1):
|
||||||
|
raise ValueError("T must have shape [3], [1, 3], or [3, 1].")
|
||||||
|
return np.ascontiguousarray(array, dtype=np.float32)
|
||||||
|
|
||||||
|
|
||||||
def _coerce_depth_image(depth_image: DepthImageLike) -> npt.NDArray[np.float32]:
|
def _coerce_depth_image(depth_image: DepthImageLike) -> npt.NDArray[np.float32]:
|
||||||
array = np.asarray(depth_image, dtype=np.float32)
|
array = np.asarray(depth_image, dtype=np.float32)
|
||||||
if array.ndim == 3 and array.shape[-1] == 1:
|
if array.ndim == 3 and array.shape[-1] == 1:
|
||||||
@@ -99,12 +127,12 @@ def convert_cameras(cameras: Sequence[CameraLike]) -> list[Camera]:
|
|||||||
|
|
||||||
camera_model = _coerce_camera_model(cam.get("model", cam.get("type", "pinhole")))
|
camera_model = _coerce_camera_model(cam.get("model", cam.get("type", "pinhole")))
|
||||||
converted.append(
|
converted.append(
|
||||||
make_camera(
|
_make_camera(
|
||||||
str(cam["name"]),
|
str(cam["name"]),
|
||||||
cam["K"],
|
_coerce_matrix3x3(cam["K"], "K").tolist(),
|
||||||
_coerce_distortion(cam["DC"], camera_model),
|
_coerce_distortion(cam["DC"], camera_model),
|
||||||
cam["R"],
|
_coerce_matrix3x3(cam["R"], "R").tolist(),
|
||||||
cam["T"],
|
_coerce_translation(cam["T"]).tolist(),
|
||||||
int(cam["width"]),
|
int(cam["width"]),
|
||||||
int(cam["height"]),
|
int(cam["height"]),
|
||||||
camera_model,
|
camera_model,
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ def test_camera_structure_repr():
|
|||||||
[[1, 0, 0], [0, 1, 0], [0, 0, 1]],
|
[[1, 0, 0], [0, 1, 0], [0, 0, 1]],
|
||||||
[0, 0, 0, 0, 0],
|
[0, 0, 0, 0, 0],
|
||||||
[[1, 0, 0], [0, 1, 0], [0, 0, 1]],
|
[[1, 0, 0], [0, 1, 0], [0, 0, 1]],
|
||||||
[[1], [2], [3]],
|
[1, 2, 3],
|
||||||
640,
|
640,
|
||||||
480,
|
480,
|
||||||
rpt.CameraModel.PINHOLE,
|
rpt.CameraModel.PINHOLE,
|
||||||
@@ -65,6 +65,7 @@ def test_camera_structure_repr():
|
|||||||
rendered = repr(camera)
|
rendered = repr(camera)
|
||||||
assert "Camera 1" in rendered
|
assert "Camera 1" in rendered
|
||||||
assert "pinhole" in rendered
|
assert "pinhole" in rendered
|
||||||
|
np.testing.assert_allclose(np.asarray(camera.T, dtype=np.float32).reshape(3), [1.0, 2.0, 3.0])
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
|
||||||
|
def test_checked_in_core_stub_exists():
|
||||||
|
assert (ROOT / "src" / "rpt" / "_core.pyi").exists()
|
||||||
|
|
||||||
|
|
||||||
|
def test_checked_in_core_stub_matches_generated_stub():
|
||||||
|
generated_stub = ROOT / "build" / "bindings" / "rpt" / "_core.pyi"
|
||||||
|
if not generated_stub.exists():
|
||||||
|
pytest.skip("Build-generated nanobind stub is unavailable.")
|
||||||
|
|
||||||
|
checked_in_stub = ROOT / "src" / "rpt" / "_core.pyi"
|
||||||
|
assert checked_in_stub.read_text(encoding="utf-8") == generated_stub.read_text(encoding="utf-8")
|
||||||
@@ -6,6 +6,18 @@ resolution-markers = [
|
|||||||
"python_full_version < '3.11'",
|
"python_full_version < '3.11'",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "basedpyright"
|
||||||
|
version = "1.38.4"
|
||||||
|
source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "nodejs-wheel-binaries" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/08/b4/26cb812eaf8ab56909c792c005fe1690706aef6f21d61107639e46e9c54c/basedpyright-1.38.4.tar.gz", hash = "sha256:8e7d4f37ffb6106621e06b9355025009cdf5b48f71c592432dd2dd304bf55e70", size = 25354730, upload-time = "2026-03-25T13:50:44.353Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/62/0b/3f95fd47def42479e61077523d3752086d5c12009192a7f1c9fd5507e687/basedpyright-1.38.4-py3-none-any.whl", hash = "sha256:90aa067cf3e8a3c17ad5836a72b9e1f046bc72a4ad57d928473d9368c9cd07a2", size = 12352258, upload-time = "2026-03-25T13:50:41.059Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorama"
|
name = "colorama"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
@@ -36,6 +48,52 @@ wheels = [
|
|||||||
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
|
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jaxtyping"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" }
|
||||||
|
resolution-markers = [
|
||||||
|
"python_full_version < '3.11'",
|
||||||
|
]
|
||||||
|
dependencies = [
|
||||||
|
{ name = "wadler-lindig", marker = "python_full_version < '3.11'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/38/40/a2ea3ce0e3e5f540eb970de7792c90fa58fef1b27d34c83f9fa94fea4729/jaxtyping-0.3.7.tar.gz", hash = "sha256:3bd7d9beb7d3cb01a89f93f90581c6f4fff3e5c5dc3c9307e8f8687a040d10c4", size = 45721, upload-time = "2026-01-30T14:18:47.409Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/78/42/caf65e9a0576a3abadc537e2f831701ba9081f21317fb3be87d64451587a/jaxtyping-0.3.7-py3-none-any.whl", hash = "sha256:303ab8599edf412eeb40bf06c863e3168fa186cf0e7334703fa741ddd7046e66", size = 56101, upload-time = "2026-01-30T14:18:45.954Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jaxtyping"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" }
|
||||||
|
resolution-markers = [
|
||||||
|
"python_full_version >= '3.11'",
|
||||||
|
]
|
||||||
|
dependencies = [
|
||||||
|
{ name = "wadler-lindig", marker = "python_full_version >= '3.11'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c2/be/00294e369938937e31b094437d5ea040e4fd1a20b998ebe572c4a1dcfa68/jaxtyping-0.3.9.tar.gz", hash = "sha256:f8c02d1b623d5f1b6665d4f3ddaec675d70004f16a792102c2fc51264190951d", size = 45857, upload-time = "2026-02-16T10:35:13.263Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/94/05/3e39d416fb92b2738a76e8265e6bfc5d10542f90a7c32ad1eb831eea3fa3/jaxtyping-0.3.9-py3-none-any.whl", hash = "sha256:a00557a9d616eff157491f06ed2e21ed94886fad3832399273eb912b345da378", size = 56274, upload-time = "2026-02-16T10:35:11.795Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nodejs-wheel-binaries"
|
||||||
|
version = "24.14.0"
|
||||||
|
source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" }
|
||||||
|
sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/71/05/c75c0940b1ebf82975d14f37176679b6f3229eae8b47b6a70d1e1dae0723/nodejs_wheel_binaries-24.14.0.tar.gz", hash = "sha256:c87b515e44b0e4a523017d8c59f26ccbd05b54fe593338582825d4b51fc91e1c", size = 8057, upload-time = "2026-02-27T02:57:30.931Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/58/8c/b057c2db3551a6fe04e93dd14e33d810ac8907891534ffcc7a051b253858/nodejs_wheel_binaries-24.14.0-py2.py3-none-macosx_13_0_arm64.whl", hash = "sha256:59bb78b8eb08c3e32186da1ef913f1c806b5473d8bd0bb4492702092747b674a", size = 54798488, upload-time = "2026-02-27T02:56:56.831Z" },
|
||||||
|
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/30/88/7e1b29c067b6625c97c81eb8b0ef37cf5ad5b62bb81e23f4bde804910ec9/nodejs_wheel_binaries-24.14.0-py2.py3-none-macosx_13_0_x86_64.whl", hash = "sha256:348fa061b57625de7250d608e2d9b7c4bc170544da7e328325343860eadd59e5", size = 54972803, upload-time = "2026-02-27T02:57:01.696Z" },
|
||||||
|
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/1e/e0/a83f0ff12faca2a56366462e572e38ac6f5cb361877bb29e289138eb7f24/nodejs_wheel_binaries-24.14.0-py2.py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:222dbf516ccc877afcad4e4789a81b4ee93daaa9f0ad97c464417d9597f49449", size = 59340859, upload-time = "2026-02-27T02:57:06.125Z" },
|
||||||
|
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e2/9f/06fad4ae8a723ae7096b5311eba67ad8b4df5f359c0a68e366750b7fef78/nodejs_wheel_binaries-24.14.0-py2.py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:b35d6fcccfe4fb0a409392d237fbc67796bac0d357b996bc12d057a1531a238b", size = 59838751, upload-time = "2026-02-27T02:57:10.449Z" },
|
||||||
|
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/8c/72/4916dadc7307c3e9bcfa43b4b6f88237932d502c66f89eb2d90fb07810db/nodejs_wheel_binaries-24.14.0-py2.py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:519507fb74f3f2b296ab1e9f00dcc211f36bbfb93c60229e72dcdee9dafd301a", size = 61340534, upload-time = "2026-02-27T02:57:15.309Z" },
|
||||||
|
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/2e/df/a8ba881ee5d04b04e0d93abc8ce501ff7292813583e97f9789eb3fc0472a/nodejs_wheel_binaries-24.14.0-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:68c93c52ff06d704bcb5ed160b4ba04ab1b291d238aaf996b03a5396e0e9a7ed", size = 61922394, upload-time = "2026-02-27T02:57:20.24Z" },
|
||||||
|
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/60/8c/b8c5f61201c72a0c7dc694b459941f89a6defda85deff258a9940a4e2efc/nodejs_wheel_binaries-24.14.0-py2.py3-none-win_amd64.whl", hash = "sha256:60b83c4e98b0c7d836ac9ccb67dcb36e343691cbe62cd325799ff9ed936286f3", size = 41218783, upload-time = "2026-02-27T02:57:24.175Z" },
|
||||||
|
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/91/23/1f904bc9cbd8eece393e20840c08ba3ac03440090c3a4e95168fa6d2709f/nodejs_wheel_binaries-24.14.0-py2.py3-none-win_arm64.whl", hash = "sha256:78a9bd1d6b11baf1433f9fb84962ff8aa71c87d48b6434f98224bc49a2253a6e", size = 38926103, upload-time = "2026-02-27T02:57:27.458Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "numpy"
|
name = "numpy"
|
||||||
version = "2.2.6"
|
version = "2.2.6"
|
||||||
@@ -233,20 +291,29 @@ name = "rapid-pose-triangulation"
|
|||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
{ name = "jaxtyping", version = "0.3.7", source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" }, marker = "python_full_version < '3.11'" },
|
||||||
|
{ name = "jaxtyping", version = "0.3.9", source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" }, marker = "python_full_version >= '3.11'" },
|
||||||
{ name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" }, marker = "python_full_version < '3.11'" },
|
{ name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" }, marker = "python_full_version < '3.11'" },
|
||||||
{ name = "numpy", version = "2.4.3", source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" }, marker = "python_full_version >= '3.11'" },
|
{ name = "numpy", version = "2.4.3", source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" }, marker = "python_full_version >= '3.11'" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dev-dependencies]
|
[package.dev-dependencies]
|
||||||
dev = [
|
dev = [
|
||||||
|
{ name = "basedpyright" },
|
||||||
{ name = "pytest" },
|
{ name = "pytest" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [{ name = "numpy", specifier = ">=2.0" }]
|
requires-dist = [
|
||||||
|
{ name = "jaxtyping" },
|
||||||
|
{ name = "numpy", specifier = ">=2.0" },
|
||||||
|
]
|
||||||
|
|
||||||
[package.metadata.requires-dev]
|
[package.metadata.requires-dev]
|
||||||
dev = [{ name = "pytest", specifier = ">=8.3" }]
|
dev = [
|
||||||
|
{ name = "basedpyright", specifier = ">=1.38.3" },
|
||||||
|
{ name = "pytest", specifier = ">=8.3" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tomli"
|
name = "tomli"
|
||||||
@@ -310,3 +377,12 @@ sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/72/94/1a
|
|||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wadler-lindig"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" }
|
||||||
|
sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/1e/67/cbae4bf7683a64755c2c1778c418fea96d00e34395bb91743f08bd951571/wadler_lindig-0.1.7.tar.gz", hash = "sha256:81d14d3fe77d441acf3ebd7f4aefac20c74128bf460e84b512806dccf7b2cd55", size = 15842, upload-time = "2025-06-18T07:00:42.843Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/8d/96/04e7b441807b26b794da5b11e59ed7f83b2cf8af202bd7eba8ad2fa6046e/wadler_lindig-0.1.7-py3-none-any.whl", hash = "sha256:e3ec83835570fd0a9509f969162aeb9c65618f998b1f42918cfc8d45122fe953", size = 20516, upload-time = "2025-06-18T07:00:41.684Z" },
|
||||||
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user