def refine_junction_perturb(
        self, junctions: Tensor, line_map: Tensor, heatmap: Tensor, H: int, W: int, device: torch.device
    ) -> Tuple[Tensor, Tensor]:
        """Refine the line endpoints in a similar way as in LSD."""
        # Fetch refinement parameters
        if not isinstance(self.junction_refine_cfg, JunctionRefineCfg):
            raise TypeError(
                "Expected to have dataclass of type JunctionRefineCfg for junction."
                f"Gotcha {type(self.junction_refine_cfg)}"
            )
        num_perturbs = self.junction_refine_cfg.num_perturbs
        perturb_interval = self.junction_refine_cfg.perturb_interval
        side_perturbs = (num_perturbs - 1) // 2

        # Fetch the 2D perturb mat
        perturb_vec = torch.arange(
            start=-perturb_interval * side_perturbs,
            end=perturb_interval * (side_perturbs + 1),
            step=perturb_interval,
            device=device,
        )

        h1_grid, w1_grid, h2_grid, w2_grid = torch_meshgrid(
            [perturb_vec, perturb_vec, perturb_vec, perturb_vec], indexing="ij"
        )

        perturb_tensor = concatenate(
            [h1_grid[..., None], w1_grid[..., None], h2_grid[..., None], w2_grid[..., None]], -1
        )
        perturb_tensor_flat = perturb_tensor.view(-1, 2, 2)

        # Fetch all the detected lines
        detected_seg_indexes = where(torch.triu(line_map, diagonal=1))
        start_points = junctions[detected_seg_indexes[0]]
        end_points = junctions[detected_seg_indexes[1]]
        line_segments = stack([start_points, end_points], 1)

        line_segment_candidates = line_segments.unsqueeze(dim=1) + perturb_tensor_flat[None]
        # Clip the boundaries
        line_segment_candidates[..., 0] = torch.clamp(line_segment_candidates[..., 0], min=0, max=H - 1)
        line_segment_candidates[..., 1] = torch.clamp(line_segment_candidates[..., 1], min=0, max=W - 1)

        # Iterate through all the segments
        refined_segment_lst = []
        num_segments = len(line_segments)
        for idx in range(num_segments):
            segment = line_segment_candidates[idx]
            # Get the corresponding start and end junctions
            candidate_junc_start = segment[:, 0]
            candidate_junc_end = segment[:, 1]

            # Get the sampling locations (N x 64)
            sampler = self.torch_sampler.to(device)[None]
            cand_samples_h = candidate_junc_start[:, 0:1] * sampler + candidate_junc_end[:, 0:1] * (1 - sampler)
            cand_samples_w = candidate_junc_start[:, 1:2] * sampler + candidate_junc_end[:, 1:2] * (1 - sampler)

            # Clip to image boundary
            cand_h = torch.clamp(cand_samples_h, min=0, max=H - 1)
            cand_w = torch.clamp(cand_samples_w, min=0, max=W - 1)

            # Perform bilinear sampling
            segment_feat = self.detect_bilinear(heatmap, cand_h, cand_w)
            segment_results = torch.mean(segment_feat, dim=-1)
            max_idx = torch.argmax(segment_results)
            refined_segment_lst.append(segment[max_idx][None])

        # Concatenate back to segments
        refined_segments = concatenate(refined_segment_lst, 0)

        # Convert back to junctions and line_map
        junctions_new = concatenate([refined_segments[:, 0, :], refined_segments[:, 1, :]], 0)
        junctions_new = torch.unique(junctions_new, dim=0)
        line_map_new = self.segments_to_line_map(junctions_new, refined_segments)

        return junctions_new, line_map_new
Refine the line endpoints in a similar way as in LSD.
kornia/feature/sold2/sold2_detector.py