├── .gitignore ├── LICENSE ├── README.md ├── flake.lock ├── flake.nix ├── pygraphslam.gif ├── pygraphslam_occupancy.gif ├── pyproject.toml ├── src ├── icp.py ├── pose_graph.py └── slam.py └── uv.lock /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | *.clf 3 | slam_*.gif 4 | .direnv 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Göktuğ Karakaşlı 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Python Implementation of Graph SLAM 2 | =================================== 3 | 4 | PyGraphSLAM is my basic implementation of graph SLAM in Python. 5 | 6 | ### GIF 7 | ![GIF](https://raw.githubusercontent.com/goktug97/PyGraphSLAM/master/pygraphslam.gif) 8 | 9 | ### Occupancy Map 10 | ![GIF](https://raw.githubusercontent.com/goktug97/PyGraphSLAM/master/pygraphslam_occupancy.gif) 11 | 12 | ### Usage 13 | You can download datasets from http://ais.informatik.uni-freiburg.de/slamevaluation/datasets.php 14 | 15 | ``` bash 16 | python -m src.slam --input intel.clf 17 | ``` 18 | 19 | - If you have nix: 20 | 21 | ```bash 22 | nix run . -- --input intel.clf 23 | ``` 24 | 25 | ### License 26 | PyGraphSLAM is licensed under the MIT License. 27 | 28 | -The `icp.py` is licensed under Apache License, Version 2.0 29 | 30 | Original version can be found here: https://github.com/ClayFlannigan/icp 31 | 32 | Modified icp to reject some pairs. 33 | 34 | ### Datasets 35 | http://ais.informatik.uni-freiburg.de/slamevaluation/datasets.php 36 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1731533236, 9 | "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", 10 | "owner": "numtide", 11 | "repo": "flake-utils", 12 | "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "numtide", 17 | "repo": "flake-utils", 18 | "type": "github" 19 | } 20 | }, 21 | "nixpkgs": { 22 | "locked": { 23 | "lastModified": 1740162160, 24 | "narHash": "sha256-SSYxFhqCOb3aiPb6MmN68yEzBIltfom8IgRz7phHscM=", 25 | "owner": "NixOS", 26 | "repo": "nixpkgs", 27 | "rev": "11415c7ae8539d6292f2928317ee7a8410b28bb9", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "owner": "NixOS", 32 | "ref": "nixos-24.11", 33 | "repo": "nixpkgs", 34 | "type": "github" 35 | } 36 | }, 37 | "pyproject-build-systems": { 38 | "inputs": { 39 | "nixpkgs": [ 40 | "nixpkgs" 41 | ], 42 | "pyproject-nix": [ 43 | "pyproject-nix" 44 | ], 45 | "uv2nix": [ 46 | "uv2nix" 47 | ] 48 | }, 49 | "locked": { 50 | "lastModified": 1739772638, 51 | "narHash": "sha256-SIO8QetyYvx/BoCM+4PvYkd4sitMv9sfWf63ePlaN6o=", 52 | "owner": "pyproject-nix", 53 | "repo": "build-system-pkgs", 54 | "rev": "53700950d05fc2dd67228277ff1729964d2e7ffd", 55 | "type": "github" 56 | }, 57 | "original": { 58 | "owner": "pyproject-nix", 59 | "repo": "build-system-pkgs", 60 | "type": "github" 61 | } 62 | }, 63 | "pyproject-nix": { 64 | "inputs": { 65 | "nixpkgs": [ 66 | "nixpkgs" 67 | ] 68 | }, 69 | "locked": { 70 | "lastModified": 1739758351, 71 | "narHash": "sha256-Aoa4dEoC7Hf6+gFVk/SDquZTMFlmlfsgdTWuqQxzePs=", 72 | "owner": "pyproject-nix", 73 | "repo": "pyproject.nix", 74 | "rev": "1329712f7f9af3a8b270764ba338a455b7323811", 75 | "type": "github" 76 | }, 77 | "original": { 78 | "owner": "pyproject-nix", 79 | "repo": "pyproject.nix", 80 | "type": "github" 81 | } 82 | }, 83 | "root": { 84 | "inputs": { 85 | "flake-utils": "flake-utils", 86 | "nixpkgs": "nixpkgs", 87 | "pyproject-build-systems": "pyproject-build-systems", 88 | "pyproject-nix": "pyproject-nix", 89 | "uv2nix": "uv2nix" 90 | } 91 | }, 92 | "systems": { 93 | "locked": { 94 | "lastModified": 1681028828, 95 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 96 | "owner": "nix-systems", 97 | "repo": "default", 98 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 99 | "type": "github" 100 | }, 101 | "original": { 102 | "owner": "nix-systems", 103 | "repo": "default", 104 | "type": "github" 105 | } 106 | }, 107 | "uv2nix": { 108 | "inputs": { 109 | "nixpkgs": [ 110 | "nixpkgs" 111 | ], 112 | "pyproject-nix": [ 113 | "pyproject-nix" 114 | ] 115 | }, 116 | "locked": { 117 | "lastModified": 1740210290, 118 | "narHash": "sha256-VXtF9oZsCmdSsRQjBOm5o0GLYE8Pp5rl7uYK+zV5a0c=", 119 | "owner": "pyproject-nix", 120 | "repo": "uv2nix", 121 | "rev": "846ad27167bf6a855c56753ba8360759bfb6f456", 122 | "type": "github" 123 | }, 124 | "original": { 125 | "owner": "pyproject-nix", 126 | "repo": "uv2nix", 127 | "type": "github" 128 | } 129 | } 130 | }, 131 | "root": "root", 132 | "version": 7 133 | } 134 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Python implementation of Graph SLAM"; 3 | 4 | inputs = { 5 | flake-utils.url = "github:numtide/flake-utils"; 6 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11"; 7 | 8 | pyproject-nix = { 9 | url = "github:pyproject-nix/pyproject.nix"; 10 | inputs.nixpkgs.follows = "nixpkgs"; 11 | }; 12 | 13 | uv2nix = { 14 | url = "github:pyproject-nix/uv2nix"; 15 | inputs.pyproject-nix.follows = "pyproject-nix"; 16 | inputs.nixpkgs.follows = "nixpkgs"; 17 | }; 18 | 19 | pyproject-build-systems = { 20 | url = "github:pyproject-nix/build-system-pkgs"; 21 | inputs.pyproject-nix.follows = "pyproject-nix"; 22 | inputs.uv2nix.follows = "uv2nix"; 23 | inputs.nixpkgs.follows = "nixpkgs"; 24 | }; 25 | 26 | }; 27 | 28 | outputs = 29 | { 30 | self, 31 | nixpkgs, 32 | flake-utils, 33 | uv2nix, 34 | pyproject-nix, 35 | pyproject-build-systems, 36 | }: 37 | flake-utils.lib.eachDefaultSystem ( 38 | system: 39 | let 40 | pkgs = nixpkgs.legacyPackages.${system}; 41 | 42 | workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; }; 43 | 44 | overlay = workspace.mkPyprojectOverlay { sourcePreference = "wheel"; }; 45 | 46 | python = pkgs.python312; 47 | pythonPackages = pkgs.python312Packages; 48 | 49 | pyprojectOverrides = final: prev: { 50 | g2o-python = prev.g2o-python.overrideAttrs { 51 | env = prev.g2o-python.env or { } // { 52 | GIT_CONFIG_COUNT = 1; 53 | GIT_CONFIG_KEY_0 = "url.https://github.com/.insteadOf"; 54 | GIT_CONFIG_VALUE_0 = "git@github.com:"; 55 | }; 56 | 57 | postPatch = '' 58 | substituteInPlace g2o/python/CMakeLists.txt \ 59 | --replace-fail "FetchContent_MakeAvailable(pybind11)" \ 60 | "find_package(pybind11 REQUIRED)" 61 | ''; 62 | 63 | preFixup = '' 64 | echo 'post install' 65 | for lib in $out/${final.python.sitePackages}/*/*.so; do 66 | patchelf --add-rpath "$out/lib64" "$lib" 67 | done 68 | ''; 69 | 70 | dontUseCmakeConfigure = true; 71 | 72 | nativeBuildInputs = 73 | prev.g2o-python.nativeBuildInputs 74 | ++ [ 75 | (final.resolveBuildSystem { 76 | setuptools = [ ]; 77 | scikit-build = [ ]; 78 | cmake = [ ]; 79 | ninja = [ ]; 80 | }) 81 | ] 82 | ++ [ 83 | pkgs.spdlog 84 | pkgs.eigen 85 | pkgs.suitesparse 86 | pythonPackages.pybind11 87 | pkgs.patchelf 88 | ]; 89 | }; 90 | 91 | raylib = prev.raylib.overrideAttrs { 92 | postFixup = '' 93 | for lib in $out/${final.python.sitePackages}/*/*.so; do 94 | patchelf $lib --add-rpath ${ 95 | pkgs.lib.makeLibraryPath [ 96 | pkgs.xorg.libX11 97 | pkgs.xorg.libXcursor 98 | pkgs.xorg.libXi 99 | pkgs.xorg.libXrandr 100 | pkgs.wayland 101 | pkgs.libxkbcommon 102 | pkgs.libGL 103 | ] 104 | } 105 | done 106 | ''; 107 | }; 108 | }; 109 | 110 | pythonSet = 111 | (pkgs.callPackage pyproject-nix.build.packages { 112 | inherit python; 113 | stdenv = pkgs.stdenv.override { 114 | targetPlatform = pkgs.stdenv.targetPlatform // { 115 | darwinSdkVersion = "15.1"; 116 | }; 117 | }; 118 | }).overrideScope 119 | ( 120 | pkgs.lib.composeManyExtensions [ 121 | pyproject-build-systems.overlays.default 122 | overlay 123 | pyprojectOverrides 124 | ] 125 | ); 126 | 127 | venv = pythonSet.mkVirtualEnv "pygraph-env" workspace.deps.default; 128 | in 129 | { 130 | packages = { 131 | default = pkgs.writeShellApplication { 132 | name = "pygraph"; 133 | text = '' 134 | exec ${venv}/bin/python -m src.slam "$@" 135 | ''; 136 | }; 137 | }; 138 | 139 | devShells.default = 140 | let 141 | editableOverlay = workspace.mkEditablePyprojectOverlay { 142 | root = "$REPO_ROOT"; 143 | members = [ "pygraphslam" ]; 144 | }; 145 | 146 | editablePythonSet = pythonSet.overrideScope ( 147 | pkgs.lib.composeManyExtensions [ 148 | editableOverlay 149 | 150 | (final: prev: { 151 | pygraph = prev.pygraph.overrideAttrs (old: { 152 | src = pkgs.lib.fileset.toSource { 153 | root = old.src; 154 | fileset = pkgs.lib.fileset.unions [ 155 | (old.src + "/pyproject.toml") 156 | (old.src + "/README.md") 157 | ]; 158 | }; 159 | 160 | nativeBuildInputs = old.nativeBuildInputs ++ final.resolveBuildSystem { editables = [ ]; }; 161 | }); 162 | }) 163 | ] 164 | ); 165 | 166 | virtualenv = editablePythonSet.mkVirtualEnv "pygraph-dev-env" workspace.deps.all; 167 | in 168 | pkgs.mkShell { 169 | packages = [ 170 | virtualenv 171 | pythonPackages.uv 172 | pythonPackages.ruff 173 | pythonPackages.python-lsp-server 174 | pkgs.glfw 175 | ]; 176 | 177 | env = { 178 | UV_NO_SYNC = "1"; 179 | UV_PYTHON = "${virtualenv}/bin/python"; 180 | UV_PYTHON_DOWNLOADS = "never"; 181 | }; 182 | 183 | shellHook = '' 184 | unset PYTHONPATH 185 | export REPO_ROOT=$(git rev-parse --show-toplevel) 186 | ''; 187 | }; 188 | } 189 | ); 190 | } 191 | -------------------------------------------------------------------------------- /pygraphslam.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goktug97/PyGraphSLAM/f8c808a8a70a007a82a3d48896deb79abc246b0d/pygraphslam.gif -------------------------------------------------------------------------------- /pygraphslam_occupancy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goktug97/PyGraphSLAM/f8c808a8a70a007a82a3d48896deb79abc246b0d/pygraphslam_occupancy.gif -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "pygraphslam" 3 | version = "0.1.0" 4 | description = "Python implementation of Graph SLAM" 5 | readme = "README.md" 6 | requires-python = ">=3.11" 7 | 8 | dependencies = [ 9 | "numpy>=2.2.2", 10 | "scikit-learn>=1.6.1", 11 | "scipy>=1.15.1", 12 | "g2o-python", 13 | "raylib>=5.5.0.2", 14 | "scikit-image>=0.25.2", 15 | ] 16 | 17 | [dependency-groups] 18 | dev = [ 19 | "scikit-build>=0.18.1", 20 | "setuptools>=75.8.0", 21 | ] 22 | 23 | [tool.uv.sources] 24 | g2o-python = { git = "https://github.com/miquelmassot/g2o-python", rev="d761ee9" } 25 | -------------------------------------------------------------------------------- /src/icp.py: -------------------------------------------------------------------------------- 1 | # Original code: https://github.com/ClayFlannigan/icp 2 | # Modifications: 3 | # Reject pairs that have greater distance than 1 meters 4 | # Weights https://arxiv.org/abs/2007.07627 5 | # Handle different length scans 6 | 7 | import numpy as np 8 | from sklearn.neighbors import NearestNeighbors 9 | 10 | 11 | def welsch_weight(weights, p=0.4): 12 | return np.exp(-weights * weights / (2 * np.square(p))) 13 | 14 | 15 | def best_fit_transform(A, B): 16 | """ 17 | Calculates the least-squares best-fit transform that maps corresponding points A to B in m spatial dimensions 18 | Input: 19 | A: Nxm numpy array of corresponding points 20 | B: Nxm numpy array of corresponding points 21 | Returns: 22 | T: (m+1)x(m+1) homogeneous transformation matrix that maps A on to B 23 | R: mxm rotation matrix 24 | t: mx1 translation vector 25 | """ 26 | 27 | assert A.shape == B.shape 28 | 29 | weights = np.linalg.norm(A - B, axis=1) 30 | weights = welsch_weight(weights) 31 | 32 | # get number of dimensions 33 | m = A.shape[1] 34 | 35 | # translate points to their centroids 36 | centroid_A = np.mean(A, axis=0) 37 | centroid_B = np.mean(B, axis=0) 38 | AA = A - centroid_A 39 | BB = B - centroid_B 40 | 41 | # rotation matrix 42 | H = np.dot(AA.T * weights, BB) 43 | U, S, Vt = np.linalg.svd(H) 44 | R = np.dot(Vt.T, U.T) 45 | 46 | # special reflection case 47 | if np.linalg.det(R) < 0: 48 | Vt[m - 1, :] *= -1 49 | R = np.dot(Vt.T, U.T) 50 | 51 | # translation 52 | t = centroid_B.T - np.dot(R, centroid_A.T) 53 | 54 | # homogeneous transformation 55 | T = np.identity(m + 1) 56 | T[:m, :m] = R 57 | T[:m, m] = t 58 | 59 | return T, R, t 60 | 61 | 62 | def nearest_neighbor(src, dst): 63 | """ 64 | Find the nearest (Euclidean) neighbor in dst for each point in src 65 | Input: 66 | src: Nxm array of points 67 | dst: Nxm array of points 68 | Output: 69 | distances: Euclidean distances of the nearest neighbor 70 | indices: dst indices of the nearest neighbor 71 | """ 72 | 73 | neigh = NearestNeighbors(n_neighbors=1) 74 | neigh.fit(dst) 75 | distances, indices = neigh.kneighbors(src, return_distance=True) 76 | return distances.ravel(), indices.ravel() 77 | 78 | 79 | def icp(A, B, init_pose=None, max_iterations=20, tolerance=0.001): 80 | """ 81 | The Iterative Closest Point method: finds best-fit transform that maps points A on to points B 82 | Input: 83 | A: Nxm numpy array of source mD points 84 | B: Nxm numpy array of destination mD point 85 | init_pose: (m+1)x(m+1) homogeneous transformation 86 | max_iterations: exit algorithm after max_iterations 87 | tolerance: convergence criteria 88 | Output: 89 | T: final homogeneous transformation that maps A on to B 90 | distances: Euclidean distances (errors) of the nearest neighbor 91 | i: number of iterations to converge 92 | """ 93 | 94 | # get number of dimensions 95 | m = A.shape[1] 96 | 97 | # make points homogeneous, copy them to maintain the originals 98 | src = np.ones((m + 1, A.shape[0])) 99 | dst = np.ones((m + 1, B.shape[0])) 100 | src[:m, :] = np.copy(A.T) 101 | dst[:m, :] = np.copy(B.T) 102 | 103 | T_acc = init_pose if init_pose is not None else np.identity(m + 1) 104 | src = np.dot(T_acc, src) 105 | 106 | prev_error = 0 107 | 108 | for i in range(max_iterations): 109 | distances, indices = nearest_neighbor(src.T, dst.T) 110 | 111 | # Reject pairs that have more than 1 meter distance between them 112 | close_match_mask = distances < 1.0 113 | 114 | # Need at least 3 points for a meaningful transform 115 | if np.sum(close_match_mask) < 3: 116 | continue 117 | 118 | matched_src = src[:m, close_match_mask].T 119 | matched_dst = dst[:m, indices[close_match_mask]].T 120 | 121 | T, _, _ = best_fit_transform(matched_src, matched_dst) 122 | 123 | # update the current source 124 | src = np.dot(T, src) 125 | 126 | T_acc = np.dot(T, T_acc) 127 | 128 | # check error 129 | mean_error = np.mean(distances[close_match_mask]) 130 | if np.abs(prev_error - mean_error) < tolerance: 131 | break 132 | prev_error = mean_error 133 | 134 | return T_acc, distances, i 135 | -------------------------------------------------------------------------------- /src/pose_graph.py: -------------------------------------------------------------------------------- 1 | import g2o 2 | import numpy as np 3 | 4 | 5 | class PoseGraphOptimization(g2o.SparseOptimizer): 6 | def __init__(self): 7 | super().__init__() 8 | solver = g2o.BlockSolverSE2(g2o.LinearSolverCholmodSE2()) 9 | solver = g2o.OptimizationAlgorithmLevenberg(solver) 10 | super().set_algorithm(solver) 11 | 12 | def optimize(self, max_iterations=20): 13 | super().initialize_optimization() 14 | super().optimize(max_iterations) 15 | 16 | def add_vertex(self, id, pose, fixed=False): 17 | v_se2 = g2o.VertexSE2() 18 | v_se2.set_id(id) 19 | v_se2.set_estimate(pose) 20 | v_se2.set_fixed(fixed) 21 | super().add_vertex(v_se2) 22 | 23 | def add_edge( 24 | self, vertices, measurement, information=np.identity(3), robust_kernel=None 25 | ): 26 | edge = g2o.EdgeSE2() 27 | for i, v in enumerate(vertices): 28 | if isinstance(v, int): 29 | v = self.vertex(v) 30 | edge.set_vertex(i, v) 31 | 32 | edge.set_measurement(measurement) 33 | edge.set_information(information) 34 | if robust_kernel is not None: 35 | edge.set_robust_kernel(robust_kernel) 36 | super().add_edge(edge) 37 | 38 | def get_pose(self, id): 39 | return self.vertex(id).estimate() 40 | -------------------------------------------------------------------------------- /src/slam.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import argparse 4 | import heapq 5 | import itertools 6 | import time 7 | from dataclasses import dataclass, field 8 | from pathlib import Path 9 | 10 | import g2o 11 | import numpy as np 12 | import pyray 13 | import raylib 14 | import skimage 15 | from numpy.typing import NDArray 16 | 17 | import icp 18 | import pose_graph 19 | 20 | 21 | @dataclass 22 | class Laser: 23 | angle_min: float 24 | angle_max: float 25 | angle_increment: float 26 | max_distance: float 27 | distances: list[float] | NDArray[float] 28 | 29 | 30 | @dataclass 31 | class Odometry: 32 | transform: NDArray[float] 33 | 34 | 35 | @dataclass 36 | class Reading: 37 | data: Laser | Odometry 38 | timestamp: float = field(default_factory=time.time) 39 | 40 | def __eq__(self, other): 41 | self.timestamp == other.timestamp 42 | 43 | def __lt__(self, other): 44 | self.timestamp < other.timestamp 45 | 46 | def __le__(self, other): 47 | (self < other) or (self == other) 48 | 49 | def __gt__(self, other): 50 | other < self 51 | 52 | def __ge__(self, other): 53 | other <= self 54 | 55 | 56 | class SLAM: 57 | def __init__(self): 58 | self.optimizer = pose_graph.PoseGraphOptimization() 59 | self.vertex_counter = itertools.count(0) 60 | self.prev_odom = g2o.SE2(g2o.Isometry2d(np.eye(3))) 61 | self.optimizer.add_vertex(next(self.vertex_counter), self.prev_odom, True) 62 | self.last_vertex_idx = 0 63 | self.registered_scans = dict() 64 | 65 | def add_reading(self, reading: Reading): 66 | data = reading.data 67 | 68 | cleanup = False 69 | 70 | if isinstance(data, Laser): 71 | angles = np.arange(data.angle_min, data.angle_max, data.angle_increment) 72 | positions = ( 73 | np.array([np.cos(angles), np.sin(angles)]).T 74 | * data.distances[:, np.newaxis] 75 | ) 76 | mask = np.linalg.norm(positions, axis=1) < data.max_distance 77 | positions = positions[mask] 78 | 79 | if not len(self.registered_scans): 80 | self.registered_scans[self.last_vertex_idx] = positions 81 | return 82 | 83 | prev_idx = next(reversed(self.registered_scans.keys())) 84 | prev_scan = self.registered_scans[prev_idx] 85 | prev_pose = self.optimizer.get_pose(prev_idx) 86 | current_pose = self.optimizer.get_pose(self.last_vertex_idx) 87 | transform = prev_pose.inverse() * current_pose 88 | if ( 89 | np.linalg.norm(transform.translation()) > 0.4 90 | or abs(transform.rotation().angle()) > 0.2 91 | ): 92 | transformation, distances, iter = icp.icp( 93 | positions, 94 | prev_scan, 95 | transform.to_isometry().matrix(), 96 | max_iterations=80, 97 | tolerance=0.00001, 98 | ) 99 | self.optimizer.add_edge( 100 | [prev_idx, self.last_vertex_idx], 101 | g2o.SE2(g2o.Isometry2d(transformation)), 102 | # TODO: How to calculate information matrix? 103 | information=100.0 / np.mean(distances) * np.eye(3), 104 | ) 105 | self.registered_scans[self.last_vertex_idx] = positions 106 | cleanup = True 107 | 108 | # Loop closure only makes sense if the last reading is a valid laser scan 109 | self.loop_closure() 110 | 111 | elif isinstance(data, Odometry): 112 | current_odom = g2o.SE2(g2o.Isometry2d(data.transform)) 113 | transform = self.prev_odom.inverse() * current_odom 114 | 115 | if (np.linalg.norm(transform.translation()) < np.finfo(float).eps) and ( 116 | transform.rotation().angle() < np.finfo(float).eps 117 | ): 118 | return 119 | 120 | vertex_idx = next(self.vertex_counter) 121 | assert data.transform.shape == (3, 3) 122 | self.optimizer.add_vertex(vertex_idx, current_odom) 123 | self.optimizer.add_edge( 124 | [vertex_idx - 1, vertex_idx], 125 | transform, 126 | information=np.eye(3), 127 | ) 128 | self.last_vertex_idx = vertex_idx 129 | self.prev_odom = current_odom 130 | else: 131 | raise ValueError(f"Unknown data type: {type(data)}") 132 | 133 | if self.last_vertex_idx > 1: 134 | # self.optimizer.set_verbose(True) 135 | self.optimizer.optimize() 136 | 137 | if cleanup: 138 | keys = reversed(self.registered_scans.keys()) 139 | end = next(keys) 140 | start = next(keys) 141 | for vertex_idx in range(start + 1, end): 142 | self.optimizer.remove_vertex(self.optimizer.vertex(vertex_idx)) 143 | 144 | def loop_closure(self): 145 | if len(self.registered_scans) < 2: 146 | return 147 | 148 | scans = enumerate(reversed(self.registered_scans.items())) 149 | scan_idx, (current_idx, current_scan) = next(scans) 150 | assert current_idx == self.last_vertex_idx 151 | current_pose = self.optimizer.get_pose(current_idx) 152 | 153 | for prev_scan_idx, (prev_idx, prev_scan) in scans: 154 | if prev_scan_idx - scan_idx < 10: 155 | # Too recent 156 | continue 157 | 158 | vertex = self.optimizer.vertex(prev_idx) 159 | inv_hessian, valid = self.optimizer.compute_marginals(vertex) 160 | 161 | if not valid: 162 | continue 163 | 164 | prev_pose = vertex.estimate() 165 | position_diff = (prev_pose.inverse() * current_pose).translation() 166 | 167 | for index, block in enumerate(inv_hessian.block_cols()): 168 | if block: 169 | cov = block[index] 170 | break 171 | 172 | cov = np.linalg.inv(cov) 173 | position_cov = cov[:2, :2] 174 | 175 | mahalanobis_dist = np.sqrt( 176 | position_diff.T @ np.linalg.inv(position_cov) @ position_diff 177 | ) 178 | 179 | if mahalanobis_dist < 3: 180 | transformation, distances, iter = icp.icp( 181 | prev_scan, 182 | current_scan, 183 | (prev_pose.inverse() * current_pose).to_isometry().matrix(), 184 | max_iterations=80, 185 | tolerance=0.0001, 186 | ) 187 | 188 | if len(distances) and np.mean(distances) < 0.15: 189 | rk = g2o.RobustKernelDCS(10) 190 | self.optimizer.add_edge( 191 | [current_idx, prev_idx], 192 | g2o.SE2(g2o.Isometry2d(transformation)), 193 | robust_kernel=rk, 194 | information=0.1 / np.mean(distances) * np.eye(3), 195 | ) 196 | 197 | 198 | def homogeneous_transform(vector): 199 | x, y, theta = vector 200 | return np.array( 201 | [ 202 | [np.cos(theta), -np.sin(theta), x], 203 | [np.sin(theta), np.cos(theta), y], 204 | [0.0, 0.0, 1.0], 205 | ] 206 | ) 207 | 208 | 209 | def load_clf_from_file(clf_file: Path): 210 | with clf_file.open() as f: 211 | readings = [] 212 | for line in f: 213 | tokens = line.split(" ") 214 | if tokens[0] == "FLASER": 215 | num_readings = int(tokens[1]) 216 | scans = np.array(tokens[2 : 2 + num_readings], dtype=float) 217 | timestamp = float(tokens[8 + num_readings]) 218 | 219 | heapq.heappush( 220 | readings, 221 | Reading( 222 | data=Laser( 223 | angle_min=-np.pi / 2, 224 | angle_max=np.pi / 2, 225 | angle_increment=np.pi / num_readings, 226 | max_distance=80, 227 | distances=scans, 228 | ), 229 | timestamp=timestamp, 230 | ), 231 | ) 232 | elif tokens[0] == "ODOM": 233 | x = float(tokens[1]) 234 | y = float(tokens[2]) 235 | theta = float(tokens[3]) 236 | timestamp = float(tokens[7]) 237 | heapq.heappush( 238 | readings, 239 | Reading( 240 | data=Odometry(transform=homogeneous_transform([x, y, theta])), 241 | timestamp=timestamp, 242 | ), 243 | ) 244 | 245 | return readings 246 | 247 | 248 | parser = argparse.ArgumentParser(description="Python Graph SLAM") 249 | parser.add_argument("--input", type=Path, help="Input CLF File.", required=True) 250 | args = parser.parse_args() 251 | 252 | raylib.InitWindow(800, 800, b"Python Graph SLAM") 253 | raylib.SetExitKey(pyray.KEY_Q) 254 | 255 | camera = pyray.Camera3D( 256 | (0.0, 0.0, 10.0), 257 | (0.0, 0.0, 0.0), 258 | (0.0, 1.0, 0.0), 259 | 45.0, 260 | pyray.CAMERA_PERSPECTIVE, 261 | ) 262 | 263 | resolution = 0.1 264 | width = 200 265 | height = 200 266 | occupancy_model = pyray.load_model_from_mesh(pyray.gen_mesh_plane(width, height, 1, 1)) 267 | image = pyray.Image() 268 | image.width = int(width / resolution) 269 | image.height = int(height / resolution) 270 | image.mipmaps = 1 271 | image.format = pyray.PIXELFORMAT_UNCOMPRESSED_GRAYSCALE 272 | occupancy_update_interval = 50 273 | texture = raylib.LoadTextureFromImage(image) 274 | pyray.set_material_texture( 275 | occupancy_model.materials[0], 276 | pyray.MATERIAL_MAP_DIFFUSE, 277 | texture, 278 | ) 279 | grid = np.zeros((int(height / resolution), int(width / resolution))) 280 | 281 | slam = SLAM() 282 | 283 | for idx, reading in enumerate(load_clf_from_file(args.input)): 284 | slam.add_reading(reading) 285 | 286 | raylib.BeginDrawing() 287 | raylib.ClearBackground(pyray.WHITE) 288 | 289 | pyray.begin_mode_3d(camera) 290 | pyray.update_camera(camera, pyray.CAMERA_THIRD_PERSON) 291 | 292 | prev_pose = None 293 | if not (idx % occupancy_update_interval): 294 | grid = np.zeros((int(height / resolution), int(width / resolution))) 295 | 296 | for vertex_idx, scan in slam.registered_scans.items(): 297 | pose = slam.optimizer.get_pose(vertex_idx) 298 | rotation_matrix = pose.rotation().rotation_matrix() 299 | translation = pose.translation() 300 | scan = (rotation_matrix @ scan.T + translation[:, np.newaxis]).T 301 | for point in scan: 302 | # Draw point cloud 303 | # raylib.DrawPoint3D( 304 | # (point[0], 0.1, point[1]), 305 | # pyray.BLUE, 306 | # ) 307 | 308 | # Build occupancy map 309 | if not (idx % occupancy_update_interval): 310 | line = list( 311 | zip( 312 | *skimage.draw.line( 313 | int(translation[1] / resolution + height / resolution / 2), 314 | int(translation[0] / resolution + width / resolution / 2), 315 | int(point[1] / resolution + height / resolution / 2), 316 | int(point[0] / resolution + width / resolution / 2), 317 | ) 318 | ) 319 | ) 320 | 321 | grid[line[-1]] += np.log10(0.7 / 0.3) 322 | for pos in line[:-1]: 323 | grid[pos] += np.log10(0.3 / 0.7) 324 | 325 | if prev_pose: 326 | # Draw trajectory 327 | prev_translation = prev_pose.translation() 328 | raylib.DrawLine3D( 329 | (prev_translation[0], 0.1, prev_translation[1]), 330 | (translation[0], 0.1, translation[1]), 331 | pyray.RED, 332 | ) 333 | 334 | prev_pose = pose 335 | 336 | if not (idx % occupancy_update_interval): 337 | gridp = (255 - 255 / (1 + np.exp(-grid))).astype(np.uint8) 338 | raylib.UpdateTexture(texture, pyray.ffi.from_buffer(gridp.data)) 339 | 340 | # Draw occupancy map 341 | pyray.draw_model(occupancy_model, (0.0, 0.0, 0.0), 1.0, pyray.WHITE) 342 | 343 | # Draw robot position 344 | size = 0.3 345 | pose = slam.optimizer.get_pose(slam.last_vertex_idx) 346 | transform_matrix = pose.to_isometry().matrix() 347 | tip = transform_matrix @ np.array([size, 0.0, 1.0]) 348 | left = transform_matrix @ np.array([-size * 0.5, -size * 0.5, 1.0]) 349 | right = transform_matrix @ np.array([-size * 0.5, size * 0.5, 1.0]) 350 | raylib.DrawTriangle3D( 351 | (tip[0], 0.1, tip[1]), 352 | (left[0], 0.1, left[1]), 353 | (right[0], 0.1, right[1]), 354 | pyray.RED, 355 | ) 356 | 357 | # raylib.DrawGrid(50, 1.0) 358 | raylib.EndMode3D() 359 | raylib.EndDrawing() 360 | 361 | 362 | pyray.close_window() 363 | -------------------------------------------------------------------------------- /uv.lock: -------------------------------------------------------------------------------- 1 | version = 1 2 | requires-python = ">=3.11" 3 | 4 | [[package]] 5 | name = "cffi" 6 | version = "1.17.1" 7 | source = { registry = "https://pypi.org/simple" } 8 | dependencies = [ 9 | { name = "pycparser" }, 10 | ] 11 | sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } 12 | wheels = [ 13 | { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264 }, 14 | { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651 }, 15 | { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259 }, 16 | { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200 }, 17 | { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235 }, 18 | { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721 }, 19 | { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242 }, 20 | { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999 }, 21 | { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242 }, 22 | { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604 }, 23 | { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727 }, 24 | { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400 }, 25 | { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178 }, 26 | { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840 }, 27 | { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 }, 28 | { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 }, 29 | { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 }, 30 | { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256 }, 31 | { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 }, 32 | { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 }, 33 | { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 }, 34 | { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 }, 35 | { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 }, 36 | { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 }, 37 | { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 }, 38 | { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 }, 39 | { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 }, 40 | { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 }, 41 | { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 }, 42 | { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 }, 43 | { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 }, 44 | { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 }, 45 | { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 }, 46 | { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 }, 47 | ] 48 | 49 | [[package]] 50 | name = "distro" 51 | version = "1.9.0" 52 | source = { registry = "https://pypi.org/simple" } 53 | sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722 } 54 | wheels = [ 55 | { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 }, 56 | ] 57 | 58 | [[package]] 59 | name = "g2o-python" 60 | version = "0.0.15" 61 | source = { git = "https://github.com/miquelmassot/g2o-python?rev=d761ee9#d761ee9f5734e6c69022822e733c01ecb8ad376f" } 62 | dependencies = [ 63 | { name = "numpy" }, 64 | { name = "scikit-build" }, 65 | { name = "scipy" }, 66 | ] 67 | 68 | [[package]] 69 | name = "imageio" 70 | version = "2.37.0" 71 | source = { registry = "https://pypi.org/simple" } 72 | dependencies = [ 73 | { name = "numpy" }, 74 | { name = "pillow" }, 75 | ] 76 | sdist = { url = "https://files.pythonhosted.org/packages/0c/47/57e897fb7094afb2d26e8b2e4af9a45c7cf1a405acdeeca001fdf2c98501/imageio-2.37.0.tar.gz", hash = "sha256:71b57b3669666272c818497aebba2b4c5f20d5b37c81720e5e1a56d59c492996", size = 389963 } 77 | wheels = [ 78 | { url = "https://files.pythonhosted.org/packages/cb/bd/b394387b598ed84d8d0fa90611a90bee0adc2021820ad5729f7ced74a8e2/imageio-2.37.0-py3-none-any.whl", hash = "sha256:11efa15b87bc7871b61590326b2d635439acc321cf7f8ce996f812543ce10eed", size = 315796 }, 79 | ] 80 | 81 | [[package]] 82 | name = "joblib" 83 | version = "1.4.2" 84 | source = { registry = "https://pypi.org/simple" } 85 | sdist = { url = "https://files.pythonhosted.org/packages/64/33/60135848598c076ce4b231e1b1895170f45fbcaeaa2c9d5e38b04db70c35/joblib-1.4.2.tar.gz", hash = "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e", size = 2116621 } 86 | wheels = [ 87 | { url = "https://files.pythonhosted.org/packages/91/29/df4b9b42f2be0b623cbd5e2140cafcaa2bef0759a00b7b70104dcfe2fb51/joblib-1.4.2-py3-none-any.whl", hash = "sha256:06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6", size = 301817 }, 88 | ] 89 | 90 | [[package]] 91 | name = "lazy-loader" 92 | version = "0.4" 93 | source = { registry = "https://pypi.org/simple" } 94 | dependencies = [ 95 | { name = "packaging" }, 96 | ] 97 | sdist = { url = "https://files.pythonhosted.org/packages/6f/6b/c875b30a1ba490860c93da4cabf479e03f584eba06fe5963f6f6644653d8/lazy_loader-0.4.tar.gz", hash = "sha256:47c75182589b91a4e1a85a136c074285a5ad4d9f39c63e0d7fb76391c4574cd1", size = 15431 } 98 | wheels = [ 99 | { url = "https://files.pythonhosted.org/packages/83/60/d497a310bde3f01cb805196ac61b7ad6dc5dcf8dce66634dc34364b20b4f/lazy_loader-0.4-py3-none-any.whl", hash = "sha256:342aa8e14d543a154047afb4ba8ef17f5563baad3fc610d7b15b213b0f119efc", size = 12097 }, 100 | ] 101 | 102 | [[package]] 103 | name = "networkx" 104 | version = "3.4.2" 105 | source = { registry = "https://pypi.org/simple" } 106 | sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368 } 107 | wheels = [ 108 | { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263 }, 109 | ] 110 | 111 | [[package]] 112 | name = "numpy" 113 | version = "2.2.3" 114 | source = { registry = "https://pypi.org/simple" } 115 | sdist = { url = "https://files.pythonhosted.org/packages/fb/90/8956572f5c4ae52201fdec7ba2044b2c882832dcec7d5d0922c9e9acf2de/numpy-2.2.3.tar.gz", hash = "sha256:dbdc15f0c81611925f382dfa97b3bd0bc2c1ce19d4fe50482cb0ddc12ba30020", size = 20262700 } 116 | wheels = [ 117 | { url = "https://files.pythonhosted.org/packages/96/86/453aa3949eab6ff54e2405f9cb0c01f756f031c3dc2a6d60a1d40cba5488/numpy-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:16372619ee728ed67a2a606a614f56d3eabc5b86f8b615c79d01957062826ca8", size = 21237256 }, 118 | { url = "https://files.pythonhosted.org/packages/20/c3/93ecceadf3e155d6a9e4464dd2392d8d80cf436084c714dc8535121c83e8/numpy-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5521a06a3148686d9269c53b09f7d399a5725c47bbb5b35747e1cb76326b714b", size = 14408049 }, 119 | { url = "https://files.pythonhosted.org/packages/8d/29/076999b69bd9264b8df5e56f2be18da2de6b2a2d0e10737e5307592e01de/numpy-2.2.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:7c8dde0ca2f77828815fd1aedfdf52e59071a5bae30dac3b4da2a335c672149a", size = 5408655 }, 120 | { url = "https://files.pythonhosted.org/packages/e2/a7/b14f0a73eb0fe77cb9bd5b44534c183b23d4229c099e339c522724b02678/numpy-2.2.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:77974aba6c1bc26e3c205c2214f0d5b4305bdc719268b93e768ddb17e3fdd636", size = 6949996 }, 121 | { url = "https://files.pythonhosted.org/packages/72/2f/8063da0616bb0f414b66dccead503bd96e33e43685c820e78a61a214c098/numpy-2.2.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d42f9c36d06440e34226e8bd65ff065ca0963aeecada587b937011efa02cdc9d", size = 14355789 }, 122 | { url = "https://files.pythonhosted.org/packages/e6/d7/3cd47b00b8ea95ab358c376cf5602ad21871410950bc754cf3284771f8b6/numpy-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2712c5179f40af9ddc8f6727f2bd910ea0eb50206daea75f58ddd9fa3f715bb", size = 16411356 }, 123 | { url = "https://files.pythonhosted.org/packages/27/c0/a2379e202acbb70b85b41483a422c1e697ff7eee74db642ca478de4ba89f/numpy-2.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c8b0451d2ec95010d1db8ca733afc41f659f425b7f608af569711097fd6014e2", size = 15576770 }, 124 | { url = "https://files.pythonhosted.org/packages/bc/63/a13ee650f27b7999e5b9e1964ae942af50bb25606d088df4229283eda779/numpy-2.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9b4a8148c57ecac25a16b0e11798cbe88edf5237b0df99973687dd866f05e1b", size = 18200483 }, 125 | { url = "https://files.pythonhosted.org/packages/4c/87/e71f89935e09e8161ac9c590c82f66d2321eb163893a94af749dfa8a3cf8/numpy-2.2.3-cp311-cp311-win32.whl", hash = "sha256:1f45315b2dc58d8a3e7754fe4e38b6fce132dab284a92851e41b2b344f6441c5", size = 6588415 }, 126 | { url = "https://files.pythonhosted.org/packages/b9/c6/cd4298729826af9979c5f9ab02fcaa344b82621e7c49322cd2d210483d3f/numpy-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f48ba6f6c13e5e49f3d3efb1b51c8193215c42ac82610a04624906a9270be6f", size = 12929604 }, 127 | { url = "https://files.pythonhosted.org/packages/43/ec/43628dcf98466e087812142eec6d1c1a6c6bdfdad30a0aa07b872dc01f6f/numpy-2.2.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12c045f43b1d2915eca6b880a7f4a256f59d62df4f044788c8ba67709412128d", size = 20929458 }, 128 | { url = "https://files.pythonhosted.org/packages/9b/c0/2f4225073e99a5c12350954949ed19b5d4a738f541d33e6f7439e33e98e4/numpy-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:87eed225fd415bbae787f93a457af7f5990b92a334e346f72070bf569b9c9c95", size = 14115299 }, 129 | { url = "https://files.pythonhosted.org/packages/ca/fa/d2c5575d9c734a7376cc1592fae50257ec95d061b27ee3dbdb0b3b551eb2/numpy-2.2.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:712a64103d97c404e87d4d7c47fb0c7ff9acccc625ca2002848e0d53288b90ea", size = 5145723 }, 130 | { url = "https://files.pythonhosted.org/packages/eb/dc/023dad5b268a7895e58e791f28dc1c60eb7b6c06fcbc2af8538ad069d5f3/numpy-2.2.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:a5ae282abe60a2db0fd407072aff4599c279bcd6e9a2475500fc35b00a57c532", size = 6678797 }, 131 | { url = "https://files.pythonhosted.org/packages/3f/19/bcd641ccf19ac25abb6fb1dcd7744840c11f9d62519d7057b6ab2096eb60/numpy-2.2.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5266de33d4c3420973cf9ae3b98b54a2a6d53a559310e3236c4b2b06b9c07d4e", size = 14067362 }, 132 | { url = "https://files.pythonhosted.org/packages/39/04/78d2e7402fb479d893953fb78fa7045f7deb635ec095b6b4f0260223091a/numpy-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b787adbf04b0db1967798dba8da1af07e387908ed1553a0d6e74c084d1ceafe", size = 16116679 }, 133 | { url = "https://files.pythonhosted.org/packages/d0/a1/e90f7aa66512be3150cb9d27f3d9995db330ad1b2046474a13b7040dfd92/numpy-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:34c1b7e83f94f3b564b35f480f5652a47007dd91f7c839f404d03279cc8dd021", size = 15264272 }, 134 | { url = "https://files.pythonhosted.org/packages/dc/b6/50bd027cca494de4fa1fc7bf1662983d0ba5f256fa0ece2c376b5eb9b3f0/numpy-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4d8335b5f1b6e2bce120d55fb17064b0262ff29b459e8493d1785c18ae2553b8", size = 17880549 }, 135 | { url = "https://files.pythonhosted.org/packages/96/30/f7bf4acb5f8db10a96f73896bdeed7a63373137b131ca18bd3dab889db3b/numpy-2.2.3-cp312-cp312-win32.whl", hash = "sha256:4d9828d25fb246bedd31e04c9e75714a4087211ac348cb39c8c5f99dbb6683fe", size = 6293394 }, 136 | { url = "https://files.pythonhosted.org/packages/42/6e/55580a538116d16ae7c9aa17d4edd56e83f42126cb1dfe7a684da7925d2c/numpy-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:83807d445817326b4bcdaaaf8e8e9f1753da04341eceec705c001ff342002e5d", size = 12626357 }, 137 | { url = "https://files.pythonhosted.org/packages/0e/8b/88b98ed534d6a03ba8cddb316950fe80842885709b58501233c29dfa24a9/numpy-2.2.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7bfdb06b395385ea9b91bf55c1adf1b297c9fdb531552845ff1d3ea6e40d5aba", size = 20916001 }, 138 | { url = "https://files.pythonhosted.org/packages/d9/b4/def6ec32c725cc5fbd8bdf8af80f616acf075fe752d8a23e895da8c67b70/numpy-2.2.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:23c9f4edbf4c065fddb10a4f6e8b6a244342d95966a48820c614891e5059bb50", size = 14130721 }, 139 | { url = "https://files.pythonhosted.org/packages/20/60/70af0acc86495b25b672d403e12cb25448d79a2b9658f4fc45e845c397a8/numpy-2.2.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:a0c03b6be48aaf92525cccf393265e02773be8fd9551a2f9adbe7db1fa2b60f1", size = 5130999 }, 140 | { url = "https://files.pythonhosted.org/packages/2e/69/d96c006fb73c9a47bcb3611417cf178049aae159afae47c48bd66df9c536/numpy-2.2.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:2376e317111daa0a6739e50f7ee2a6353f768489102308b0d98fcf4a04f7f3b5", size = 6665299 }, 141 | { url = "https://files.pythonhosted.org/packages/5a/3f/d8a877b6e48103733ac224ffa26b30887dc9944ff95dffdfa6c4ce3d7df3/numpy-2.2.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8fb62fe3d206d72fe1cfe31c4a1106ad2b136fcc1606093aeab314f02930fdf2", size = 14064096 }, 142 | { url = "https://files.pythonhosted.org/packages/e4/43/619c2c7a0665aafc80efca465ddb1f260287266bdbdce517396f2f145d49/numpy-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52659ad2534427dffcc36aac76bebdd02b67e3b7a619ac67543bc9bfe6b7cdb1", size = 16114758 }, 143 | { url = "https://files.pythonhosted.org/packages/d9/79/ee4fe4f60967ccd3897aa71ae14cdee9e3c097e3256975cc9575d393cb42/numpy-2.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1b416af7d0ed3271cad0f0a0d0bee0911ed7eba23e66f8424d9f3dfcdcae1304", size = 15259880 }, 144 | { url = "https://files.pythonhosted.org/packages/fb/c8/8b55cf05db6d85b7a7d414b3d1bd5a740706df00bfa0824a08bf041e52ee/numpy-2.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1402da8e0f435991983d0a9708b779f95a8c98c6b18a171b9f1be09005e64d9d", size = 17876721 }, 145 | { url = "https://files.pythonhosted.org/packages/21/d6/b4c2f0564b7dcc413117b0ffbb818d837e4b29996b9234e38b2025ed24e7/numpy-2.2.3-cp313-cp313-win32.whl", hash = "sha256:136553f123ee2951bfcfbc264acd34a2fc2f29d7cdf610ce7daf672b6fbaa693", size = 6290195 }, 146 | { url = "https://files.pythonhosted.org/packages/97/e7/7d55a86719d0de7a6a597949f3febefb1009435b79ba510ff32f05a8c1d7/numpy-2.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:5b732c8beef1d7bc2d9e476dbba20aaff6167bf205ad9aa8d30913859e82884b", size = 12619013 }, 147 | { url = "https://files.pythonhosted.org/packages/a6/1f/0b863d5528b9048fd486a56e0b97c18bf705e88736c8cea7239012119a54/numpy-2.2.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:435e7a933b9fda8126130b046975a968cc2d833b505475e588339e09f7672890", size = 20944621 }, 148 | { url = "https://files.pythonhosted.org/packages/aa/99/b478c384f7a0a2e0736177aafc97dc9152fc036a3fdb13f5a3ab225f1494/numpy-2.2.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7678556eeb0152cbd1522b684dcd215250885993dd00adb93679ec3c0e6e091c", size = 14142502 }, 149 | { url = "https://files.pythonhosted.org/packages/fb/61/2d9a694a0f9cd0a839501d362de2a18de75e3004576a3008e56bdd60fcdb/numpy-2.2.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:2e8da03bd561504d9b20e7a12340870dfc206c64ea59b4cfee9fceb95070ee94", size = 5176293 }, 150 | { url = "https://files.pythonhosted.org/packages/33/35/51e94011b23e753fa33f891f601e5c1c9a3d515448659b06df9d40c0aa6e/numpy-2.2.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:c9aa4496fd0e17e3843399f533d62857cef5900facf93e735ef65aa4bbc90ef0", size = 6691874 }, 151 | { url = "https://files.pythonhosted.org/packages/ff/cf/06e37619aad98a9d03bd8d65b8e3041c3a639be0f5f6b0a0e2da544538d4/numpy-2.2.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4ca91d61a4bf61b0f2228f24bbfa6a9facd5f8af03759fe2a655c50ae2c6610", size = 14036826 }, 152 | { url = "https://files.pythonhosted.org/packages/0c/93/5d7d19955abd4d6099ef4a8ee006f9ce258166c38af259f9e5558a172e3e/numpy-2.2.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:deaa09cd492e24fd9b15296844c0ad1b3c976da7907e1c1ed3a0ad21dded6f76", size = 16096567 }, 153 | { url = "https://files.pythonhosted.org/packages/af/53/d1c599acf7732d81f46a93621dab6aa8daad914b502a7a115b3f17288ab2/numpy-2.2.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:246535e2f7496b7ac85deffe932896a3577be7af8fb7eebe7146444680297e9a", size = 15242514 }, 154 | { url = "https://files.pythonhosted.org/packages/53/43/c0f5411c7b3ea90adf341d05ace762dad8cb9819ef26093e27b15dd121ac/numpy-2.2.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:daf43a3d1ea699402c5a850e5313680ac355b4adc9770cd5cfc2940e7861f1bf", size = 17872920 }, 155 | { url = "https://files.pythonhosted.org/packages/5b/57/6dbdd45ab277aff62021cafa1e15f9644a52f5b5fc840bc7591b4079fb58/numpy-2.2.3-cp313-cp313t-win32.whl", hash = "sha256:cf802eef1f0134afb81fef94020351be4fe1d6681aadf9c5e862af6602af64ef", size = 6346584 }, 156 | { url = "https://files.pythonhosted.org/packages/97/9b/484f7d04b537d0a1202a5ba81c6f53f1846ae6c63c2127f8df869ed31342/numpy-2.2.3-cp313-cp313t-win_amd64.whl", hash = "sha256:aee2512827ceb6d7f517c8b85aa5d3923afe8fc7a57d028cffcd522f1c6fd082", size = 12706784 }, 157 | ] 158 | 159 | [[package]] 160 | name = "packaging" 161 | version = "24.2" 162 | source = { registry = "https://pypi.org/simple" } 163 | sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } 164 | wheels = [ 165 | { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, 166 | ] 167 | 168 | [[package]] 169 | name = "pillow" 170 | version = "11.1.0" 171 | source = { registry = "https://pypi.org/simple" } 172 | sdist = { url = "https://files.pythonhosted.org/packages/f3/af/c097e544e7bd278333db77933e535098c259609c4eb3b85381109602fb5b/pillow-11.1.0.tar.gz", hash = "sha256:368da70808b36d73b4b390a8ffac11069f8a5c85f29eff1f1b01bcf3ef5b2a20", size = 46742715 } 173 | wheels = [ 174 | { url = "https://files.pythonhosted.org/packages/dd/d6/2000bfd8d5414fb70cbbe52c8332f2283ff30ed66a9cde42716c8ecbe22c/pillow-11.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:e06695e0326d05b06833b40b7ef477e475d0b1ba3a6d27da1bb48c23209bf457", size = 3229968 }, 175 | { url = "https://files.pythonhosted.org/packages/d9/45/3fe487010dd9ce0a06adf9b8ff4f273cc0a44536e234b0fad3532a42c15b/pillow-11.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96f82000e12f23e4f29346e42702b6ed9a2f2fea34a740dd5ffffcc8c539eb35", size = 3101806 }, 176 | { url = "https://files.pythonhosted.org/packages/e3/72/776b3629c47d9d5f1c160113158a7a7ad177688d3a1159cd3b62ded5a33a/pillow-11.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3cd561ded2cf2bbae44d4605837221b987c216cff94f49dfeed63488bb228d2", size = 4322283 }, 177 | { url = "https://files.pythonhosted.org/packages/e4/c2/e25199e7e4e71d64eeb869f5b72c7ddec70e0a87926398785ab944d92375/pillow-11.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f189805c8be5ca5add39e6f899e6ce2ed824e65fb45f3c28cb2841911da19070", size = 4402945 }, 178 | { url = "https://files.pythonhosted.org/packages/c1/ed/51d6136c9d5911f78632b1b86c45241c712c5a80ed7fa7f9120a5dff1eba/pillow-11.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:dd0052e9db3474df30433f83a71b9b23bd9e4ef1de13d92df21a52c0303b8ab6", size = 4361228 }, 179 | { url = "https://files.pythonhosted.org/packages/48/a4/fbfe9d5581d7b111b28f1d8c2762dee92e9821bb209af9fa83c940e507a0/pillow-11.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:837060a8599b8f5d402e97197d4924f05a2e0d68756998345c829c33186217b1", size = 4484021 }, 180 | { url = "https://files.pythonhosted.org/packages/39/db/0b3c1a5018117f3c1d4df671fb8e47d08937f27519e8614bbe86153b65a5/pillow-11.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:aa8dd43daa836b9a8128dbe7d923423e5ad86f50a7a14dc688194b7be5c0dea2", size = 4287449 }, 181 | { url = "https://files.pythonhosted.org/packages/d9/58/bc128da7fea8c89fc85e09f773c4901e95b5936000e6f303222490c052f3/pillow-11.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0a2f91f8a8b367e7a57c6e91cd25af510168091fb89ec5146003e424e1558a96", size = 4419972 }, 182 | { url = "https://files.pythonhosted.org/packages/5f/bb/58f34379bde9fe197f51841c5bbe8830c28bbb6d3801f16a83b8f2ad37df/pillow-11.1.0-cp311-cp311-win32.whl", hash = "sha256:c12fc111ef090845de2bb15009372175d76ac99969bdf31e2ce9b42e4b8cd88f", size = 2291201 }, 183 | { url = "https://files.pythonhosted.org/packages/3a/c6/fce9255272bcf0c39e15abd2f8fd8429a954cf344469eaceb9d0d1366913/pillow-11.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fbd43429d0d7ed6533b25fc993861b8fd512c42d04514a0dd6337fb3ccf22761", size = 2625686 }, 184 | { url = "https://files.pythonhosted.org/packages/c8/52/8ba066d569d932365509054859f74f2a9abee273edcef5cd75e4bc3e831e/pillow-11.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:f7955ecf5609dee9442cbface754f2c6e541d9e6eda87fad7f7a989b0bdb9d71", size = 2375194 }, 185 | { url = "https://files.pythonhosted.org/packages/95/20/9ce6ed62c91c073fcaa23d216e68289e19d95fb8188b9fb7a63d36771db8/pillow-11.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2062ffb1d36544d42fcaa277b069c88b01bb7298f4efa06731a7fd6cc290b81a", size = 3226818 }, 186 | { url = "https://files.pythonhosted.org/packages/b9/d8/f6004d98579a2596c098d1e30d10b248798cceff82d2b77aa914875bfea1/pillow-11.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a85b653980faad27e88b141348707ceeef8a1186f75ecc600c395dcac19f385b", size = 3101662 }, 187 | { url = "https://files.pythonhosted.org/packages/08/d9/892e705f90051c7a2574d9f24579c9e100c828700d78a63239676f960b74/pillow-11.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9409c080586d1f683df3f184f20e36fb647f2e0bc3988094d4fd8c9f4eb1b3b3", size = 4329317 }, 188 | { url = "https://files.pythonhosted.org/packages/8c/aa/7f29711f26680eab0bcd3ecdd6d23ed6bce180d82e3f6380fb7ae35fcf3b/pillow-11.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fdadc077553621911f27ce206ffcbec7d3f8d7b50e0da39f10997e8e2bb7f6a", size = 4412999 }, 189 | { url = "https://files.pythonhosted.org/packages/c8/c4/8f0fe3b9e0f7196f6d0bbb151f9fba323d72a41da068610c4c960b16632a/pillow-11.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:93a18841d09bcdd774dcdc308e4537e1f867b3dec059c131fde0327899734aa1", size = 4368819 }, 190 | { url = "https://files.pythonhosted.org/packages/38/0d/84200ed6a871ce386ddc82904bfadc0c6b28b0c0ec78176871a4679e40b3/pillow-11.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9aa9aeddeed452b2f616ff5507459e7bab436916ccb10961c4a382cd3e03f47f", size = 4496081 }, 191 | { url = "https://files.pythonhosted.org/packages/84/9c/9bcd66f714d7e25b64118e3952d52841a4babc6d97b6d28e2261c52045d4/pillow-11.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3cdcdb0b896e981678eee140d882b70092dac83ac1cdf6b3a60e2216a73f2b91", size = 4296513 }, 192 | { url = "https://files.pythonhosted.org/packages/db/61/ada2a226e22da011b45f7104c95ebda1b63dcbb0c378ad0f7c2a710f8fd2/pillow-11.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:36ba10b9cb413e7c7dfa3e189aba252deee0602c86c309799da5a74009ac7a1c", size = 4431298 }, 193 | { url = "https://files.pythonhosted.org/packages/e7/c4/fc6e86750523f367923522014b821c11ebc5ad402e659d8c9d09b3c9d70c/pillow-11.1.0-cp312-cp312-win32.whl", hash = "sha256:cfd5cd998c2e36a862d0e27b2df63237e67273f2fc78f47445b14e73a810e7e6", size = 2291630 }, 194 | { url = "https://files.pythonhosted.org/packages/08/5c/2104299949b9d504baf3f4d35f73dbd14ef31bbd1ddc2c1b66a5b7dfda44/pillow-11.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a697cd8ba0383bba3d2d3ada02b34ed268cb548b369943cd349007730c92bddf", size = 2626369 }, 195 | { url = "https://files.pythonhosted.org/packages/37/f3/9b18362206b244167c958984b57c7f70a0289bfb59a530dd8af5f699b910/pillow-11.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:4dd43a78897793f60766563969442020e90eb7847463eca901e41ba186a7d4a5", size = 2375240 }, 196 | { url = "https://files.pythonhosted.org/packages/b3/31/9ca79cafdce364fd5c980cd3416c20ce1bebd235b470d262f9d24d810184/pillow-11.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ae98e14432d458fc3de11a77ccb3ae65ddce70f730e7c76140653048c71bfcbc", size = 3226640 }, 197 | { url = "https://files.pythonhosted.org/packages/ac/0f/ff07ad45a1f172a497aa393b13a9d81a32e1477ef0e869d030e3c1532521/pillow-11.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cc1331b6d5a6e144aeb5e626f4375f5b7ae9934ba620c0ac6b3e43d5e683a0f0", size = 3101437 }, 198 | { url = "https://files.pythonhosted.org/packages/08/2f/9906fca87a68d29ec4530be1f893149e0cb64a86d1f9f70a7cfcdfe8ae44/pillow-11.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:758e9d4ef15d3560214cddbc97b8ef3ef86ce04d62ddac17ad39ba87e89bd3b1", size = 4326605 }, 199 | { url = "https://files.pythonhosted.org/packages/b0/0f/f3547ee15b145bc5c8b336401b2d4c9d9da67da9dcb572d7c0d4103d2c69/pillow-11.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b523466b1a31d0dcef7c5be1f20b942919b62fd6e9a9be199d035509cbefc0ec", size = 4411173 }, 200 | { url = "https://files.pythonhosted.org/packages/b1/df/bf8176aa5db515c5de584c5e00df9bab0713548fd780c82a86cba2c2fedb/pillow-11.1.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:9044b5e4f7083f209c4e35aa5dd54b1dd5b112b108648f5c902ad586d4f945c5", size = 4369145 }, 201 | { url = "https://files.pythonhosted.org/packages/de/7c/7433122d1cfadc740f577cb55526fdc39129a648ac65ce64db2eb7209277/pillow-11.1.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:3764d53e09cdedd91bee65c2527815d315c6b90d7b8b79759cc48d7bf5d4f114", size = 4496340 }, 202 | { url = "https://files.pythonhosted.org/packages/25/46/dd94b93ca6bd555588835f2504bd90c00d5438fe131cf01cfa0c5131a19d/pillow-11.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:31eba6bbdd27dde97b0174ddf0297d7a9c3a507a8a1480e1e60ef914fe23d352", size = 4296906 }, 203 | { url = "https://files.pythonhosted.org/packages/a8/28/2f9d32014dfc7753e586db9add35b8a41b7a3b46540e965cb6d6bc607bd2/pillow-11.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b5d658fbd9f0d6eea113aea286b21d3cd4d3fd978157cbf2447a6035916506d3", size = 4431759 }, 204 | { url = "https://files.pythonhosted.org/packages/33/48/19c2cbe7403870fbe8b7737d19eb013f46299cdfe4501573367f6396c775/pillow-11.1.0-cp313-cp313-win32.whl", hash = "sha256:f86d3a7a9af5d826744fabf4afd15b9dfef44fe69a98541f666f66fbb8d3fef9", size = 2291657 }, 205 | { url = "https://files.pythonhosted.org/packages/3b/ad/285c556747d34c399f332ba7c1a595ba245796ef3e22eae190f5364bb62b/pillow-11.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:593c5fd6be85da83656b93ffcccc2312d2d149d251e98588b14fbc288fd8909c", size = 2626304 }, 206 | { url = "https://files.pythonhosted.org/packages/e5/7b/ef35a71163bf36db06e9c8729608f78dedf032fc8313d19bd4be5c2588f3/pillow-11.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:11633d58b6ee5733bde153a8dafd25e505ea3d32e261accd388827ee987baf65", size = 2375117 }, 207 | { url = "https://files.pythonhosted.org/packages/79/30/77f54228401e84d6791354888549b45824ab0ffde659bafa67956303a09f/pillow-11.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:70ca5ef3b3b1c4a0812b5c63c57c23b63e53bc38e758b37a951e5bc466449861", size = 3230060 }, 208 | { url = "https://files.pythonhosted.org/packages/ce/b1/56723b74b07dd64c1010fee011951ea9c35a43d8020acd03111f14298225/pillow-11.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8000376f139d4d38d6851eb149b321a52bb8893a88dae8ee7d95840431977081", size = 3106192 }, 209 | { url = "https://files.pythonhosted.org/packages/e1/cd/7bf7180e08f80a4dcc6b4c3a0aa9e0b0ae57168562726a05dc8aa8fa66b0/pillow-11.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ee85f0696a17dd28fbcfceb59f9510aa71934b483d1f5601d1030c3c8304f3c", size = 4446805 }, 210 | { url = "https://files.pythonhosted.org/packages/97/42/87c856ea30c8ed97e8efbe672b58c8304dee0573f8c7cab62ae9e31db6ae/pillow-11.1.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:dd0e081319328928531df7a0e63621caf67652c8464303fd102141b785ef9547", size = 4530623 }, 211 | { url = "https://files.pythonhosted.org/packages/ff/41/026879e90c84a88e33fb00cc6bd915ac2743c67e87a18f80270dfe3c2041/pillow-11.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e63e4e5081de46517099dc30abe418122f54531a6ae2ebc8680bcd7096860eab", size = 4465191 }, 212 | { url = "https://files.pythonhosted.org/packages/e5/fb/a7960e838bc5df57a2ce23183bfd2290d97c33028b96bde332a9057834d3/pillow-11.1.0-cp313-cp313t-win32.whl", hash = "sha256:dda60aa465b861324e65a78c9f5cf0f4bc713e4309f83bc387be158b077963d9", size = 2295494 }, 213 | { url = "https://files.pythonhosted.org/packages/d7/6c/6ec83ee2f6f0fda8d4cf89045c6be4b0373ebfc363ba8538f8c999f63fcd/pillow-11.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ad5db5781c774ab9a9b2c4302bbf0c1014960a0a7be63278d13ae6fdf88126fe", size = 2631595 }, 214 | { url = "https://files.pythonhosted.org/packages/cf/6c/41c21c6c8af92b9fea313aa47c75de49e2f9a467964ee33eb0135d47eb64/pillow-11.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:67cd427c68926108778a9005f2a04adbd5e67c442ed21d95389fe1d595458756", size = 2377651 }, 215 | ] 216 | 217 | [[package]] 218 | name = "pycparser" 219 | version = "2.22" 220 | source = { registry = "https://pypi.org/simple" } 221 | sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 } 222 | wheels = [ 223 | { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, 224 | ] 225 | 226 | [[package]] 227 | name = "pygraphslam" 228 | version = "0.1.0" 229 | source = { virtual = "." } 230 | dependencies = [ 231 | { name = "g2o-python" }, 232 | { name = "numpy" }, 233 | { name = "raylib" }, 234 | { name = "scikit-image" }, 235 | { name = "scikit-learn" }, 236 | { name = "scipy" }, 237 | ] 238 | 239 | [package.dev-dependencies] 240 | dev = [ 241 | { name = "scikit-build" }, 242 | { name = "setuptools" }, 243 | ] 244 | 245 | [package.metadata] 246 | requires-dist = [ 247 | { name = "g2o-python", git = "https://github.com/miquelmassot/g2o-python?rev=d761ee9" }, 248 | { name = "numpy", specifier = ">=2.2.2" }, 249 | { name = "raylib", specifier = ">=5.5.0.2" }, 250 | { name = "scikit-image", specifier = ">=0.25.2" }, 251 | { name = "scikit-learn", specifier = ">=1.6.1" }, 252 | { name = "scipy", specifier = ">=1.15.1" }, 253 | ] 254 | 255 | [package.metadata.requires-dev] 256 | dev = [ 257 | { name = "scikit-build", specifier = ">=0.18.1" }, 258 | { name = "setuptools", specifier = ">=75.8.0" }, 259 | ] 260 | 261 | [[package]] 262 | name = "raylib" 263 | version = "5.5.0.2" 264 | source = { registry = "https://pypi.org/simple" } 265 | dependencies = [ 266 | { name = "cffi" }, 267 | ] 268 | sdist = { url = "https://files.pythonhosted.org/packages/8c/35/9bf3a2af73c55fd4310dcaec4f997c739888e0db9b4dfac71b7680810852/raylib-5.5.0.2.tar.gz", hash = "sha256:83c108ae3b4af40b53c93d1de2afbe309e986dd5efeb280ebe2e61c79956edb0", size = 181172 } 269 | wheels = [ 270 | { url = "https://files.pythonhosted.org/packages/9e/c4/ce21721b474eb8f65379f7315b382ccfe1d5df728eea4dcf287b874e7461/raylib-5.5.0.2-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:37eb0ec97fc6b08f989489a50e09b5dde519e1bb8eb17e4033ac82227b0e5eda", size = 1703742 }, 271 | { url = "https://files.pythonhosted.org/packages/23/61/138e305c82549869bb8cd41abe75571559eafbeab6aed1ce7d8fbe3ffd58/raylib-5.5.0.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:bb9e506ecd3dbec6dba868eb036269837a8bde68220690842c3238239ee887ef", size = 1247449 }, 272 | { url = "https://files.pythonhosted.org/packages/85/e0/dc638c42d1a505f0992263d48e1434d82c21afdf376b06f549d2e281dfd4/raylib-5.5.0.2-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:70aa8bed67875a8cf25191f35263ef92d646bdfcb1f507915c81562a321f4931", size = 2184315 }, 273 | { url = "https://files.pythonhosted.org/packages/c9/1a/49db57283a28fdc1ff0e4604911b7fff085128c2ac8bdd9efa8c5c47439d/raylib-5.5.0.2-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:0365e8c578f72f598795d9377fc70342f0d62aa193c2f304ca048b3e28866752", size = 2278139 }, 274 | { url = "https://files.pythonhosted.org/packages/f0/8a/e1a690ab6889d4cb67346a2d32bad8b8e8b0f85ec826b00f76b0ad7e6ad6/raylib-5.5.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:5219be70e7fca03e9c4fddebf7e60e885d77137125c7a13f3800a947f8562a13", size = 1693944 }, 275 | { url = "https://files.pythonhosted.org/packages/69/2b/49bfa6833ad74ddf318d54ecafe73d535f583531469ecbd5b009d79667d1/raylib-5.5.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5233c529d9a0cfd469d88239c2182e55c5215a7755d83cc3d611148d3b9c9e67", size = 1706157 }, 276 | { url = "https://files.pythonhosted.org/packages/58/9c/8a3f4de0c81ad1228bf26410cfe3ecdc73011c59f18e542685ffc92c0120/raylib-5.5.0.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:1f76204ffbc492722b571b12dbdc0dca89b10da76ddf48c12a3968d2db061dff", size = 1248027 }, 277 | { url = "https://files.pythonhosted.org/packages/7f/16/63baf1aae94832b9f5d15cafcee67bb6dd07a20cf64d40bac09903b79274/raylib-5.5.0.2-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:f8cc2e39f1d6b29211a97ec0ac818a5b04c43a40e747e4b4622101d48c711f9e", size = 2195374 }, 278 | { url = "https://files.pythonhosted.org/packages/70/bd/61a006b4e3ce4a6ca974cb0ceeb19f3816815ebabac650e9bf82767e65f6/raylib-5.5.0.2-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:f12da578a28da7f48481f46323e5aab8dd25461982b0e80d045782d6e69649f5", size = 2299593 }, 279 | { url = "https://files.pythonhosted.org/packages/f4/4f/59d554cc495bea8235b17cebfc76ed57aaa602c613b870159e31282fd4c1/raylib-5.5.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:b40234bbad9523fd6a2049640c76a98b4d6f0b8f4bd19bd33eaee55faf5e050d", size = 1696780 }, 280 | { url = "https://files.pythonhosted.org/packages/ba/0a/78edc3ed1e2ca7e2ccea31ac5a8f4440a924662ee1042ecb76e08f465d8a/raylib-5.5.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2bfa9419a12eeb259f99c75c351db167968306295a5017cd4735241eaf2fa399", size = 1706104 }, 281 | { url = "https://files.pythonhosted.org/packages/48/fb/8b79a03c0d63bd6613d3e25df26d6c42fe36689f052abefa00a311be53fc/raylib-5.5.0.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:216456d0fa8da85c253a8596ca4b35c995bbf8af0fb8fa5244a4c6f5debfe294", size = 1248018 }, 282 | { url = "https://files.pythonhosted.org/packages/57/42/8ef2a8e21a2b4ba7ac4ea13b1dd9bc5d1084020ddca06ad0c6582c784a4e/raylib-5.5.0.2-cp313-cp313-manylinux2014_x86_64.whl", hash = "sha256:4f1c33b7d2404e70dbf3dd8d71701efb24902adfcb553122bf3d9441ea4fd6f0", size = 2299336 }, 283 | { url = "https://files.pythonhosted.org/packages/b4/67/4c25526fde4dabf5cc60093202f8d07a7dc4b1bd29d7b84db55b443a527c/raylib-5.5.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:6b60c97a9f6cfaeef4f59ff162ea29f02c18282d129edebb62f132b2ad6bb935", size = 1696790 }, 284 | { url = "https://files.pythonhosted.org/packages/4a/22/2e02e3738ad041f5ec2830aecdfab411fc2960bfc3400e03b477284bfaf7/raylib-5.5.0.2-pp311-pypy311_pp73-macosx_10_13_x86_64.whl", hash = "sha256:bc45fe1c0aac50aa319a9a66d44bb2bd0dcd038a44d95978191ae7bfeb4a06d8", size = 1216231 }, 285 | { url = "https://files.pythonhosted.org/packages/fe/7d/b29afedc4a706b12143f74f322cb32ad5a6f43e56aaca2a9fb89b0d94eee/raylib-5.5.0.2-pp311-pypy311_pp73-manylinux2014_x86_64.whl", hash = "sha256:2242fd6079da5137e9863a447224f800adef6386ca8f59013a5d62cc5cadab2b", size = 1394928 }, 286 | { url = "https://files.pythonhosted.org/packages/b6/fa/2daf36d78078c6871b241168a36156169cfc8ea089faba5abe8edad304be/raylib-5.5.0.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:e475a40764c9f83f9e66406bd86d85587eb923329a61ade463c3c59e1e880b16", size = 1564224 }, 287 | ] 288 | 289 | [[package]] 290 | name = "scikit-build" 291 | version = "0.18.1" 292 | source = { registry = "https://pypi.org/simple" } 293 | dependencies = [ 294 | { name = "distro" }, 295 | { name = "packaging" }, 296 | { name = "setuptools" }, 297 | { name = "wheel" }, 298 | ] 299 | sdist = { url = "https://files.pythonhosted.org/packages/56/54/2beb41f3fcddb4ea238634c6c23fe93115090d8799a45f626a83e6934c16/scikit_build-0.18.1.tar.gz", hash = "sha256:a4152ac5a084d499c28a7797be0628d8366c336e2fb0e1a063eb32e55efcb8e7", size = 274171 } 300 | wheels = [ 301 | { url = "https://files.pythonhosted.org/packages/c3/a3/21b519f58de90d684056c52ec4e45f744cfda7483f082dcc4dd18cc74a93/scikit_build-0.18.1-py3-none-any.whl", hash = "sha256:a6860e300f6807e76f21854163bdb9db16afc74eadf34bd6a9947d3fdfcd725a", size = 85568 }, 302 | ] 303 | 304 | [[package]] 305 | name = "scikit-image" 306 | version = "0.25.2" 307 | source = { registry = "https://pypi.org/simple" } 308 | dependencies = [ 309 | { name = "imageio" }, 310 | { name = "lazy-loader" }, 311 | { name = "networkx" }, 312 | { name = "numpy" }, 313 | { name = "packaging" }, 314 | { name = "pillow" }, 315 | { name = "scipy" }, 316 | { name = "tifffile" }, 317 | ] 318 | sdist = { url = "https://files.pythonhosted.org/packages/c7/a8/3c0f256012b93dd2cb6fda9245e9f4bff7dc0486880b248005f15ea2255e/scikit_image-0.25.2.tar.gz", hash = "sha256:e5a37e6cd4d0c018a7a55b9d601357e3382826d3888c10d0213fc63bff977dde", size = 22693594 } 319 | wheels = [ 320 | { url = "https://files.pythonhosted.org/packages/c4/97/3051c68b782ee3f1fb7f8f5bb7d535cf8cb92e8aae18fa9c1cdf7e15150d/scikit_image-0.25.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f4bac9196fb80d37567316581c6060763b0f4893d3aca34a9ede3825bc035b17", size = 14003057 }, 321 | { url = "https://files.pythonhosted.org/packages/19/23/257fc696c562639826065514d551b7b9b969520bd902c3a8e2fcff5b9e17/scikit_image-0.25.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:d989d64ff92e0c6c0f2018c7495a5b20e2451839299a018e0e5108b2680f71e0", size = 13180335 }, 322 | { url = "https://files.pythonhosted.org/packages/ef/14/0c4a02cb27ca8b1e836886b9ec7c9149de03053650e9e2ed0625f248dd92/scikit_image-0.25.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2cfc96b27afe9a05bc92f8c6235321d3a66499995675b27415e0d0c76625173", size = 14144783 }, 323 | { url = "https://files.pythonhosted.org/packages/dd/9b/9fb556463a34d9842491d72a421942c8baff4281025859c84fcdb5e7e602/scikit_image-0.25.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24cc986e1f4187a12aa319f777b36008764e856e5013666a4a83f8df083c2641", size = 14785376 }, 324 | { url = "https://files.pythonhosted.org/packages/de/ec/b57c500ee85885df5f2188f8bb70398481393a69de44a00d6f1d055f103c/scikit_image-0.25.2-cp311-cp311-win_amd64.whl", hash = "sha256:b4f6b61fc2db6340696afe3db6b26e0356911529f5f6aee8c322aa5157490c9b", size = 12791698 }, 325 | { url = "https://files.pythonhosted.org/packages/35/8c/5df82881284459f6eec796a5ac2a0a304bb3384eec2e73f35cfdfcfbf20c/scikit_image-0.25.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8db8dd03663112783221bf01ccfc9512d1cc50ac9b5b0fe8f4023967564719fb", size = 13986000 }, 326 | { url = "https://files.pythonhosted.org/packages/ce/e6/93bebe1abcdce9513ffec01d8af02528b4c41fb3c1e46336d70b9ed4ef0d/scikit_image-0.25.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:483bd8cc10c3d8a7a37fae36dfa5b21e239bd4ee121d91cad1f81bba10cfb0ed", size = 13235893 }, 327 | { url = "https://files.pythonhosted.org/packages/53/4b/eda616e33f67129e5979a9eb33c710013caa3aa8a921991e6cc0b22cea33/scikit_image-0.25.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d1e80107bcf2bf1291acfc0bf0425dceb8890abe9f38d8e94e23497cbf7ee0d", size = 14178389 }, 328 | { url = "https://files.pythonhosted.org/packages/6b/b5/b75527c0f9532dd8a93e8e7cd8e62e547b9f207d4c11e24f0006e8646b36/scikit_image-0.25.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a17e17eb8562660cc0d31bb55643a4da996a81944b82c54805c91b3fe66f4824", size = 15003435 }, 329 | { url = "https://files.pythonhosted.org/packages/34/e3/49beb08ebccda3c21e871b607c1cb2f258c3fa0d2f609fed0a5ba741b92d/scikit_image-0.25.2-cp312-cp312-win_amd64.whl", hash = "sha256:bdd2b8c1de0849964dbc54037f36b4e9420157e67e45a8709a80d727f52c7da2", size = 12899474 }, 330 | { url = "https://files.pythonhosted.org/packages/e6/7c/9814dd1c637f7a0e44342985a76f95a55dd04be60154247679fd96c7169f/scikit_image-0.25.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7efa888130f6c548ec0439b1a7ed7295bc10105458a421e9bf739b457730b6da", size = 13921841 }, 331 | { url = "https://files.pythonhosted.org/packages/84/06/66a2e7661d6f526740c309e9717d3bd07b473661d5cdddef4dd978edab25/scikit_image-0.25.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:dd8011efe69c3641920614d550f5505f83658fe33581e49bed86feab43a180fc", size = 13196862 }, 332 | { url = "https://files.pythonhosted.org/packages/4e/63/3368902ed79305f74c2ca8c297dfeb4307269cbe6402412668e322837143/scikit_image-0.25.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28182a9d3e2ce3c2e251383bdda68f8d88d9fff1a3ebe1eb61206595c9773341", size = 14117785 }, 333 | { url = "https://files.pythonhosted.org/packages/cd/9b/c3da56a145f52cd61a68b8465d6a29d9503bc45bc993bb45e84371c97d94/scikit_image-0.25.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8abd3c805ce6944b941cfed0406d88faeb19bab3ed3d4b50187af55cf24d147", size = 14977119 }, 334 | { url = "https://files.pythonhosted.org/packages/8a/97/5fcf332e1753831abb99a2525180d3fb0d70918d461ebda9873f66dcc12f/scikit_image-0.25.2-cp313-cp313-win_amd64.whl", hash = "sha256:64785a8acefee460ec49a354706db0b09d1f325674107d7fa3eadb663fb56d6f", size = 12885116 }, 335 | { url = "https://files.pythonhosted.org/packages/10/cc/75e9f17e3670b5ed93c32456fda823333c6279b144cd93e2c03aa06aa472/scikit_image-0.25.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:330d061bd107d12f8d68f1d611ae27b3b813b8cdb0300a71d07b1379178dd4cd", size = 13862801 }, 336 | ] 337 | 338 | [[package]] 339 | name = "scikit-learn" 340 | version = "1.6.1" 341 | source = { registry = "https://pypi.org/simple" } 342 | dependencies = [ 343 | { name = "joblib" }, 344 | { name = "numpy" }, 345 | { name = "scipy" }, 346 | { name = "threadpoolctl" }, 347 | ] 348 | sdist = { url = "https://files.pythonhosted.org/packages/9e/a5/4ae3b3a0755f7b35a280ac90b28817d1f380318973cff14075ab41ef50d9/scikit_learn-1.6.1.tar.gz", hash = "sha256:b4fc2525eca2c69a59260f583c56a7557c6ccdf8deafdba6e060f94c1c59738e", size = 7068312 } 349 | wheels = [ 350 | { url = "https://files.pythonhosted.org/packages/6c/2a/e291c29670795406a824567d1dfc91db7b699799a002fdaa452bceea8f6e/scikit_learn-1.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:72abc587c75234935e97d09aa4913a82f7b03ee0b74111dcc2881cba3c5a7b33", size = 12102620 }, 351 | { url = "https://files.pythonhosted.org/packages/25/92/ee1d7a00bb6b8c55755d4984fd82608603a3cc59959245068ce32e7fb808/scikit_learn-1.6.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:b3b00cdc8f1317b5f33191df1386c0befd16625f49d979fe77a8d44cae82410d", size = 11116234 }, 352 | { url = "https://files.pythonhosted.org/packages/30/cd/ed4399485ef364bb25f388ab438e3724e60dc218c547a407b6e90ccccaef/scikit_learn-1.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc4765af3386811c3ca21638f63b9cf5ecf66261cc4815c1db3f1e7dc7b79db2", size = 12592155 }, 353 | { url = "https://files.pythonhosted.org/packages/a8/f3/62fc9a5a659bb58a03cdd7e258956a5824bdc9b4bb3c5d932f55880be569/scikit_learn-1.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25fc636bdaf1cc2f4a124a116312d837148b5e10872147bdaf4887926b8c03d8", size = 13497069 }, 354 | { url = "https://files.pythonhosted.org/packages/a1/a6/c5b78606743a1f28eae8f11973de6613a5ee87366796583fb74c67d54939/scikit_learn-1.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:fa909b1a36e000a03c382aade0bd2063fd5680ff8b8e501660c0f59f021a6415", size = 11139809 }, 355 | { url = "https://files.pythonhosted.org/packages/0a/18/c797c9b8c10380d05616db3bfb48e2a3358c767affd0857d56c2eb501caa/scikit_learn-1.6.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:926f207c804104677af4857b2c609940b743d04c4c35ce0ddc8ff4f053cddc1b", size = 12104516 }, 356 | { url = "https://files.pythonhosted.org/packages/c4/b7/2e35f8e289ab70108f8cbb2e7a2208f0575dc704749721286519dcf35f6f/scikit_learn-1.6.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:2c2cae262064e6a9b77eee1c8e768fc46aa0b8338c6a8297b9b6759720ec0ff2", size = 11167837 }, 357 | { url = "https://files.pythonhosted.org/packages/a4/f6/ff7beaeb644bcad72bcfd5a03ff36d32ee4e53a8b29a639f11bcb65d06cd/scikit_learn-1.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1061b7c028a8663fb9a1a1baf9317b64a257fcb036dae5c8752b2abef31d136f", size = 12253728 }, 358 | { url = "https://files.pythonhosted.org/packages/29/7a/8bce8968883e9465de20be15542f4c7e221952441727c4dad24d534c6d99/scikit_learn-1.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e69fab4ebfc9c9b580a7a80111b43d214ab06250f8a7ef590a4edf72464dd86", size = 13147700 }, 359 | { url = "https://files.pythonhosted.org/packages/62/27/585859e72e117fe861c2079bcba35591a84f801e21bc1ab85bce6ce60305/scikit_learn-1.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:70b1d7e85b1c96383f872a519b3375f92f14731e279a7b4c6cfd650cf5dffc52", size = 11110613 }, 360 | { url = "https://files.pythonhosted.org/packages/2e/59/8eb1872ca87009bdcdb7f3cdc679ad557b992c12f4b61f9250659e592c63/scikit_learn-1.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2ffa1e9e25b3d93990e74a4be2c2fc61ee5af85811562f1288d5d055880c4322", size = 12010001 }, 361 | { url = "https://files.pythonhosted.org/packages/9d/05/f2fc4effc5b32e525408524c982c468c29d22f828834f0625c5ef3d601be/scikit_learn-1.6.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:dc5cf3d68c5a20ad6d571584c0750ec641cc46aeef1c1507be51300e6003a7e1", size = 11096360 }, 362 | { url = "https://files.pythonhosted.org/packages/c8/e4/4195d52cf4f113573fb8ebc44ed5a81bd511a92c0228889125fac2f4c3d1/scikit_learn-1.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c06beb2e839ecc641366000ca84f3cf6fa9faa1777e29cf0c04be6e4d096a348", size = 12209004 }, 363 | { url = "https://files.pythonhosted.org/packages/94/be/47e16cdd1e7fcf97d95b3cb08bde1abb13e627861af427a3651fcb80b517/scikit_learn-1.6.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8ca8cb270fee8f1f76fa9bfd5c3507d60c6438bbee5687f81042e2bb98e5a97", size = 13171776 }, 364 | { url = "https://files.pythonhosted.org/packages/34/b0/ca92b90859070a1487827dbc672f998da95ce83edce1270fc23f96f1f61a/scikit_learn-1.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:7a1c43c8ec9fde528d664d947dc4c0789be4077a3647f232869f41d9bf50e0fb", size = 11071865 }, 365 | { url = "https://files.pythonhosted.org/packages/12/ae/993b0fb24a356e71e9a894e42b8a9eec528d4c70217353a1cd7a48bc25d4/scikit_learn-1.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a17c1dea1d56dcda2fac315712f3651a1fea86565b64b48fa1bc090249cbf236", size = 11955804 }, 366 | { url = "https://files.pythonhosted.org/packages/d6/54/32fa2ee591af44507eac86406fa6bba968d1eb22831494470d0a2e4a1eb1/scikit_learn-1.6.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6a7aa5f9908f0f28f4edaa6963c0a6183f1911e63a69aa03782f0d924c830a35", size = 11100530 }, 367 | { url = "https://files.pythonhosted.org/packages/3f/58/55856da1adec655bdce77b502e94a267bf40a8c0b89f8622837f89503b5a/scikit_learn-1.6.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0650e730afb87402baa88afbf31c07b84c98272622aaba002559b614600ca691", size = 12433852 }, 368 | { url = "https://files.pythonhosted.org/packages/ff/4f/c83853af13901a574f8f13b645467285a48940f185b690936bb700a50863/scikit_learn-1.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:3f59fe08dc03ea158605170eb52b22a105f238a5d512c4470ddeca71feae8e5f", size = 11337256 }, 369 | ] 370 | 371 | [[package]] 372 | name = "scipy" 373 | version = "1.15.2" 374 | source = { registry = "https://pypi.org/simple" } 375 | dependencies = [ 376 | { name = "numpy" }, 377 | ] 378 | sdist = { url = "https://files.pythonhosted.org/packages/b7/b9/31ba9cd990e626574baf93fbc1ac61cf9ed54faafd04c479117517661637/scipy-1.15.2.tar.gz", hash = "sha256:cd58a314d92838f7e6f755c8a2167ead4f27e1fd5c1251fd54289569ef3495ec", size = 59417316 } 379 | wheels = [ 380 | { url = "https://files.pythonhosted.org/packages/40/1f/bf0a5f338bda7c35c08b4ed0df797e7bafe8a78a97275e9f439aceb46193/scipy-1.15.2-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:92233b2df6938147be6fa8824b8136f29a18f016ecde986666be5f4d686a91a4", size = 38703651 }, 381 | { url = "https://files.pythonhosted.org/packages/de/54/db126aad3874601048c2c20ae3d8a433dbfd7ba8381551e6f62606d9bd8e/scipy-1.15.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:62ca1ff3eb513e09ed17a5736929429189adf16d2d740f44e53270cc800ecff1", size = 30102038 }, 382 | { url = "https://files.pythonhosted.org/packages/61/d8/84da3fffefb6c7d5a16968fe5b9f24c98606b165bb801bb0b8bc3985200f/scipy-1.15.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:4c6676490ad76d1c2894d77f976144b41bd1a4052107902238047fb6a473e971", size = 22375518 }, 383 | { url = "https://files.pythonhosted.org/packages/44/78/25535a6e63d3b9c4c90147371aedb5d04c72f3aee3a34451f2dc27c0c07f/scipy-1.15.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a8bf5cb4a25046ac61d38f8d3c3426ec11ebc350246a4642f2f315fe95bda655", size = 25142523 }, 384 | { url = "https://files.pythonhosted.org/packages/e0/22/4b4a26fe1cd9ed0bc2b2cb87b17d57e32ab72c346949eaf9288001f8aa8e/scipy-1.15.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a8e34cf4c188b6dd004654f88586d78f95639e48a25dfae9c5e34a6dc34547e", size = 35491547 }, 385 | { url = "https://files.pythonhosted.org/packages/32/ea/564bacc26b676c06a00266a3f25fdfe91a9d9a2532ccea7ce6dd394541bc/scipy-1.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28a0d2c2075946346e4408b211240764759e0fabaeb08d871639b5f3b1aca8a0", size = 37634077 }, 386 | { url = "https://files.pythonhosted.org/packages/43/c2/bfd4e60668897a303b0ffb7191e965a5da4056f0d98acfb6ba529678f0fb/scipy-1.15.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:42dabaaa798e987c425ed76062794e93a243be8f0f20fff6e7a89f4d61cb3d40", size = 37231657 }, 387 | { url = "https://files.pythonhosted.org/packages/4a/75/5f13050bf4f84c931bcab4f4e83c212a36876c3c2244475db34e4b5fe1a6/scipy-1.15.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6f5e296ec63c5da6ba6fa0343ea73fd51b8b3e1a300b0a8cae3ed4b1122c7462", size = 40035857 }, 388 | { url = "https://files.pythonhosted.org/packages/b9/8b/7ec1832b09dbc88f3db411f8cdd47db04505c4b72c99b11c920a8f0479c3/scipy-1.15.2-cp311-cp311-win_amd64.whl", hash = "sha256:597a0c7008b21c035831c39927406c6181bcf8f60a73f36219b69d010aa04737", size = 41217654 }, 389 | { url = "https://files.pythonhosted.org/packages/4b/5d/3c78815cbab499610f26b5bae6aed33e227225a9fa5290008a733a64f6fc/scipy-1.15.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c4697a10da8f8765bb7c83e24a470da5797e37041edfd77fd95ba3811a47c4fd", size = 38756184 }, 390 | { url = "https://files.pythonhosted.org/packages/37/20/3d04eb066b471b6e171827548b9ddb3c21c6bbea72a4d84fc5989933910b/scipy-1.15.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:869269b767d5ee7ea6991ed7e22b3ca1f22de73ab9a49c44bad338b725603301", size = 30163558 }, 391 | { url = "https://files.pythonhosted.org/packages/a4/98/e5c964526c929ef1f795d4c343b2ff98634ad2051bd2bbadfef9e772e413/scipy-1.15.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:bad78d580270a4d32470563ea86c6590b465cb98f83d760ff5b0990cb5518a93", size = 22437211 }, 392 | { url = "https://files.pythonhosted.org/packages/1d/cd/1dc7371e29195ecbf5222f9afeedb210e0a75057d8afbd942aa6cf8c8eca/scipy-1.15.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:b09ae80010f52efddb15551025f9016c910296cf70adbf03ce2a8704f3a5ad20", size = 25232260 }, 393 | { url = "https://files.pythonhosted.org/packages/f0/24/1a181a9e5050090e0b5138c5f496fee33293c342b788d02586bc410c6477/scipy-1.15.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a6fd6eac1ce74a9f77a7fc724080d507c5812d61e72bd5e4c489b042455865e", size = 35198095 }, 394 | { url = "https://files.pythonhosted.org/packages/c0/53/eaada1a414c026673eb983f8b4a55fe5eb172725d33d62c1b21f63ff6ca4/scipy-1.15.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b871df1fe1a3ba85d90e22742b93584f8d2b8e6124f8372ab15c71b73e428b8", size = 37297371 }, 395 | { url = "https://files.pythonhosted.org/packages/e9/06/0449b744892ed22b7e7b9a1994a866e64895363572677a316a9042af1fe5/scipy-1.15.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:03205d57a28e18dfd39f0377d5002725bf1f19a46f444108c29bdb246b6c8a11", size = 36872390 }, 396 | { url = "https://files.pythonhosted.org/packages/6a/6f/a8ac3cfd9505ec695c1bc35edc034d13afbd2fc1882a7c6b473e280397bb/scipy-1.15.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:601881dfb761311045b03114c5fe718a12634e5608c3b403737ae463c9885d53", size = 39700276 }, 397 | { url = "https://files.pythonhosted.org/packages/f5/6f/e6e5aff77ea2a48dd96808bb51d7450875af154ee7cbe72188afb0b37929/scipy-1.15.2-cp312-cp312-win_amd64.whl", hash = "sha256:e7c68b6a43259ba0aab737237876e5c2c549a031ddb7abc28c7b47f22e202ded", size = 40942317 }, 398 | { url = "https://files.pythonhosted.org/packages/53/40/09319f6e0f276ea2754196185f95cd191cb852288440ce035d5c3a931ea2/scipy-1.15.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01edfac9f0798ad6b46d9c4c9ca0e0ad23dbf0b1eb70e96adb9fa7f525eff0bf", size = 38717587 }, 399 | { url = "https://files.pythonhosted.org/packages/fe/c3/2854f40ecd19585d65afaef601e5e1f8dbf6758b2f95b5ea93d38655a2c6/scipy-1.15.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:08b57a9336b8e79b305a143c3655cc5bdbe6d5ece3378578888d2afbb51c4e37", size = 30100266 }, 400 | { url = "https://files.pythonhosted.org/packages/dd/b1/f9fe6e3c828cb5930b5fe74cb479de5f3d66d682fa8adb77249acaf545b8/scipy-1.15.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:54c462098484e7466362a9f1672d20888f724911a74c22ae35b61f9c5919183d", size = 22373768 }, 401 | { url = "https://files.pythonhosted.org/packages/15/9d/a60db8c795700414c3f681908a2b911e031e024d93214f2d23c6dae174ab/scipy-1.15.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:cf72ff559a53a6a6d77bd8eefd12a17995ffa44ad86c77a5df96f533d4e6c6bb", size = 25154719 }, 402 | { url = "https://files.pythonhosted.org/packages/37/3b/9bda92a85cd93f19f9ed90ade84aa1e51657e29988317fabdd44544f1dd4/scipy-1.15.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9de9d1416b3d9e7df9923ab23cd2fe714244af10b763975bea9e4f2e81cebd27", size = 35163195 }, 403 | { url = "https://files.pythonhosted.org/packages/03/5a/fc34bf1aa14dc7c0e701691fa8685f3faec80e57d816615e3625f28feb43/scipy-1.15.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb530e4794fc8ea76a4a21ccb67dea33e5e0e60f07fc38a49e821e1eae3b71a0", size = 37255404 }, 404 | { url = "https://files.pythonhosted.org/packages/4a/71/472eac45440cee134c8a180dbe4c01b3ec247e0338b7c759e6cd71f199a7/scipy-1.15.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5ea7ed46d437fc52350b028b1d44e002646e28f3e8ddc714011aaf87330f2f32", size = 36860011 }, 405 | { url = "https://files.pythonhosted.org/packages/01/b3/21f890f4f42daf20e4d3aaa18182dddb9192771cd47445aaae2e318f6738/scipy-1.15.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:11e7ad32cf184b74380f43d3c0a706f49358b904fa7d5345f16ddf993609184d", size = 39657406 }, 406 | { url = "https://files.pythonhosted.org/packages/0d/76/77cf2ac1f2a9cc00c073d49e1e16244e389dd88e2490c91d84e1e3e4d126/scipy-1.15.2-cp313-cp313-win_amd64.whl", hash = "sha256:a5080a79dfb9b78b768cebf3c9dcbc7b665c5875793569f48bf0e2b1d7f68f6f", size = 40961243 }, 407 | { url = "https://files.pythonhosted.org/packages/4c/4b/a57f8ddcf48e129e6054fa9899a2a86d1fc6b07a0e15c7eebff7ca94533f/scipy-1.15.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:447ce30cee6a9d5d1379087c9e474628dab3db4a67484be1b7dc3196bfb2fac9", size = 38870286 }, 408 | { url = "https://files.pythonhosted.org/packages/0c/43/c304d69a56c91ad5f188c0714f6a97b9c1fed93128c691148621274a3a68/scipy-1.15.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:c90ebe8aaa4397eaefa8455a8182b164a6cc1d59ad53f79943f266d99f68687f", size = 30141634 }, 409 | { url = "https://files.pythonhosted.org/packages/44/1a/6c21b45d2548eb73be9b9bff421aaaa7e85e22c1f9b3bc44b23485dfce0a/scipy-1.15.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:def751dd08243934c884a3221156d63e15234a3155cf25978b0a668409d45eb6", size = 22415179 }, 410 | { url = "https://files.pythonhosted.org/packages/74/4b/aefac4bba80ef815b64f55da06f62f92be5d03b467f2ce3668071799429a/scipy-1.15.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:302093e7dfb120e55515936cb55618ee0b895f8bcaf18ff81eca086c17bd80af", size = 25126412 }, 411 | { url = "https://files.pythonhosted.org/packages/b1/53/1cbb148e6e8f1660aacd9f0a9dfa2b05e9ff1cb54b4386fe868477972ac2/scipy-1.15.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cd5b77413e1855351cdde594eca99c1f4a588c2d63711388b6a1f1c01f62274", size = 34952867 }, 412 | { url = "https://files.pythonhosted.org/packages/2c/23/e0eb7f31a9c13cf2dca083828b97992dd22f8184c6ce4fec5deec0c81fcf/scipy-1.15.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d0194c37037707b2afa7a2f2a924cf7bac3dc292d51b6a925e5fcb89bc5c776", size = 36890009 }, 413 | { url = "https://files.pythonhosted.org/packages/03/f3/e699e19cabe96bbac5189c04aaa970718f0105cff03d458dc5e2b6bd1e8c/scipy-1.15.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:bae43364d600fdc3ac327db99659dcb79e6e7ecd279a75fe1266669d9a652828", size = 36545159 }, 414 | { url = "https://files.pythonhosted.org/packages/af/f5/ab3838e56fe5cc22383d6fcf2336e48c8fe33e944b9037fbf6cbdf5a11f8/scipy-1.15.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f031846580d9acccd0044efd1a90e6f4df3a6e12b4b6bd694a7bc03a89892b28", size = 39136566 }, 415 | { url = "https://files.pythonhosted.org/packages/0a/c8/b3f566db71461cabd4b2d5b39bcc24a7e1c119535c8361f81426be39bb47/scipy-1.15.2-cp313-cp313t-win_amd64.whl", hash = "sha256:fe8a9eb875d430d81755472c5ba75e84acc980e4a8f6204d402849234d3017db", size = 40477705 }, 416 | ] 417 | 418 | [[package]] 419 | name = "setuptools" 420 | version = "75.8.0" 421 | source = { registry = "https://pypi.org/simple" } 422 | sdist = { url = "https://files.pythonhosted.org/packages/92/ec/089608b791d210aec4e7f97488e67ab0d33add3efccb83a056cbafe3a2a6/setuptools-75.8.0.tar.gz", hash = "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6", size = 1343222 } 423 | wheels = [ 424 | { url = "https://files.pythonhosted.org/packages/69/8a/b9dc7678803429e4a3bc9ba462fa3dd9066824d3c607490235c6a796be5a/setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3", size = 1228782 }, 425 | ] 426 | 427 | [[package]] 428 | name = "threadpoolctl" 429 | version = "3.5.0" 430 | source = { registry = "https://pypi.org/simple" } 431 | sdist = { url = "https://files.pythonhosted.org/packages/bd/55/b5148dcbf72f5cde221f8bfe3b6a540da7aa1842f6b491ad979a6c8b84af/threadpoolctl-3.5.0.tar.gz", hash = "sha256:082433502dd922bf738de0d8bcc4fdcbf0979ff44c42bd40f5af8a282f6fa107", size = 41936 } 432 | wheels = [ 433 | { url = "https://files.pythonhosted.org/packages/4b/2c/ffbf7a134b9ab11a67b0cf0726453cedd9c5043a4fe7a35d1cefa9a1bcfb/threadpoolctl-3.5.0-py3-none-any.whl", hash = "sha256:56c1e26c150397e58c4926da8eeee87533b1e32bef131bd4bf6a2f45f3185467", size = 18414 }, 434 | ] 435 | 436 | [[package]] 437 | name = "tifffile" 438 | version = "2025.2.18" 439 | source = { registry = "https://pypi.org/simple" } 440 | dependencies = [ 441 | { name = "numpy" }, 442 | ] 443 | sdist = { url = "https://files.pythonhosted.org/packages/de/1f/96d743b3417425f958dfed2518ad271b346a072d27b6859bb158e601bc21/tifffile-2025.2.18.tar.gz", hash = "sha256:8d731789e691b468746c1615d989bc550ac93cf753e9210865222e90a5a95d11", size = 365412 } 444 | wheels = [ 445 | { url = "https://files.pythonhosted.org/packages/63/70/6f363ab13f9903557a567a4471a28ee231b962e34af8e1dd8d1b0f17e64e/tifffile-2025.2.18-py3-none-any.whl", hash = "sha256:54b36c4d5e5b8d8920134413edfe5a7cfb1c7617bb50cddf7e2772edb7149043", size = 226358 }, 446 | ] 447 | 448 | [[package]] 449 | name = "wheel" 450 | version = "0.45.1" 451 | source = { registry = "https://pypi.org/simple" } 452 | sdist = { url = "https://files.pythonhosted.org/packages/8a/98/2d9906746cdc6a6ef809ae6338005b3f21bb568bea3165cfc6a243fdc25c/wheel-0.45.1.tar.gz", hash = "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729", size = 107545 } 453 | wheels = [ 454 | { url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248", size = 72494 }, 455 | ] 456 | --------------------------------------------------------------------------------