a
    di<                     @   s:  U d dl mZmZmZ d dlZd dlmZ d dlm  mZ	 d dlm
Z
 d dlmZ d dl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< dddddddddddddddddddddddddddd 	dddd!dd"d#Zeed$< G d%d& d&ejZG d'd( d(ejZe
ee
d)d*d+Zd,d- ZdS ).    )DictOptionalTupleN)Tensor)normalize_pixel_coordinates)KORNIA_CHECK_SHAPE   )SOLD2Net)LineSegmentDetectionModuleline_map_to_segmentsprob_to_junctionsurlsz<http://cmp.felk.cvut.cz/~mishkdmy/models/sold2_wireframe.pth	wireframe         )Zinput_channeldepthZ
num_stacks
num_blocksZnum_classesT   gv?  g      ?@   gGz?g      @localg?gMbP?   )modeZratioZvalid_threshr   Zoverlap_ratio	   g      ?)Znum_perturbsZperturb_interval)	Zdetect_threshnum_samplesZinlier_threshZuse_candidate_suppressionZnms_dist_toleranceZuse_heatmap_refinementZheatmap_refine_cfgZuse_junction_refinementZjunction_refine_cfg
   )cross_checkr   min_dist_ptstop_k_candidates	grid_size)Zbackbone_cfgZuse_descriptorr    Zkeep_border_validdetection_threshmax_num_junctionsline_detector_cfgline_matcher_cfgdefault_cfgc                       s\   e Zd ZdZdeee d fddZeeddd	Z	eeeeed
ddZ
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, 512, 512)
        >>> 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configc                    s   t    |d u rtn|| _| jd | _| jdd| _| jdd| _t| j| _	|rt
jjtd dd d	}| |d
 }| j	| |   | jd | _tf i | jd | _tf i | jd | _d S )Nr    r!   g ?r"   r   r   c                 S   s   | S N )Zstoragelocr*   r*   c/var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/kornia/feature/sold2/sold2.py<lambda>Z       z SOLD2.__init__.<locals>.<lambda>)Zmap_locationZmodel_state_dictr#   r$   )super__init__r%   r(   r    getjunc_detect_threshr"   r	   modeltorchZhubZload_state_dict_from_urlr   adapt_state_dictZload_state_dictevalr#   r
   line_detectorWunschLineMatcherline_matcher)selfr'   r(   Zpretrained_dict
state_dict	__class__r*   r,   r0   N   s     
zSOLD2.__init__)imgreturnc           
      C   s   t |g d i }| |}|d |d< |d |d< |d |d< g }t|d |d D ]@\}}t|| j| j| j}| j||\}}}	|	t
|| qV||d< |S )	a  
        Args:
            img: batched images with shape :math:`(B, 1, H, W)`.

        Return:
            - ``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	junctionsZjunction_heatmapheatmapZline_heatmapZdescriptorsZ
dense_descZline_segments)r   r3   zipr   r    r2   r"   r7   detectappendr   )
r:   r>   outputsZnet_outputslinesZ	junc_probrE   rD   Zline_map_r*   r*   r,   forwardg   s    
zSOLD2.forward	line_seg1	line_seg2desc1desc2r?   c                 C   s   |  ||||S )a  Find the best matches between two sets of line segments and their corresponding descriptors.

        Args:
            line_seg1, line_seg2: list of line segments in two images, with shape [num_lines, 2, 2].
            desc1, desc2: semi-dense descriptor maps of the images, 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.
        )r9   )r:   rN   rO   rP   rQ   r*   r*   r,   match   s    
zSOLD2.matchc                 C   s:   |d= |d= |d= |d |d< |d |d< |d= |d= |S )NZw_juncZ	w_heatmapZ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*   )r:   r;   r*   r*   r,   r5      s    zSOLD2.adapt_state_dict)TN)__name__
__module____qualname____doc__boolr   r   r0   r   rL   rR   r5   __classcell__r*   r*   r<   r,   r&   4   s
   !r&   c                       sx   e Zd ZdZdeeeeeed fddZeeeeed	d
dZee	dddZ
eedddZeedddZ  ZS )r8   zClass matching two sets of line segments with the Needleman-Wunsch algorithm.

    TODO: move it later in kornia.feature.matching
    Tr   r   F)r   r   r   r   r    
line_scorec                    s2   t    || _|| _|| _|| _|| _|| _d S r)   )r/   r0   r   r   r   r   r    rY   )r:   r   r   r   r   r    rY   r<   r*   r,   r0      s    	
zWunschLineMatcher.__init__rM   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rtjdtj|dS t|dkrt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2r\   )r@   DrB   rB   r      r   dtypedeviceF)Zalign_cornersNdimr   )ra   )r   ra   shaper    lenr4   emptyintonessample_line_pointsreshapekeypoints_to_gridF	normalizeZgrid_sampletflattenr   Zpermutefilter_and_match_linesr   arange)r:   rN   rO   rP   rQ   ra   Z	img_size1Z	img_size2Zline_points1Zvalid_points1Zline_points2Zvalid_points2Zgrid1Zgrid2scoresmatchesZmatches2Zmutualr*   r*   r,   rL      s<      

..

zWunschLineMatcher.forward)line_segr?   c              	   C   s~  t |g d t|}tj|dddf |dddf  dd}ttj|| jddd| j }tj	|| jdftj
d	}tj	|| jftjd	}td| jd D ]}||k}|| }	t|	ddddf |	ddddf |d
d}
t|	ddddf |	ddddf |d
d}tj|
|gd
d}t|ddd| j| f}tjt|	| jtjd	}d|dd|df< |||< |||< q||fS )aE  Regularly sample points along each line segments, with a minimal distance between each point.

        Pad the remaining points.
        Inputs:
            line_seg: an Nx2x2 Tensor.
        Outputs:
            line_points: an N x num_samples x 2 Tensor.
            valid_points: a boolean N x num_samples Tensor.
        rZ   Nr   r   rc   floor)Zrounding_moder   r`   rb   F)r   rf   r4   Znormclampdivr   r   rh   rg   floatrW   rangebatched_linspacestackrm   padri   )r:   ru   Z	num_linesZline_lengthsZnum_samples_lstZline_pointsZvalid_pointsZn_sampZcur_maskZcur_line_segZline_points_xZline_points_yZcur_line_pointsZcur_valid_pointsr*   r*   r,   rj      s(    
*,,
z$WunschLineMatcher.sample_line_points)rs   r?   c                 C   sB  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j|tj|dgd	gdd}|j	\}	}
}}|
|	|
 ||f}| |}|
|	|
}ttj|dd|
d }|t|	|f }|S )
a~  Use the scores to keep the top k best lines, compute the Needleman- Wunsch algorithm on each candidate
        pairs, and keep the highest score.

        Inputs:
            scores: a (N, M, n, n) Tensor containing the pairwise scores
                    of the elements to match.
        Outputs:
            matches: a (N) Tensor containing the indices of the best match
        )Mr[   nr   r^   r   rb   r   r   rc   N)dims)r   maxsumr4   Zargsortr   Ztake_along_dimcatZflipre   rk   needleman_wunsch	remainderZargmaxrr   )r:   rs   Zline_scores1Zvalid_scores1Zline_scores2Zvalid_scores2Zline_scoresZ
topk_linesZ
top_scoresZn_lines1Ztop2kr   m	nw_scoresrt   r*   r*   r,   rq     s$    
"$
z(WunschLineMatcher.filter_and_match_linesc           
      C   s   t |g d |j\}}}d}|| }tj||d |d tjd}t|D ]}t|D ]r}	tt|dd|d |	f |dd||	d f |dd||	f |dd||	f  |dd|d |	d f< qVqJ|ddddf S )a1  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.
        Inputs:
            scores: a (B, N, M) Tensor containing the pairwise scores
                    of the elements to match.
        )r@   r[   r   g?r   rw   Nrb   )r   re   r4   zerosrz   r{   maximum)
r:   rs   br   r   Zgapr   Znw_gridijr*   r*   r,   r   2  s    	Pz"WunschLineMatcher.needleman_wunsch)Tr   r   r   r   F)rS   rT   rU   rV   rW   rh   r0   r   rL   r   rj   rq   r   rX   r*   r*   r<   r,   r8      s&         0'%r8   )	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)
    r[   r\   Nr   r   rb   r   )r   rf   r   view)r   r   Zn_pointsZgrid_pointsr*   r*   r,   rl   M  s
    $rl   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   r_   )Z	unsqueezerf   re   r4   rr   rz   ra   rk   )startendsteprd   Z	intervalsZbroadcast_sizeZsamplesr*   r*   r,   r|   [  s    r|   )typingr   r   r   r4   Ztorch.nnnnZtorch.nn.functionalZ
functionalrm   r   Zkornia.geometry.conversionsr   Zkornia.testingr   Z	backbonesr	   Zsold2_detectorr
   r   r   r   str__annotations__r%   Moduler&   r8   tuplerl   r|   r*   r*   r*   r,   <module>   sV   "k /