o
    oij                     @   s  U d dl Z d dlZd dlmZmZmZmZ d dlZd dlm	Z	m
Z
mZmZmZmZmZmZ d dlmZ d dlmZmZmZmZ d dlmZ d dlmZmZmZ dd	lmZ i Z ee!e!f e"d
< de d< G dd de	Z#G dd dZ$de
de
de
fddZ%dde
de&de&de'de
f
ddZ(dS )    N)AnyDictOptionalTuple)ModuleTensorconcatenatesinstacktensorwherezeros)KORNIA_CHECK_SHAPE)DetectorCfgHeatMapRefineCfgJunctionRefineCfgLineDetectorCfg)nms)dataclass_to_dictdict_to_dataclasstorch_meshgrid   )SOLD2Neturlsz6https://cvg-data.inf.ethz.ch/SOLD2/sold2_wireframe.tar	wireframec                       sp   e Zd ZdZddedee ddf fddZd	ee	e
f dee	e
f fd
dZdedee	e
f fddZ  ZS )SOLD2_detectoru  Module, which detects 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 (DetectorCfg): Configuration object containing all parameters. None will load the default parameters,
            which are tuned for images in the range 400~800 px. Using a dataclass ensures type safety and clearer
            parameter management.
        pretrained (bool): If True, download and set pretrained weights to the model.

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

    Example:
        >>> img = torch.rand(1, 1, 128, 128)
        >>> sold2_detector = SOLD2_detector(pretrained=False)
        >>> line_segments = sold2_detector(img)["line_segments"]

    TN
pretrainedconfigreturnc                    s   t |trtjdtdd t|t}t   |d ur|nt | _	| j	j
| _
| j	j| _| j	j| _tt| j	| _|rTtjjtd tdd}| |d }| 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 plaindictionaries as config will be removed in kornia v0.8.0 (December 2024).   )category
stacklevelr   cpu)map_locationmodel_state_dict)
isinstancedictwarningswarnDeprecationWarningr   r   super__init__r   	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evalLineSegmentDetectionModuleline_detector_cfgline_detector)selfr   r   pretrained_dict
state_dict	__class__ W/home/ubuntu/.local/lib/python3.10/site-packages/kornia/feature/sold2/sold2_detector.pyr+   :   s&   





zSOLD2_detector.__init__r=   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@   )r;   r=   r@   r@   rA   r5   W   s   zSOLD2_detector.adapt_state_dictimgc           
      C   s   t |g d i }| |}|d |d< |d |d< g }t|d |d D ] \}}t|| j| j| j}| j||\}}}	|	t
|| q%||d< |S )ar  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)`.

        )B1HW	junctionsjunction_heatmapheatmapline_heatmapline_segments)r   r0   zipprob_to_junctionsr,   r.   r/   r:   detectappendline_map_to_segments)
r;   rE   outputsnet_outputslines	junc_probrL   rJ   line_map_r@   r@   rA   forwarda   s   
zSOLD2_detector.forward)TN)__name__
__module____qualname____doc__boolr   r   r+   r   strr   r5   r   rZ   __classcell__r@   r@   r>   rA   r   $   s
     ""
r   c                   @   s2  e Zd ZdZd+dee ddfddZdededeeeef fd	d
Z	d,dede
de
defddZ				d-dedede
de
de
defddZdededefddZdedededededejdeeef fdd Zded!edefd"d#Zded$ed%edefd&d'Zded$ed%ededed(edejdefd)d*ZdS ).r8   a  Module extracting line segments from junctions and line heatmaps.

    Args:
        config (LineDetectorCfg): Configuration dataclass containing all settings required for line segment detection.
            - detect_thresh (float): Probability threshold for mean activation (0. ~ 1.).
            - num_samples (int): Number of sampling locations along the line segments.
            - inlier_thresh (float): Minimum inlier ratio to satisfy (0. ~ 1.) => 0. means no threshold.
            - heatmap_low_thresh (float): Lowest threshold for pixel considered as a candidate in junction recovery.
            - heatmap_high_thresh (float): Higher threshold for NMS in junction recovery.
            - max_local_patch_radius (float): Maximum patch to be considered in local maximum search.
            - lambda_radius (float): Lambda factor in linear local maximum search formulation.
            - use_candidate_suppression (bool): Apply candidate suppression to break long segments into sub-segments.
            - nms_dist_tolerance (float): Distance tolerance for NMS. Decides whether the junctions are on the line.
            - use_heatmap_refinement (bool): Whether to use heatmap refinement methods.
            - heatmap_refine_cfg: Configuration for heatmap refinement methods.
            - use_junction_refinement (bool): Whether to use junction refinement methods.
            - junction_refine_cfg: Configuration for junction refinement methods.

    Example:
        >>> config = LineDetectorCfg(detect_thresh=0.6, use_heatmap_refinement=True)
        >>> module = LineSegmentDetectionModule(config)
        >>> junctions, heatmap = torch.rand(10, 2), torch.rand(256, 256)
        >>> line_map, junctions, _ = module.detect(junctions, heatmap)

    Nr   r   c                 C   s   |d u rt  }|| _| jj| _| jj| _| jj| _| jj| _| jj| _| jj| _	| jj
| _tdd| j| _| jj| _| jj| _| jj| _| jj| _| jrV| jd u rVtd| jj| _| jj| _| jrl| jd u rntdd S d S )Nr   r   z*[Error] Missing heatmap refinement config.z+[Error] Missing junction refinement config.)r   r   detect_threshnum_samplesinlier_threshmax_local_patch_radiuslocal_patch_radiuslambda_radiusheatmap_low_thresh
low_threshheatmap_high_threshhigh_threshr1   linspacetorch_sampleruse_candidate_suppressionnms_dist_toleranceuse_heatmap_refinementheatmap_refine_cfg
ValueErroruse_junction_refinementjunction_refine_cfg)r;   r   r@   r@   rA   r+      s,   












z#LineSegmentDetectionModule.__init__rJ   rL   c           "   
   C   s  t |ddg |j\}}|j}| jrAt| jtrA| jjdkr*| || jj	| jj
}n| jjdkrA| || jj| jj| jj	| jj
}t|}t||g|tjd}|dk rX|||fS tjtj||g|tjddd}| jrq| ||}t|}	t|	d	 d
 |	d d
 gd}
||
ddd	f  }||
dddf  }| j|d }|ddd	df | |ddd	df d|   }|ddddf | |ddddf d|   }tj|d	|d d}tj|d	|d d}ttj|tj|tj d dd}||d |d  d  }t|}d}||krt|| }g }t |D ]g}||d ksX||| |d | ddf }||| |d | ddf }||| |d |  }n ||| dddf }||| dddf }||| d }| !|||||||}|"| q"t|d	}n| !|||||||}tj#|dd| j$k}| j%d	krtj|| j$kdd|j&| j' }|| j%k} ||  }|
| }!d||!ddd	f |!dddf f< d||!dddf |!ddd	f f< | j(rt|!d	kr| )||||||\}}|||fS )zPerform line segment detection.rH   rI   globallocalr4   dtyper   r   diagonalr   .NNminmaxdim      ?i'  )*r   shaper4   rp   r%   rq   r   moderefine_heatmapratiovalid_threshrefine_heatmap_local
num_blocksoverlap_ratiolenr   r1   int32triuonesrn   candidate_suppressionr   r   rm   toclampsqrtsumfloat32mathceilrangedetect_local_maxrR   meanrb   rd   rx   rc   rs   refine_junction_perturb)"r;   rJ   rL   rH   rI   r4   num_junctionsline_map_predcandidate_mapcandidate_indicescandidate_index_mapcandidate_junc_startcandidate_junc_endsamplercand_samples_hcand_samples_wcand_hcand_wsegments_lengthnormalized_seg_lengthnum_cand
group_sizenum_itersampled_feat_lstiter_idxcand_h_cand_w_normalized_seg_length_sampled_feat_sampled_featdetection_resultsinlier_ratiodetection_results_inlierdetected_junc_indexesr@   r@   rA   rQ      s   
	
44$
  "
$$
z!LineSegmentDetectionModule.detect皙?{Gz?r   r   c                 C   s\   |||k }t j|ddd }t|jd | }t |d| }t j|| ddd}|S )z!Global heatmap refinement method.T)
descendingr   N              ?r}   )r1   sortr   r   r   r   r   )r;   rL   r   r   heatmap_valuessorted_values	top10_lenmax20r@   r@   rA   r   -  s   z)LineSegmentDetectionModule.refine_heatmap   r   Mb`?r   r   c                 C   sV  |j \}}d| }t|d|d |   }	t|d|d |   }
t|j tj|jd}t|j tj|jd}t|D ]e}t|D ]^}t||	 | }t||
 | }||d k r[||	 n|}||d k rg||
 n|}|||||f }| |kr| j	|||d}|||||f  |7  < |||||f  d7  < q?q9tj
|| ddd}|S )z Local heatmap refinement method.r   )rx   r4   )r   r   r   )r   r~   )r   roundr   r1   intr4   floatr   r   r   r   )r;   rL   r   r   r   r   rH   rI   increase_ratioh_blockw_block	count_mapheatmap_outputh_idxw_idxh_startw_starth_endw_end
subheatmapr@   r@   rA   r   7  s(   

z/LineSegmentDetectionModule.refine_heatmap_localr   c                 C   s  | j }tjtj|dd|d  d ddd }ttj|dd}|d }|d }||d	d	f }||d	d	f }	|||f }
|	| tj|	| ddd
  }|d |jdd }tj|dd}td||d
 |
d  }|dk|dk }ttd||d
 |d
  }|d
 t	| }||k}|| }t
|}tj|ddgd}||d td||f tj8 }||d td||f tj8 }|dk}d||| || f< |S )z:Suppress overlapping long lines in the candidate segments.r   r   )N.r   r|   r   ry   r   Nr{   zbij,bjk->bik).NN.r   )ro   r1   r   	unsqueezer   r   normeinsumacosr	   r   aranger   r   )r;   rJ   r   dist_toleranceline_dist_mapseg_indexesstart_point_idxsend_point_idxsstart_points
end_points
line_distsdir_vecs	cand_vecscand_vecs_normproj	proj_maskcand_angles
cand_distsjunc_dist_mask	junc_masknum_segsjunc_counts
final_maskr@   r@   rA   r   \  s4   ($$z0LineSegmentDetectionModule.candidate_suppressionrX   rH   rI   r4   c           '      C   s  t | jtstdt| j | jj}| jj}|d d }	tj| |	 ||	d  ||d}
t	|
|
|
|
gdd\}}}}t
|d |d |d |d gd}|ddd}ttj|dd	}||d
  }||d  }t||gd}|jdd|d  }tj|d d
|d d|d< tj|d d
|d d|d< g }t|}t|D ]}|| }|ddd
f }|dddf }| j|d }|ddd
df | |ddd
df d|   }|ddddf | |ddddf d|   }tj|d
|d d}tj|d
|d d} | ||| }!tj|!dd}"t|"}#|||# d  qt
|d
}$t
|$ddd
ddf |$dddddf gd
}%tj|%d
d}%| |%|$}&|%|&fS )z5Refine the line endpoints in a similar way as in LSD.zIExpected to have dataclass of type JunctionRefineCfg for junction.Gotcha r   r   )startendstepr4   ij)indexingr{   r|   ry   r   r   Nr   r}   ).r   )r%   rt   r   	TypeErrortypenum_perturbsperturb_intervalr1   r   r   r   viewr   r   r
   r   r   r   r   rm   r   detect_bilinearr   argmaxrR   uniquesegments_to_line_map)'r;   rJ   rX   rL   rH   rI   r4   r   r   side_perturbsperturb_vech1_gridw1_gridh2_gridw2_gridperturb_tensorperturb_tensor_flatdetected_seg_indexesr   r   rN   line_segment_candidatesrefined_segment_lstnum_segmentsidxsegmentr   r   r   r   r   r   r   segment_featsegment_resultsmax_idxrefined_segmentsjunctions_newline_map_newr@   r@   rA   r     sb   
44

2z2LineSegmentDetectionModule.refine_junction_perturbsegmentsc                 C   s   t |}t||g|jd}ttj|d |ddddf kdd\}}ttj|d |ddddf kdd\}}d|||f< d|||f< |S )z)Convert the list of segments to line map.r4   Nr   r   r   r   )r   r   r4   r   r1   all)r;   rJ   r  r   rX   rY   	idx_junc1	idx_junc2r@   r@   rA   r     s   ,,z/LineSegmentDetectionModule.segments_to_line_mapr   r   c           	      C   s   t |t j}t |t j}t |t j}t |t j}|||f ||  ||  |||f ||  ||   |||f ||  ||   |||f ||  ||   }|S )zDetect by bilinear sampling.)r1   floorr   longr   )	r;   rL   r   r   cand_h_floorcand_h_ceilcand_w_floorcand_w_ceilcand_samples_featr@   r@   rA   r     s   z*LineSegmentDetectionModule.detect_bilinearr   c                 C   s4  d| j |  }tj|d | jdd}t|d |d gd}	t|	}
ttd| j d td| j d g|d}t	| j| jgg|tj
d}t|d	k\}}t|d |d gd}ttj|| d dd}||| jkd
d
f }|| j }tj|
dd|d  }ttjtj|	dd| d dd}||d k }tj|d
d
d
d
d
d
d	f d	|d dtj}tj|d
d
d
d
d
d
df d	|d dtj}t|d |d gd}||d
d
d
d
d
d
d	f |d
d
d
d
d
d
df f }||tj
 }t|d	krtd	| j}|S tj|ddd	 }|S )zDetect by local maximum search.g;f?r{   r|   r   r   r   r  rw   r   N)NNr}   )rg   r1   repeat_interleaverc   r   r   r   r   rf   r   r   r   r   r   r   r   r   r  r   emptyr   )r;   rL   r   r   rH   rI   r   r4   dist_threshcand_pointscand_points_round
patch_maskpatch_centerH_patch_pointsW_patch_pointspatch_pointspatch_center_distpatch_points_shifted
patch_distpatch_dist_maskpoints_Hpoints_Wpointsr   sampled_feat_lmaxr@   r@   rA   r     s0   
,
&44<z+LineSegmentDetectionModule.detect_local_max)N)r   r   )r   r   r   r   )r[   r\   r]   r^   r   r   r+   r   r   rQ   r   r   r   r   r   r1   r4   r   r   r   r   r@   r@   r@   rA   r8      sr     'h
%/

L	r8   rJ   rX   r   c                 C   s,   t t|\}}t| | | | gd}|S )zBConvert a junction connectivity map to a Nx2x2 tensor of segments.r   )r   r1   r   r
   )rJ   rX   	junc_loc1	junc_loc2r  r@   r@   rA   rS   .  s   rS   r   probdistprob_threshtop_kc           	      C   s   t t| |kd }t|dkr|S t||d  ||d  gd}| | |k }t||d}|| }|dkrCtt||}|d| }|S )zVExtract junctions from a probability map, apply NMS, and extract the top k candidates.r|   r   r   r   gMbP?N)r
   r   r   r   r   r   r~   )	r.  r/  r0  r1  rJ   boxesscores
remainingskr@   r@   rA   rP   5  s   rP   )r   r   ))r   r'   typingr   r   r   r   r1   kornia.corer   r   r   r	   r
   r   r   r   kornia.core.checkr   kornia.feature.sold2.structuresr   r   r   r   kornia.geometry.bboxr   kornia.utilsr   r   r   	backbonesr   r   r`   __annotations__r   r8   rS   r   r   rP   r@   r@   r@   rA   <module>   s&   
(_   .$