diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6fecef17..28f5c5c0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,7 +18,6 @@ jobs: fail-fast: false matrix: config: [ - {os: ubuntu-latest, python-version: "3.8"}, {os: ubuntu-latest, python-version: "3.9"}, {os: ubuntu-latest, python-version: "3.10"}, {os: ubuntu-latest, python-version: "3.11"}, diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 767948e4..544d81ec 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -37,7 +37,7 @@ jobs: exit 0 fi set +x -euo pipefail - python -m pip install ruff==0.6.7 clang-format==19.1.0 + python -m pip install ruff==0.8.6 clang-format==19.1.0 ./scripts/format/clang_format.sh ./scripts/format/python.sh git diff --name-only diff --git a/README.md b/README.md index 97b9bc66..f93e2324 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ In this project, we provide interfaces for various geometric operations on 2D/3D ## Installation **Install the dependencies as follows:** -* Python 3.8/9/10/11 +* Python 3.9/10/11 * CMake >= 3.17 * CUDA (for deep learning based detectors/matchers) * System dependencies [[Command line](./misc/install/dependencies.md)] diff --git a/limap/features/models/s2dnet.py b/limap/features/models/s2dnet.py index 2788234b..ecaddaeb 100644 --- a/limap/features/models/s2dnet.py +++ b/limap/features/models/s2dnet.py @@ -1,6 +1,5 @@ import os from pathlib import Path -from typing import List import numpy as np import torch @@ -64,7 +63,7 @@ def print_gpu_memory(): class AdapLayers(nn.Module): """Small adaptation layers.""" - def __init__(self, hypercolumn_layers: List[str], output_dim: int = 128): + def __init__(self, hypercolumn_layers: list[str], output_dim: int = 128): """Initialize one adaptation layer for every extraction point. Args: hypercolumn_layers: The list of the hypercolumn layer names. @@ -84,7 +83,7 @@ def __init__(self, hypercolumn_layers: List[str], output_dim: int = 128): self.layers.append(layer) self.add_module(f"adap_layer_{i}", layer) - def forward(self, features: List[torch.tensor]): + def forward(self, features: list[torch.tensor]): """Apply adaptation layers.""" for i, _ in enumerate(features): features[i] = getattr(self, f"adap_layer_{i}")(features[i]) diff --git a/limap/fitting/fitting.py b/limap/fitting/fitting.py index 9dbb13d5..b6a192c1 100644 --- a/limap/fitting/fitting.py +++ b/limap/fitting/fitting.py @@ -1,6 +1,7 @@ import numpy as np from _limap import _estimators, _fitting from bresenham import bresenham + from hloc.localize_inloc import interpolate_scan diff --git a/limap/point2d/superglue/superglue.py b/limap/point2d/superglue/superglue.py index f4e5942f..ff9d01db 100644 --- a/limap/point2d/superglue/superglue.py +++ b/limap/point2d/superglue/superglue.py @@ -43,14 +43,13 @@ import os from copy import deepcopy from pathlib import Path -from typing import List, Tuple import torch from pycolmap import logging from torch import nn -def MLP(channels: List[int], do_bn: bool = True) -> nn.Module: +def MLP(channels: list[int], do_bn: bool = True) -> nn.Module: """Multi-layer perceptron""" n = len(channels) layers = [] @@ -78,7 +77,7 @@ def normalize_keypoints(kpts, image_shape): class KeypointEncoder(nn.Module): """Joint encoding of visual appearance and location using MLPs""" - def __init__(self, feature_dim: int, layers: List[int]) -> None: + def __init__(self, feature_dim: int, layers: list[int]) -> None: super().__init__() self.encoder = MLP([3] + layers + [feature_dim]) nn.init.constant_(self.encoder[-1].bias, 0.0) @@ -90,7 +89,7 @@ def forward(self, kpts, scores): def attention( query: torch.Tensor, key: torch.Tensor, value: torch.Tensor -) -> Tuple[torch.Tensor, torch.Tensor]: +) -> tuple[torch.Tensor, torch.Tensor]: dim = query.shape[1] scores = torch.einsum("bdhn,bdhm->bhnm", query, key) / dim**0.5 prob = torch.nn.functional.softmax(scores, dim=-1) @@ -135,7 +134,7 @@ def forward(self, x: torch.Tensor, source: torch.Tensor) -> torch.Tensor: class AttentionalGNN(nn.Module): - def __init__(self, feature_dim: int, layer_names: List[str]) -> None: + def __init__(self, feature_dim: int, layer_names: list[str]) -> None: super().__init__() self.layers = nn.ModuleList( [ @@ -147,7 +146,7 @@ def __init__(self, feature_dim: int, layer_names: List[str]) -> None: def forward( self, desc0: torch.Tensor, desc1: torch.Tensor - ) -> Tuple[torch.Tensor, torch.Tensor]: + ) -> tuple[torch.Tensor, torch.Tensor]: for layer, name in zip(self.layers, self.names): if name == "cross": src0, src1 = desc1, desc0 diff --git a/limap/point2d/superpoint/main.py b/limap/point2d/superpoint/main.py index 8735f992..f7411087 100644 --- a/limap/point2d/superpoint/main.py +++ b/limap/point2d/superpoint/main.py @@ -1,16 +1,17 @@ import collections.abc as collections import pprint from pathlib import Path -from typing import Dict, List, Optional, Union +from typing import Optional, Union import h5py import numpy as np import torch -from hloc import extract_features -from hloc.utils.io import list_h5_names from pycolmap import logging from tqdm import tqdm +from hloc import extract_features +from hloc.utils.io import list_h5_names + from .superpoint import SuperPoint string_classes = str @@ -34,11 +35,11 @@ def map_tensor(input_, func): @torch.no_grad() def run_superpoint( - conf: Dict, + conf: dict, image_dir: Path, export_dir: Optional[Path] = None, as_half: bool = True, - image_list: Optional[Union[Path, List[str]]] = None, + image_list: Optional[Union[Path, list[str]]] = None, feature_path: Optional[Path] = None, overwrite: bool = False, keypoints=None, diff --git a/limap/pointsfm/colmap_sfm.py b/limap/pointsfm/colmap_sfm.py index b1562f52..4da3a425 100644 --- a/limap/pointsfm/colmap_sfm.py +++ b/limap/pointsfm/colmap_sfm.py @@ -9,9 +9,10 @@ from pycolmap import logging sys.path.append(os.path.dirname(os.path.abspath(__file__))) +from model_converter import convert_imagecols_to_colmap + import hloc.utils.database as database import hloc.utils.read_write_model as colmap_utils -from model_converter import convert_imagecols_to_colmap def import_images_with_known_cameras(image_dir, database_path, imagecols): diff --git a/limap/pointsfm/model_converter.py b/limap/pointsfm/model_converter.py index e13524ad..3c6abff0 100644 --- a/limap/pointsfm/model_converter.py +++ b/limap/pointsfm/model_converter.py @@ -4,9 +4,10 @@ from limap.util.geometry import rotation_from_quaternion sys.path.append(os.path.dirname(os.path.abspath(__file__))) -import hloc.utils.read_write_model as colmap_utils from colmap_reader import PyReadCOLMAP +import hloc.utils.read_write_model as colmap_utils + def convert_colmap_to_visualsfm(colmap_model_path, output_nvm_file): reconstruction = PyReadCOLMAP(colmap_model_path) diff --git a/limap/runners/hybrid_localization.py b/limap/runners/hybrid_localization.py index b854c507..2030d8c5 100644 --- a/limap/runners/hybrid_localization.py +++ b/limap/runners/hybrid_localization.py @@ -2,7 +2,6 @@ from collections import defaultdict import numpy as np -from hloc.utils.io import get_keypoints, get_matches from pycolmap import logging from tqdm import tqdm @@ -11,6 +10,7 @@ import limap.line2d import limap.runners as runners import limap.util.io as limapio +from hloc.utils.io import get_keypoints, get_matches from limap.optimize.hybrid_localization.functions import ( filter_line_2to2_epipolarIoU, get_reprojection_dist_func, diff --git a/ruff.toml b/ruff.toml index 3aa6f99f..93e59ee2 100644 --- a/ruff.toml +++ b/ruff.toml @@ -15,6 +15,7 @@ select = [ # isort "I", ] +ignore = ['I001'] [lint.per-file-ignores] "limap/line2d/L2D2/RAL_net_cov.py" = ["SIM"] diff --git a/runners/7scenes/localization.py b/runners/7scenes/localization.py index 4775df5a..e08f56d0 100644 --- a/runners/7scenes/localization.py +++ b/runners/7scenes/localization.py @@ -10,9 +10,7 @@ import pickle from pathlib import Path -import hloc.utils.read_write_model as colmap_utils import pycolmap -from hloc.utils.parsers import parse_retrieval from utils import ( DepthReader, evaluate, @@ -22,9 +20,11 @@ run_hloc_7scenes, ) +import hloc.utils.read_write_model as colmap_utils import limap.runners as runners import limap.util.config as cfgutils import limap.util.io as limapio +from hloc.utils.parsers import parse_retrieval formatter = logging.Formatter( fmt="[%(asctime)s %(name)s %(levelname)s] %(message)s", diff --git a/runners/7scenes/utils.py b/runners/7scenes/utils.py index f4eef0ba..9ecbf758 100644 --- a/runners/7scenes/utils.py +++ b/runners/7scenes/utils.py @@ -7,6 +7,11 @@ import PIL.Image import pycolmap import torch +from tqdm import tqdm + +import limap.base as base +import limap.pointsfm as pointsfm +import limap.util.io as limapio from hloc import ( extract_features, localize_sfm, @@ -19,11 +24,6 @@ evaluate, ) from hloc.utils.read_write_model import read_model, write_model -from tqdm import tqdm - -import limap.base as base -import limap.pointsfm as pointsfm -import limap.util.io as limapio ############################################################################### # The following utils functions are taken/modified from hloc.pipelines.7scenes diff --git a/runners/cambridge/localization.py b/runners/cambridge/localization.py index 495aa1cc..c1d2c6d3 100644 --- a/runners/cambridge/localization.py +++ b/runners/cambridge/localization.py @@ -10,7 +10,6 @@ import pickle from pathlib import Path -from hloc.utils.parsers import parse_retrieval from utils import ( eval, get_result_filenames, @@ -23,6 +22,7 @@ import limap.runners as runners import limap.util.config as cfgutils import limap.util.io as limapio +from hloc.utils.parsers import parse_retrieval formatter = logging.Formatter( fmt="[%(asctime)s %(name)s %(levelname)s] %(message)s", diff --git a/runners/cambridge/utils.py b/runners/cambridge/utils.py index 5996dadf..23c8e120 100644 --- a/runners/cambridge/utils.py +++ b/runners/cambridge/utils.py @@ -11,17 +11,17 @@ import imagesize import pycolmap +from tqdm import tqdm + +import limap.base as base +import limap.pointsfm as pointsfm +import limap.util.io as limapio from hloc import ( extract_features, localize_sfm, match_features, pairs_from_retrieval, ) -from tqdm import tqdm - -import limap.base as base -import limap.pointsfm as pointsfm -import limap.util.io as limapio def read_scene_visualsfm( diff --git a/runners/inloc/utils.py b/runners/inloc/utils.py index 26d5c61b..f6762d0e 100644 --- a/runners/inloc/utils.py +++ b/runners/inloc/utils.py @@ -3,13 +3,13 @@ import imagesize import numpy as np -from hloc import extract_features, localize_inloc, match_features -from hloc.utils.parsers import parse_retrieval from scipy.io import loadmat from tqdm import tqdm import limap.base as base import limap.util.io as limapio +from hloc import extract_features, localize_inloc, match_features +from hloc.utils.parsers import parse_retrieval class InLocP3DReader(base.BaseP3DReader): diff --git a/scripts/format/python.sh b/scripts/format/python.sh index 7dd575c3..b840a8a1 100755 --- a/scripts/format/python.sh +++ b/scripts/format/python.sh @@ -4,7 +4,7 @@ # Check version version_string=$(ruff --version | sed -E 's/^.*(\d+\.\d+-.*).*$/\1/') -expected_version_string='0.6.7' +expected_version_string='0.8.6' if [[ "$version_string" =~ "$expected_version_string" ]]; then echo "ruff version '$version_string' matches '$expected_version_string'" else diff --git a/setup.py b/setup.py index 1ea0e7d4..0093f3f2 100644 --- a/setup.py +++ b/setup.py @@ -69,7 +69,7 @@ def build_extension(self, ext): name="limap", version="1.0.0", packages=find_packages(), - python_requires=">=3.8, < 3.12", + python_requires=">=3.9, < 3.12", author="Shaohui Liu", author_email="b1ueber2y@gmail.com", description="A toolbox for mapping and localization with line features",