o
    oi:                  
   @   s$  U d dl Z d dlmZmZmZmZ d dlZd dlm  m	Z
 d dlmZmZmZ d dlmZ d dlmZmZ d dlmZ d dlmZmZ dd	lmZ dd
lmZmZmZ i Zee e f e!d< ded< G dd deZ"G dd deZ#dedee$e$f defddZ%dedede$de$def
ddZ&dS )    N)AnyDictOptionalTuple)ModuleTensorconcatenate)KORNIA_CHECK_SHAPE)DetectorCfgLineMatcherCfg)normalize_pixel_coordinates)dataclass_to_dictdict_to_dataclass   )SOLD2Net)LineSegmentDetectionModuleline_map_to_segmentsprob_to_junctionsurlsz<http://cmp.felk.cvut.cz/~mishkdmy/models/sold2_wireframe.pth	wireframec                
       s   e Zd ZdZddedee ddf fddZd	ede	e
ef fd
dZdededededef
ddZde	e
ef de	e
ef fddZ  ZS )SOLD2u  Module, which detects and describe line segments in an image.

    This is based on the original code from the paper "SOLD²: Self-supervised
    Occlusion-aware Line Detector and Descriptor". See :cite:`SOLD22021` for more details.

    Args:
        config: Dict specifying parameters. None will load the default parameters,
            which are tuned for images in the range 400~800 px.
        pretrained: If True, download and set pretrained weights to the model.

    Returns:
        The raw junction and line heatmaps, the semi-dense descriptor map,
        as well as the list of detected line segments (ij coordinates convention).

    Example:
        >>> images = torch.rand(2, 1, 64, 64)
        >>> sold2 = SOLD2()
        >>> outputs = sold2(images)
        >>> line_seg1 = outputs["line_segments"][0]
        >>> line_seg2 = outputs["line_segments"][1]
        >>> desc1 = outputs["dense_desc"][0]
        >>> desc2 = outputs["dense_desc"][1]
        >>> matches = sold2.match(line_seg1, line_seg2, desc1[None], desc2[None])

    TN
pretrainedconfigreturnc                    s   t |trtjdtdd t|t}t   |d ur|nt | _	d| j	_
| j	j| _| j	j| _| j	j| _tt| j	| _|rXtjjtd tdd}| |d }| j| |   t| j	j| _t| j	j| _d S )	NzUsage of config as a plain dictionary is deprecated in favor of `kornia.features.sold2.structures.DetectorCfg`. The support of plain dictionariesas config will be removed in kornia v0.8.0 (December 2024).   )category
stacklevelTr   cpu)map_locationmodel_state_dict) 
isinstancedictwarningswarnDeprecationWarningr   r
   super__init__r   use_descriptor	grid_sizedetection_threshjunc_detect_threshmax_num_junctionsr   r   modeltorchhubload_state_dict_from_urlr   deviceadapt_state_dictload_state_dictevalr   line_detector_cfgline_detectorWunschLineMatcherline_matcher_cfgline_matcher)selfr   r   pretrained_dict
state_dict	__class__ N/home/ubuntu/.local/lib/python3.10/site-packages/kornia/feature/sold2/sold2.pyr&   @   s*   





zSOLD2.__init__imgc           
      C   s   t |g d i }| |}|d |d< |d |d< |d |d< g }t|d |d D ] \}}t|| j| j| j}| j||\}}}	|	t
|| q+||d< |S )	a  Run forward.

        Args:
            img: batched images with shape :math:`(B, 1, H, W)`.

        Returns:
            line_segments: list of N line segments in each of the B images :math:`List[(N, 2, 2)]`.
            junction_heatmap: raw junction heatmap of shape :math:`(B, H, W)`.
            line_heatmap: raw line heatmap of shape :math:`(B, H, W)`.
            dense_desc: the semi-dense descriptor map of shape :math:`(B, 128, H/4, W/4)`.

        )B1HW	junctionsjunction_heatmapheatmapline_heatmapdescriptors
dense_descline_segments)r	   r,   zipr   r(   r*   r+   r5   detectappendr   )
r9   r@   outputsnet_outputslines	junc_probrG   rE   line_map_r>   r>   r?   forward`   s   
zSOLD2.forward	line_seg1	line_seg2desc1desc2c                 C   s   |  ||||S )a  Find the best matches between two sets of line segments and their corresponding descriptors.

        Args:
            line_seg1: list of line segments in image 1, with shape [num_lines, 2, 2].
            line_seg2: list of line segments in image 2, with shape [num_lines, 2, 2].
            desc1: semi-dense descriptor map of image 1, with shape [1, 128, H/4, W/4].
            desc2: semi-dense descriptor map of image 2, with shape [1, 128, H/4, W/4].

        Returns:
            A np.array of size [num_lines1] indicating the index in line_seg2 of the matched line,
            for each line in line_seg1. -1 means that the line is not matched.

        )r8   )r9   rV   rW   rX   rY   r>   r>   r?   match   s   zSOLD2.matchr;   c                 C   s:   |d= |d= |d= |d |d< |d |d< |d= |d= |S )Nw_junc	w_heatmapw_descz'heatmap_decoder.conv_block_lst.2.weightz)heatmap_decoder.conv_block_lst.2.0.weightz%heatmap_decoder.conv_block_lst.2.biasz'heatmap_decoder.conv_block_lst.2.0.biasr>   )r9   r;   r>   r>   r?   r1      s   zSOLD2.adapt_state_dict)TN)__name__
__module____qualname____doc__boolr   r
   r&   r   r   strr   rU   rZ   r1   __classcell__r>   r>   r<   r?   r   %   s      #*r   c                
       s   e Zd ZdZddee ddf fddZdeded	ed
edef
ddZdede	eef fddZ
dedefddZdedefddZ  ZS )r6   zClass matching two sets of line segments with the Needleman-Wunsch algorithm.

    TODO: move it later in kornia.feature.matching
    Nr   r   c                    s^   t    |d u rt }|| _| jj| _| jj| _| jj| _| jj| _| jj| _| jj	| _	d S N)
r%   r&   r   r   cross_checknum_samplesmin_dist_ptstop_k_candidatesr(   
line_score)r9   r   r<   r>   r?   r&      s   





zWunschLineMatcher.__init__rV   rW   rX   rY   c                 C   s  t |g d t |g d t |g d t |g d |j}|jd | j |jd | j f}|jd | j |jd | j f}t|dkrNtjdtj|dS t|dkr`tjt|tj|d S | 	|\}}	| 	|\}
}|
dd}|

dd}
t||}t|
|}tjtj||dd	dd
d
d
d
df dd}tjtj||dd	dd
d
d
d
df dd}| | }d||	  < d|d
d
|  f< |
t|| jt|| j}|dddd}| |}| jr| |dddd}|| tjt||dk}d|| < |S )z\Find the best matches between two sets of line segments and their corresponding descriptors.)N2rl   )rA   DrC   rC   r      r   dtyper0   F)align_cornersNdimr   r0   )r	   r0   shaper(   lenr-   emptyintonessample_line_pointsreshapekeypoints_to_gridF	normalizegrid_sampletflattenrg   permutefilter_and_match_linesrf   arange)r9   rV   rW   rX   rY   r0   	img_size1	img_size2line_points1valid_points1line_points2valid_points2grid1grid2scoresmatchesmatches2mutualr>   r>   r?   rU      s<     

..

zWunschLineMatcher.forwardline_segc                 C   s  |j \}}}| j}|j}tj|dddf |dddf  dd}tj|| j   d|d}|dddf 	d}|dddf |dddf  	d}	tj
||d	d}
|d 	d}|
| }||	|	d  }|
|	dk }||	d d	}||fS )
aE  Regularly sample points along each line segments, with a minimal distance between each point.

        Pad the remaining points.

        Args:
            line_seg: an Nx2x2 Tensor.

        Returns:
            line_points: an N x num_samples x 2 Tensor.
            valid_points: a boolean N x num_samples Tensor.
        Nr   r   rs   r   )minmaxru   rq   g        )rv   rg   r0   r-   normclamprh   floorry   	unsqueezer   masked_fill)r9   r   _NrT   Mdevlengthsnum_ptsorigdirsidxdenomalphaptsvalidr>   r>   r?   r{      s   *&z$WunschLineMatcher.sample_line_pointsr   c                 C   s>  t |g d |dd }|dk}|| d|d }|dd }|dk}|| d|d }|| d }tj|dddd| j df }tj||ddddddf dd}t|tj|dgd	gd}|j	\}	}
}}|
|	|
 ||f}| |}|
|	|
}ttj|dd|
d }|t|	|f }|S )
az  Use scores to keep the top k best lines.

        Compute the Needleman- Wunsch algorithm on each candidate pairs, and keep the highest score.

        Args:
            scores: a (N, M, n, n) Tensor containing the pairwise scores
                    of the elements to match.

        Returns:
            matches: a (N) Tensor containing the indices of the best match
        )r   rk   nr   rn   r   rq   r   r   rs   N)dims)r	   r   sumr-   argsortri   take_along_dimr   fliprv   r|   needleman_wunsch	remainderargmaxr   )r9   r   line_scores1valid_scores1line_scores2valid_scores2line_scores
topk_lines
top_scoresn_lines1top2kr   m	nw_scoresr   r>   r>   r?   r      s$   "$
z(WunschLineMatcher.filter_and_match_linesc                 C   s(  t |g d d}|j\}}}tj||d |d |jd}|| }td|| d D ]`}td|| }	t||d }
tj|	|
d |jd}|| }|dd|d |f }|dd||d f }|dd|d |d f |dd|d |d f  }tt||||dd||f< q*|ddddf S )a0  Batched implementation of the Needleman-Wunsch algorithm.

        The cost of the InDel operation is set to 0 by subtracting the gap
        penalty to the scores.

        Args:
            scores: a (B, N, M) Tensor containing the pairwise scores
                    of the elements to match.
        )rA   rk   r   g?r   ru   r   Nrq   )	r	   rv   r-   zerosr0   ranger   r   r   )r9   r   gaprA   rk   r   dpSki_mini_maxijupleftdiagr>   r>   r?   r   '  s   
4$z"WunschLineMatcher.needleman_wunschre   )r^   r_   r`   ra   r   r   r&   r   rU   r   r{   r   r   rd   r>   r>   r<   r?   r6      s    0(r6   	keypointsimg_sizer   c                 C   sN   t | ddg t| }t| ddddgf |d |d }|d|dd}|S )u   Convert a list of keypoints into a grid in [-1, 1]² that can be used in torch.nn.functional.interpolate.

    Args:
        keypoints: a tensor [N, 2] of N keypoints (ij coordinates convention).
        img_size: the original image size (H, W)

    rk   rl   Nr   r   rq   r   )r	   rw   r   view)r   r   n_pointsgrid_pointsr>   r>   r?   r}   C  s
   $r}   startendsteprt   c                 C   s^   ||  |d   |}dgt|j }|||< tj|tj| jd|}|  |||  }|S )z<Batch version of torch.normalize (similar to the numpy one).r   ro   )r   rw   rv   r-   r   floatr0   r|   )r   r   r   rt   	intervalsbroadcast_sizesamplesr>   r>   r?   batched_linspaceR  s   r   )'r"   typingr   r   r   r   r-   torch.nn.functionalnn
functionalr~   kornia.corer   r   r   kornia.core.checkr	   kornia.feature.sold2.structuresr
   r   kornia.geometry.conversionsr   kornia.utilsr   r   	backbonesr   sold2_detectorr   r   r   r   rc   __annotations__r   r6   ry   r}   r   r>   r>   r>   r?   <module>   s$   
y &"