class_docstr: Class matching two sets of line segments with the Needleman-Wunsch algorithm.
  
  TODO: move it later in kornia.feature.matching
class_docstr_tok: ["Class","matching","two","sets","of","line","segments","with","the","Needleman-Wunsch","algorithm",".","TODO",":","move","it","later","in","kornia.feature.matching"]
docstr: Find the best matches between two sets of line segments and their corresponding descriptors.
docstr_tok: ["Find","the","best","matches","between","two","sets","of","line","segments","and","their","corresponding","descriptors","."]
code: def forward(
      self,
      line_seg1: Tensor,
      line_seg2: Tensor,
      desc1: Tensor,
      desc2: Tensor,
  ) -> Tensor:
      """Find the best matches between two sets of line segments and their corresponding descriptors."""
      KORNIA_CHECK_SHAPE(line_seg1, ["N", "2", "2"])
      KORNIA_CHECK_SHAPE(line_seg2, ["N", "2", "2"])
      KORNIA_CHECK_SHAPE(desc1, ["B", "D", "H", "H"])
      KORNIA_CHECK_SHAPE(desc2, ["B", "D", "H", "H"])
      device = desc1.device
      img_size1 = (
          desc1.shape[2] * self.grid_size,
          desc1.shape[3] * self.grid_size,
      )
      img_size2 = (
          desc2.shape[2] * self.grid_size,
          desc2.shape[3] * self.grid_size,
      )
  
      # Default case when an image has no lines
      if len(line_seg1) == 0:
          return torch.empty(0, dtype=torch.int, device=device)
      if len(line_seg2) == 0:
          return -torch.ones(
              len(line_seg1), dtype=torch.int, device=device
          )
  
      # Sample points regularly along each line
      line_points1, valid_points1 = self.sample_line_points(line_seg1)
      line_points2, valid_points2 = self.sample_line_points(line_seg2)
      line_points1 = line_points1.reshape(-1, 2)
      line_points2 = line_points2.reshape(-1, 2)
  
      # Extract the descriptors for each point
      grid1 = keypoints_to_grid(line_points1, img_size1)
      grid2 = keypoints_to_grid(line_points2, img_size2)
      desc1 = F.normalize(
          F.grid_sample(desc1, grid1, align_corners=False)[0, :, :, 0],
          dim=0,
      )
      desc2 = F.normalize(
          F.grid_sample(desc2, grid2, align_corners=False)[0, :, :, 0],
          dim=0,
      )
  
      # Precompute the distance between line points for every pair of lines
      # Assign a score of -1 for invalid points
      scores = desc1.t() @ desc2
      scores[~valid_points1.flatten()] = -1
      scores[:, ~valid_points2.flatten()] = -1
      scores = scores.reshape(
          len(line_seg1),
          self.num_samples,
          len(line_seg2),
          self.num_samples,
      )
      scores = scores.permute(0, 2, 1, 3)
      # scores.shape = (n_lines1, n_lines2, num_samples, num_samples)
  
      # Pre-filter the line candidates and find the best match for each line
      matches = self.filter_and_match_lines(scores)
  
      # [Optionally] filter matches with mutual nearest neighbor filtering
      if self.cross_check:
          matches2 = self.filter_and_match_lines(
              scores.permute(1, 0, 3, 2)
          )
          mutual = matches2[matches] == torch.arange(
              len(line_seg1), device=device
          )
          matches[~mutual] = -1
  
      return matches
  
imports: from typing import Any, Dict, Optional, Tuple
  import torch
  import torch.nn.functional
  from kornia.core import Module, Tensor, concatenate, pad, stack
  from kornia.core.check import KORNIA_CHECK_SHAPE
  from kornia.geometry.conversions import normalize_pixel_coordinates
  from kornia.utils import map_location_to_cpu
  from .backbones import SOLD2Net
  from .sold2_detector import LineSegmentDetectionModule, line_map_to_segments, prob_to_junctions
label_desc: Use image node_id 2 for calling the WunschLineMatcher obj's underlying member method code with example usage: obj.forward(line_seg1, line_seg2, desc1, desc2) and returns: matches, torch, unknown