Line detection, description and matching

Line segments are detected, optionally described, and matched across image pairs. Methods are selected by name through the registries below; each returns an implementation of the base interfaces.

Instantiate a line detector / descriptor

limap.image.line.get_detector(method: str, loptions: DetectorOptions)
limap.image.line.get_extractor(method: str, loptions: ExtractorOptions)

Get a line descriptor speicified by cfg_extractor[“method”]

Parameters:

cfg_extractor – config for the line extractor

limap.image.line.get_uncertainty2d(method: str) float

Get the default 2D uncertainty for a line detector.

Parameters:

method – Name of the line detector (e.g., “lsd”, “deeplsd”, “sold2”).

Returns:

Default 2D uncertainty value in pixels for the specified detector.

Raises:

ValueError – If the detector method is not recognized.

class limap.image.line.DetectorOptions(base_options: limap.image.line.base_detector.BaseDetectorOptions = <factory>)
__init__(base_options: BaseDetectorOptions = <factory>) None
base_options: BaseDetectorOptions
class limap.image.line.ExtractorOptions(base_options: limap.image.line.base_detector.BaseDetectorOptions = <factory>)
__init__(base_options: BaseDetectorOptions = <factory>) None
base_options: BaseDetectorOptions

Instantiate a line matcher

limap.image.line.get_matcher(method: str, loptions: MatcherOptions, extractor: Any)
class limap.image.line.MatcherOptions(base_options: limap.image.line.base_matcher.BaseMatcherOptions = <factory>, superglue_options: limap.image.line.register_matcher.SuperGlueMatcherOptions = <factory>, dense_options: limap.image.line.register_matcher.DenseMatcherOptions = <factory>)
__init__(base_options: BaseMatcherOptions = <factory>, superglue_options: SuperGlueMatcherOptions = <factory>, dense_options: DenseMatcherOptions = <factory>) None
base_options: BaseMatcherOptions
dense_options: DenseMatcherOptions
superglue_options: SuperGlueMatcherOptions
class limap.image.line.register_matcher.SuperGlueMatcherOptions(weights: str = 'outdoor')
__init__(weights: str = 'outdoor') None
weights: str = 'outdoor'
class limap.image.line.register_matcher.DenseMatcherOptions(one_to_many: bool = False, weights: str = 'outdoor')
__init__(one_to_many: bool = False, weights: str = 'outdoor') None
one_to_many: bool = False
weights: str = 'outdoor'

Base interfaces

Implemented by every method under limap/image/line/; a new method needs a subclass of these plus one branch in the registry above.

class limap.image.line.base_detector.BaseDetector(options=BaseDetectorOptions(set_gray=True, max_num_2d_segs=3000, do_merge_lines=False, visualize=False, weight_path=None))

Virtual class for line detector

__init__(options=BaseDetectorOptions(set_gray=True, max_num_2d_segs=3000, do_merge_lines=False, visualize=False, weight_path=None))
detect(image_path: Path) ndarray

Virtual method (for detector) - detect 2D line segments

Parameters:

image_path – full path to the image

Returns:

line detections. Each row corresponds to x1, y1, x2, y2 and score.

Return type:

np.array of shape (N, 5)

detect_all_images(output_folder, image_paths, skip_exists=False)

Perform line detection on all images and save the line segments

Parameters:
  • output_folder (str) – The output folder

  • image_paths (dict[int, pathlib.Path]) – mapping from image id to full image path

  • skip_exists (bool) – Whether to skip already processed images

Returns:

The line detection for each image indexed by the image id. Each segment is with shape (N, 5). Each row corresponds to x1, y1, x2, y2 and score.

Return type:

dict[int -> np.array]

detect_and_extract(image_path: Path) tuple[ndarray, Any]

Virtual method (for dual-functional class that can perform both detection and extraction) - Detect and extract on a single image

Parameters:

image_path – full path to the image

Returns:

of shape (N, 5), line detections. Each row corresponds to x1, y1, x2, y2 and score. Computed from the detect method. descinfo: The features extracted from the function extract

Return type:

segs (np.array)

detect_and_extract_all_images(output_folder, image_paths, skip_exists=False)

Perform line detection and description on all images and save the line segments and descriptors

Parameters:
  • output_folder (str) – The output folder

  • image_paths (dict[int, pathlib.Path]) – mapping from image id to full image path

  • skip_exists (bool) – Whether to skip already processed images

Returns:

The line detection for each image indexed by the image id. Each segment is with shape (N, 5). Each row corresponds to x1, y1, x2, y2 and score. descinfo_folder (str): Path to the extracted descriptors.

Return type:

all_segs (dict[int -> np.array])

extract(image_path: Path, segs: ndarray) Any

Virtual method (for extractor) - extract the features for the detected segments

Parameters:
  • image_path – full path to the image

  • segsnp.array of shape (N, 5), line detections. Each row corresponds to x1, y1, x2, y2 and score. Computed from the detect method.

Returns:

The extracted feature

extract_all_images(output_folder, image_paths, all_2d_segs, skip_exists=False)

Line descriptor extraction on all images and save the descriptors.

Parameters:
  • output_folder (str) – The output folder.

  • image_paths (dict[int, pathlib.Path]) – mapping from image id to full image path

  • all_2d_segs (dict[int -> np.array]) – The line detection for each image indexed by the image id. Each segment is with shape (N, 5). Each row corresponds to x1, y1, x2, y2 and score. Computed from detect_all_images

  • skip_exists (bool) – Whether to skip already processed images.

Returns:

The path to the saved descriptors.

Return type:

descinfo_folder (str)

get_descinfo_fname(descinfo_folder: Path, img_id: int) Path

Virtual method (for extractor) - Get the target filename of the extracted feature

Parameters:
  • descinfo_folder (pathlib.Path) – The output folder

  • img_id (int) – The image id

Returns:

target filename

Return type:

pathlib.Path

get_descinfo_folder(output_folder: Path) Path

Return the folder path to the extracted descriptors

Parameters:

output_folder (pathlib.Path) – The output folder

Returns:

The path to the saved descriptors

Return type:

path_to_descinfos (pathlib.Path)

get_module_name() str

Virtual method (need to be implemented) - return the name of the module

get_segments_folder(output_folder: Path) Path

Return the folder path to the detected segments

Parameters:

output_folder (pathlib.Path) – The output folder

Returns:

The path to the saved segments

Return type:

path_to_segments (pathlib.Path)

merge_lines(segs)
read_descinfo(descinfo_folder: Path, img_id: Any) Any

Virtual method (for extractor) - Read in the extracted feature. Dual function for save_descinfo.

Parameters:
  • descinfo_folder (pathlib.Path) – The output folder

  • img_id (int) – The image id

Returns:

The extracted feature

sample_descinfo_by_indexes(descinfo: Any, indexes: list[int]) Any

Virtual method (for dual-functional class that can perform both detection and extraction) - sample descriptors for a subset of images

Parameters:
  • descinfo – The features extracted from the function extract.

  • indexes (list[int]) – List of image ids for the subset.

save_descinfo(descinfo_folder: Path, img_id: int, descinfo: Any) None

Virtual method (for extractor) - Save the extracted feature to the target folder

Parameters:
  • descinfo_folder (pathlib.Path) – The output folder

  • img_id (int) – The image id

  • descinfo – The features extracted from the function extract

take_longest_k(segs, max_num_2d_segs=3000)
visualize_segs(output_folder, image_paths, first_k=10)
class limap.image.line.base_detector.BaseDetectorOptions(set_gray: bool = True, max_num_2d_segs: int = 3000, do_merge_lines: bool = False, visualize: bool = False, weight_path: Path | None = None)

Base options for the line detector

Parameters:
  • set_gray – whether to set the image to gray scale (sometimes depending on the detector)

  • max_num_2d_segs – maximum number of detected line segments (default = 3000)

  • do_merge_lines – whether to merge close similar lines at post-processing (default = False)

  • visualize – whether to output visualizations into output folder along with the detections (default = False)

  • weight_path – root directory to load/store weights (at default, ~/.cache/limap, overridable with the LIMAP_WEIGHTS_PATH environment variable)

__init__(set_gray: bool = True, max_num_2d_segs: int = 3000, do_merge_lines: bool = False, visualize: bool = False, weight_path: Path | None = None) None
do_merge_lines: bool = False
max_num_2d_segs: int = 3000
set_gray: bool = True
visualize: bool = False
weight_path: Path | None = None
class limap.image.line.base_matcher.BaseMatcher(extractor, options=BaseMatcherOptions(topk=0, n_neighbors=20, n_jobs=1, weight_path=None))

Virtual class for line matcher

__init__(extractor, options=BaseMatcherOptions(topk=0, n_neighbors=20, n_jobs=1, weight_path=None))
get_match_filename(matches_folder: Path, idx: int) Path

Return the filename of the matches specified by an image id

Parameters:
  • matches_folder (pathlib.Path) – The output matching folder

  • idx (int) – image id

get_matches_folder(output_folder: Path) Path

Return the folder path to the output matches

Parameters:

output_folder (pathlib.Path) – The output folder

Returns:

The path to the saved matches

Return type:

path_to_matches (pathlib.Path)

get_module_name()

Virtual method (need to be implemented) - return the name of the module

match_all_exhaustive_pairs(output_folder, image_ids, descinfo_folder, skip_exists=False)

Match all images exhaustively

Parameters:
  • output_folder (pathlib.Path) – The output folder

  • image_ids (list[int]) – list of image ids

  • descinfo_folder (pathlib.Path) – The folder storing all descriptors

  • skip_exists (bool) – Whether to skip already processed images

Returns:

The output matching folder

Return type:

matches_folder

match_all_neighbors(output_folder, image_ids, neighbors, descinfo_folder, skip_exists=False)

Match all images with its visual neighbors

Parameters:
  • output_folder (pathlib.Path) – The output folder

  • image_ids (list[int]) – list of image ids

  • neighbors (dict[int -> list[int]]) – visual neighbors for each image

  • descinfo_folder (str) – The folder storing all the descriptors

  • skip_exists (bool) – Whether to skip already processed images

Returns:

The output matching folder

Return type:

matches_folder

match_pair(descinfo1, descinfo2)

Virtual method (need to be implemented) - match two set of lines based on the descriptors

read_descinfo(descinfo_folder, idx)
read_match(matches_folder: Path, idx: int) dict[int, ndarray]

Read the matches for one image with its neighbors

Parameters:
  • matches_folder (pathlib.Path) – The output matching folder

  • idx (int) – image id

Returns:

The output matches for each neighboring image, each with shape (N, 2)

Return type:

matches (dict[int -> np.array])

save_match(matches_folder: Path, idx: int, matches: dict[int, ndarray]) None

Save the output matches from one image to its neighbors

Parameters:
  • matches_folder (pathlib.Path) – The output matching folder

  • idx (int) – image id

  • matches (dict[int -> np.array]) – The output matches for each neighboring image, each with shape (N, 2)

class limap.image.line.base_matcher.BaseMatcherOptions(topk: int = 0, n_neighbors: int = 20, n_jobs: int = 1, weight_path: Path | None = None)

Base options for the line matcher

Parameters:
  • topk – number of top matches for each line (if equal to 0, do mutual nearest neighbor matching)

  • n_neighbors – number of visual neighbors, only for naming the output folder

  • n_jobs – number of jobs at multi-processing (please make sure not to exceed the GPU memory limit with learning methods)

  • weight_path – root directory to load/store weights (at default, ~/.cache/limap, overridable with the LIMAP_WEIGHTS_PATH environment variable)

__init__(topk: int = 0, n_neighbors: int = 20, n_jobs: int = 1, weight_path: Path | None = None) None
n_jobs: int = 1
n_neighbors: int = 20
topk: int = 0
weight_path: Path | None = None

Detection and matching over a set of images

The batch helpers the pipelines call, writing their output into the structure database.

class limap.image.line.LineDetectionOptions(skip_exists: bool = True, compute_descinfo: bool = True, weight_path: pathlib.Path = PosixPath('/local/home/shaoliu/.limap/models'), detector_method: str = 'deeplsd', extractor_method: str | None = 'wireframe', _detector_options: limap.image.line.register_detector.DetectorOptions = <factory>, _extractor_options: limap.image.line.register_detector.ExtractorOptions = <factory>)
__init__(skip_exists: bool = True, compute_descinfo: bool = True, weight_path: Path = PosixPath('/local/home/shaoliu/.limap/models'), detector_method: str = 'deeplsd', extractor_method: str | None = 'wireframe', _detector_options: DetectorOptions = <factory>, _extractor_options: ExtractorOptions = <factory>) None
compute_descinfo: bool = True
detector_method: str = 'deeplsd'
property detector_options: DetectorOptions
extractor_method: str | None = 'wireframe'
property extractor_options: ExtractorOptions
skip_exists: bool = True
weight_path: Path = PosixPath('/local/home/shaoliu/.limap/models')
limap.image.line.line_detection(image_paths: dict[int, Path], output_dir, options: LineDetectionOptions) tuple[dict[int, ndarray], Path | None]
class limap.image.line.LineMatcherOptions(skip_exists: bool = True, weight_path: pathlib.Path = PosixPath('/local/home/shaoliu/.limap/models'), method: str = 'gluestick', _matching_options: limap.image.line.register_matcher.MatcherOptions = <factory>)
__init__(skip_exists: bool = True, weight_path: Path = PosixPath('/local/home/shaoliu/.limap/models'), method: str = 'gluestick', _matching_options: MatcherOptions = <factory>) None
property matching_options: MatcherOptions
method: str = 'gluestick'
skip_exists: bool = True
weight_path: Path = PosixPath('/local/home/shaoliu/.limap/models')
limap.image.line.line_matching(descinfo_folder: Path, output_dir: Path, neighbors: dict[int, list[int]], det_options: LineDetectionOptions, options: LineMatcherOptions) Path
limap.image.line.exhaustive_line_matching(descinfo_folder: Path, output_dir: Path, image_ids: list[int], det_options: LineDetectionOptions, options: LineMatcherOptions) Path