o
    0jv                     @   s  d dl mZmZmZmZmZ d dlZd dl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 edr<d dlZee Zeeef Zg dZdd Zdd ZdIddZ	dJddZeddKddZdd Zdd Z d d! Z!	dLd"d#Z"d$d% Z#	dLd&ed'ee$ d(eeef d)ed*ef
d+d,Z%dLd-d.Z&d/d0 Z'	1dMd2eeeef  d3eeeef  d4e$d*efd5d6Z(d7d8 Z)	1dMd9eeje*e+f d:eeje*e+f d*efd;d<Z,d=ee$ee f d>e$d*ee$ee f fd?d@Z-d&ee dAee$ fdBdCZ.dNdEdFZ/ej0G dGdH dHZ1dS )O    )DictListOptionalTupleUnionN)ndarray   )logging)function_requires_depsis_dep_available   )	benchmark   )check_containmentnmszopencv-contrib-python)Zfigure_titleZvision_footnoteimagecharttableheaderZheader_imagefooterZfooter_imageZfootnoteZ
aside_textc                 C   s8   ||  }|| }|d |d  |d |d   }|dk S )z-
    Calculate if the polygon is convex.
    r       )p_prevp_currp_nextv1v2crossr   r   t/var/www/html/Deteccion_Ine/venv/lib/python3.10/site-packages/paddlex/inference/models/layout_analysis/processors.py	is_convex/   s    r   c                 C   sJ   | t j|  }|t j| }t t ||dd}t |}t |S )z2
    Calculate the angle between two vectors.
    g      g      ?)nplinalgnormclipdotZarccosdegrees)r   r   Zunit_v1Zunit_v2Zdot_prodZ	angle_radr   r   r   angle_between_vectors9   s
   

r&      c                 C   s@   |t j| |t j|  }|t j| }| ||  }|S )zH
    Calculate the new point based on the direction of two vectors.
    )r    r!   r"   )r   r   r   Zdistancedir_vecZp_newr   r   r   calc_new_pointE   s    r)   -   333333?c              	      s  t | }t|}||9 }g }t|D ]7}||d |  || ||d |  }}	}
||	 |
|	 }}t||	|
}t||}||||||d qdd t|D }t |rg }|d g}tdt|D ]6}|| ||d   dks||d  |d kr|| dkr|||  qgt|dkr|	| || g}qgt|dkr|	| t|dkr|d dkr|d |d krd|v r|d |v r̈
| n
| fddt|D }g }tt|D ]t}|| }||d t|  }|| t j|| ||  }||krY||krtt|d |ntt|d |ttd|   rYtt || d }t |krD|	  qt | |	 fd	dt|D  qtt|}g }|D ]e}|| }|| }	|d
 rt|d | dk r|d t j|d  }|d t j|d  }|| }|t j| }t j|d t j|d  d }|t|	||   qd|t|	 qd|S )Nr   )indexr   angler   r   c                 S   s   g | ]
\}}|d  s|qS )r   r   .0iinfor   r   r   
<listcomp>f       z+extract_custom_vertices.<locals>.<listcomp>r   r   c                    s0   g | ]\}}|d  s| v r|d dkr|qS )r   r-   x   r   r.   )preserve_concaver   r   r2      s    c                    s   g | ]
} t |  qS r   )intr/   r0   )intermediatestepr   r   r2      r3   r   r-   r   r   )r    arraylenranger   r&   append	enumeratesetextendupdater!   r"   listr7   ceilsortedabstuple)polygonmax_allowed_distZsharp_angle_threshZmax_dist_ratiopolynZ
point_infor0   r   r   r   r   r   Zis_convex_pointr-   Zconcave_indicesgroupsZcurrent_groupZkept_pointsZfinal_pointsidxZcurrent_idxZnext_idxdistZ
num_neededresr1   Zv1_normZv2_normr(   dr   )r9   r6   r:   r   extract_custom_verticesO   s   
,


 







 $rQ   Mbp?Tc           
      C   sn   t | t jt j\}}|sdS t|t jd}|t |d }t ||d}| }	t	
|	}	|r5t|	|}	|	S )z
    Postprocess mask by removing small noise.
    Args:
        mask (ndarray): The input mask of shape [H, W].
        epsilon_ratio (float): The ratio of epsilon.
    Returns:
        ndarray: The output mask after postprocessing.
    N)keyT)cv2ZfindContoursZRETR_EXTERNALZCHAIN_APPROX_SIMPLEmaxZcontourAreaZ	arcLengthZapproxPolyDPZsqueezer    Z
atleast_2drQ   )
maskrI   Zepsilon_ratioZextract_customZcnts_ZcntepsilonZ
approx_cntpolygon_pointsr   r   r   mask2polygon   s   


rZ   c              	   C   s  |d d |d d }}|j dd \}}g }t| dddf | dddf  }	tt| D ]}
| |
ddf tj\}}}}|| || }}t| |
ddf }|dks]|dkrc|| q0t	t
t|| t
t|| gd|}t	t
t|| t
t|| gd|}||
|d |d |d |d f }|jdkst|dkr|| q0tj|tj||ftjd}||	d	 kr|}n|	}t||}|durt|dkr|t||g }|t| |
ddf ||t|dkr|d
 ndd q0|S )uE   
    修改后的提取函数：auto 模式下信任几何决策
    r   r   r   Nr   r      )interpolation333333?r4   boxrH   layout_shape_modeprevious_polygon)shaperU   r=   r<   astyper    int32_rect_from_boxr>   r#   r7   roundsizesumrT   resizeZuint8ZINTER_NEARESTrZ   r;   _normalize_layout_polygon)boxesmasksscale_ratior`   Zscale_wZscale_hZh_mZw_mrY   Z	max_box_wr0   x_miny_minx_maxy_maxZbox_wZbox_hrectZx_sZy_sZcroppedZresized_maskrI   rH   r   r   r   extract_polygon_points_by_masks   sN   $ 
""&

rs   c              	   C   sN   g }t || D ]\}}|t|dd ||t|dkr|d nd d q|S )Nr   r[   r   r4   r^   )zipr>   rj   r<   )rk   rY   r`   Znormalized_pointsrH   r_   r   r   r   !normalize_polygon_points_by_boxes  s   
ru   c                 C   sB   t | t j\}}}}t j||g||g||g||ggt jdS )NZdtype)r    asarrayrc   rd   r;   float32)r_   rn   ro   rp   rq   r   r   r   re     s
   re   c                 C   s  t | }|d u r
|S tj|tjd}|jdkr|dd}t|dk r%|S |dkr+|S |dkr1|S t|}|dkrA|d ur?|S |S |d	kr| }|d ur| }t	||d
d}|dkr^|S | }	t	|	|d
d}
d}|d urxt	| |dd}|
dkr|dk r|S |S t
d)Nrv   r   r4   r   r   rr   rJ   quadautounionmodegffffff?r   smallg?g{Gz?zAlayout_shape_mode must be one of ['rect', 'poly', 'quad', 'auto'])re   r    rw   rx   ndimreshaper<   convert_polygon_to_quadtolistcalculate_polygon_overlap_ratio
ValueError)r_   rH   r`   ra   rr   ry   Z	rect_listZ	quad_listZiou_rect_quadZ	poly_listZiou_poly_quadZiou_prer   r   r   rj   %  sR   
rj   c           	      C   s   | du s
t | dk rdS tj| tjd}t |jdkr!|dd}t|}t|}|j	dd}t
|dddf |d  |dddf |d  }t|}|| }|dddf |dddf  }t|}tj|| dd}|S )	z
    Convert polygon to minimum bounding rectangle (quad).
    Args:
        polygon (ndarray): The polygon points of shape [N, 2].
    Returns:
        quad (ndarray): The 4-point quad, clockwise from top-left, or None if invalid.
    Nr   rv   r   r4   r   r   )Zaxis)r<   r    r;   rx   rb   r   rT   ZminAreaRectZ	boxPointsmeanZarctan2argsortZargminZroll)	rH   ZpointsZmin_rectry   centerZanglesZsorted_indicesZsumsZtop_left_idxr   r   r   r   b  s   

4
 
r   rk   labelsimg_sizerY   returnc                 C   s   g }|\}}t | D ]e\}}|dd \}	}
}}ttd|	}	ttd|
}
tt||}tt||}||	ks<||
kr=q
t|d |t|d  t|d |	|
||g|d d}|durj|| }|du rfq
||d< || q
|S )ae  
    Restructure the given bounding boxes and labels based on the image size.

    Args:
        boxes (ndarray): A 2D array of bounding boxes with each box represented as [cls_id, score, xmin, ymin, xmax, ymax].
        labels (List[str]): A list of class labels corresponding to the class ids.
        img_size (Tuple[int, int]): A tuple representing the width and height of the image.
        polygon_points (ndarray): A 2D array of polygon points with each point represented as [x, y].
    Returns:
        Boxes: A list of dictionaries, each containing 'cls_id', 'label', 'score', and 'coordinate' keys.
    r   Nr   r   )Zcls_idlabelscore
coordinateorderrY   )r?   r7   rU   minfloatr>   )rk   r   r   rY   Zbox_listwhrM   r_   xminyminxmaxymaxrO   Zpolygon_pointr   r   r   restructured_boxes  s.   


r   c              	   C   s  |du r| S t |trng }| D ]Y}|\}}}}}}	||v rc|| \}
}|| }|	| }||
 }|| }||d  }||d  }||d  }||d  }||d  }||d  }|||||||g q|| qt|S | dddf | dddf  }| dddf | dddf  }||d  }||d  }| dddf |d  }| dddf |d  }||d  }||d  }||d  }||d  }t| dddf | dddf ||||f}|S )a]  
    Expand bounding boxes from (x1, y1, x2, y2) format using an unclipping ratio.

    Parameters:
    - boxes: np.ndarray of shape (N, 4), where each row is (x1, y1, x2, y2).
    - unclip_ratio: tuple of (width_ratio, height_ratio), optional.

    Returns:
    - expanded_boxes: np.ndarray of shape (N, 4), where each row is (x1, y1, x2, y2).
    Nr   r      r   r   r   )
isinstancedictr>   r    r;   Zcolumn_stack)rk   Zunclip_ratioZexpanded_boxesr_   Zclass_idr   x1y1x2y2Zwidth_ratioZheight_ratiowidthheightZnew_wZnew_hZcenter_xZcenter_yZnew_x1Znew_y1Znew_x2Znew_y2widthsZheightsr   r   r   unclip_boxes  sF   

  &r   c                 C   s   | j s| d} | S )Nr   )Zis_validbuffer)rJ   r   r   r   
make_valid  s   
r   r{   polygon1polygon2r}   c           
      C   s   zddl m} W n ty   tdw || }||}t|}t|}||j}||j}|dkr8|| S |dkrGt|j|j}|| S |dkrVt|j|j}	||	 S t	d| )a  
    Calculate the overlap ratio between two polygons.

    Args:
        polygon1 (List[Tuple[int, int]]): First polygon represented as a list of points.
        polygon2 (List[Tuple[int, int]]): Second polygon represented as a list of points.
        mode (str, optional): Overlap calculation mode. Defaults to "union".

    Returns:
        float: Overlap ratio value between 0 and 1.
    r   PolygonPlease install Shapely library.r{   r~   largezUnknown mode: )
shapely.geometryr   ImportErrorr   intersectionarear{   r   rU   r   )
r   r   r}   r   Zpoly1Zpoly2r   r{   Z
small_areaZ
large_arear   r   r   r     s(   r   c                 C   s*   t t| \}}}}t|| ||  }|S )zCalculate bounding box area)mapr   rF   )Zbboxr   r   r   r   r   r   r   r   calculate_bbox_area  s   r   bbox1bbox2c                 C   s  t | } t |}t | d |d }t | d |d }t | d |d }t | d |d }t d|| }t d|| }|| }	t| }
t|}|dkrY|
| |	 }n|dkrdt |
|}n|dkrot |
|}ntd| d	|dkr}d
S |	| S )a  
    Calculate the overlap ratio between two bounding boxes using NumPy.

    Args:
        bbox1 (np.ndarray, list or tuple): The first bounding box, format [x_min, y_min, x_max, y_max]
        bbox2 (np.ndarray, list or tuple): The second bounding box, format [x_min, y_min, x_max, y_max]
        mode (str): The mode of calculation, either 'union', 'small', or 'large'.

    Returns:
        float: The overlap ratio value between the two bounding boxes
    r   r   r   r   r{   r~   r   zInvalid mode z-, must be one of ['union', 'small', 'large'].g        )r    r;   maximumminimumr   r   )r   r   r}   Zx_min_interZy_min_interZx_max_interZy_max_interZinter_widthZinter_heightZ
inter_areaZ
bbox1_areaZ
bbox2_areaZref_arear   r   r   calculate_overlap_ratio  s.   


r   	src_boxesr`   c                    s  dd | D }t   tt|D ]}|| d \}}}}|| || }}	|dk s-|	dk r2 | t|d t|D ]}
| v sE|
 v rFq;t|| d ||
 d d}|| d dksd||
 d dkr|d	kr|| d dkru | ||
 d dkr |
 q;|d
kr|dkrd|| v rt|| d ||
 d d}|d
k rq;t|| d }t||
 d }|| d ||
 d h}|h d@ rt|dkrd|vs|h dkrq;||kr |
 q; | q;q fddt|D }|S )a%  
    Remove overlapping boxes from layout detection results based on a given overlap ratio.

    Args:
        boxes (Dict[str, List[Dict]]): Layout detection result dict containing a 'boxes' list.

    Returns:
        Dict[str, List[Dict]]: Filtered dict with overlapping boxes removed.
    c                 S   s   g | ]
}|d  dkr|qS )r   	referencer   )r/   r_   r   r   r   r2   V  r3   z filter_boxes.<locals>.<listcomp>r   r[   r   r~   r   Zinline_formula      ?gffffff?rr   rY   >   r   r   r   Zsealr   c                    s   g | ]
\}}| vr|qS r   r   )r/   rM   r_   Zdropped_indexesr   r   r2     r3   )r@   r=   r<   addr   r   r   r?   )r   r`   rk   r0   r   r   r   r   r   r   jZoverlap_ratioZpoly_overlap_ratioZ
box_area_iZ
box_area_jr   Z	out_boxesr   r   r   filter_boxesJ  sR   



&r   skip_order_labelsc                 C   s<   d}| D ]}|d }||vr||d< |d7 }qd|d< q| S )a?  
    Update the 'order_index' field of each box in the provided list of boxes.

    Args:
        boxes (List[Dict]): A list of boxes, where each box is represented as a dictionary with an 'order_index' field.

    Returns:
        None. The  function updates the 'order_index' field of each box in the input list.
    r   r   r   Nr   )rk   r   Zorder_indexr_   r   r   r   r   update_order_index  s   


r   2   c                 C   s   zddl m} W n ty   tdw ||}tdd |D }tdd |D }t|D ](}	|||	 }
}|
| || }}| |
|||}||rVt|
t|f  S q.t|t|fS )Nr   r   r   c                 S      g | ]}|d  qS r   r   r/   pr   r   r   r2         z'find_label_position.<locals>.<listcomp>c                 S   r   )r   r   r   r   r   r   r2     r   )r   r   r   r   r=   Z
intersectsr7   )r_   rY   Ztext_wZtext_hZ	max_shiftr   rJ   Zmin_xZmin_yZdyr   r   r   r   Z
label_rectr   r   r   find_label_position  s    
r   c                       sH  e Zd ZdZ	ddeee  deee  ddf fddZ			dd	e	d
e
eef deeef dee deeee
eef ef  deeeef  dee	 dee deee	  defddZ							ddee dee deeeef  dee deeee
eef f  dee dee dee deee  dee fddZ  ZS )LayoutAnalysisProcesszSave Result Transform

    This class is responsible for post-processing detection results, including
    thresholding, non-maximum suppression (NMS), and restructuring the boxes
    based on the input type (normal or rotated object detection).
    Nr   
scale_sizer   c                    s   t    || _|| _dS )a  Initialize the DetPostProcess class.

        Args:
            threshold (float, optional): The threshold to apply to the detection scores. Defaults to 0.5.
            labels (Optional[List[str]], optional): The list of labels for the detection categories. Defaults to None.
            layout_postprocess (bool, optional): Whether to apply layout post-processing. Defaults to False.
        N)super__init__r   r   )selfr   r   	__class__r   r   r     s   


zLayoutAnalysisProcess.__init__rz   rk   r   	threshold
layout_nmslayout_unclip_ratiolayout_merge_bboxes_moderl   r`   rY   c
           +         s  |dkrddt |ddddf t|ddddf< t|tr[|dddf |k|dddf dk@ }
||
ddf }durK|
df durZfd	d
t|
D nt|trg }durig }durog }t |dddf D ]y}||dddf |k }dur|dddf |k }durfdd
t 	|dddf |kd D }|
t|d}|dddf |k|dddf dk@ }dur|| }|| dur|dd
 t||D  |||  qz|rt |nt g }dur|rt |nt g dur||rNt|ddddf ddd}t || }dur@fdd
|D durNfdd
|D d}|r4t|dkr4|jd dv r4|d |d krnd}nd}d| jv r|| jdnd}|d |d  }g }g }g }t|D ]y\}}|dd \}}}} }!}"||krtd|}td| } t|d |!}!t|d |"}"|!| |"|   }#|#|| kr|| dur||  dur||  q|| dur||  dur||  qt|dkr!|}dur}dur!}t |}dur-|dur4||r9d| jv rC| jdnd}$t|tr|dv sWJ d| |dkr]nt|ddddf |$\ |dkr| dk }dur fdd
tD n|dkr|dk dkB  }dur fdd
tD nt|tr9t jt|td | D ]X\}%}&|&dv sJ d|& |&dkrӐq|&dkrt|ddddf |$|%|&d!\  dkM q|&dkrt|ddddf |$|%|&d!\ dk dkB M q| }dur)fd"d
tD dur9fd#d
tD |jdkrDt g S |jd d$krt |ddd%f  |dddf f}'||' }(|(ddddf }dur~fd&d
|'D })|)durfd'd
|'D |jd d%krt |dddf }'||' }(|(ddddf }durfd(d
|'D })|)durˇfd)d
|'D du rdurd*d
 t| j |D }*t!|t |*|ndurt"|||r.t|tr||f}n%t|t#t$frt|dksJ d+nt|trn
t%d,t&| d-t'||}|jd dkrA	 t(|| j|}|S 	 t%d.|jd  )/a	  Apply post-processing to the detection boxes.

        Args:
            boxes (ndarray): The input detection boxes with scores.
            img_size (tuple): The original image size.

        Returns:
            Boxes: The post-processed detection boxes.
        rr   Nr   r[   r   r   r4   .c                    s   g | ]
\}}|r | qS r   r   )r/   r0   keeprY   r   r   r2     s
    z/LayoutAnalysisProcess.apply.<locals>.<listcomp>c                       g | ]} | qS r   r   r8   r   r   r   r2     s    r   c                 S   s   g | ]\}}|r|qS r   r   )r/   rJ   r   r   r   r   r2     s    r]   g\(\?)Ziou_sameZiou_diffc                    r   r   r   r8   rl   r   r   r2     r   c                    r   r   r   r8   r   r   r   r2     r   T)r[         g=
ףp=?g(\?r   Zformula)r{   r   r~   z\The value of `layout_merge_bboxes_mode` must be one of ['union', 'large', 'small'], but got r{   r   c                    s    g | ]\}} | d kr|qS r   r   r/   r0   rV   )contained_by_otherr   r   r2   e  s
    r~   c                    s,   g | ]\}}| d k | dkB r|qS )r   r   r   r   )r   contains_otherr   r   r2   m  s    

rv   r|   c                       g | ]
\}} | r|qS r   r   r   	keep_maskr   r   r2     r3   c                    r   r   r   )r/   r0   rJ   r   r   r   r2     s
    r   r   c                    r   r   r   r8   r   r   r   r2     r   c                    r   r   r   r8   r   r   r   r2     r   c                    r   r   r   r8   r   r   r   r2     r   c                    r   r   r   r8   r   r   r   r2     r   c                 S   s   g | ]\}}|| qS r   r   )r/   r   sr   r   r   r2     s    z0The length of `layout_unclip_ratio` should be 2.zqThe type of `layout_unclip_ratio` must be float, Tuple[float, float] or  Dict[int, Tuple[float, float]], but got .z1The shape of boxes should be 6 or 10, instead of ))r    rf   rc   r7   r   r   r?   r   uniquewheregetr>   rA   rt   Zvstackr;   Zconcatenater   r<   rb   r   r,   rU   r   strr   Zonesboolitemsrg   Zlexsortr   r   rs   ru   rG   rC   r   typer   r   )+r   rk   r   r   r   r   r   rl   r`   rY   Zexpect_boxesZcategory_filtered_boxesZcategory_filtered_masksZ category_filtered_polygon_pointsZcat_idZcategory_boxesZcategory_masksZcategory_polygon_pointsZcategory_thresholdZselected_indicesZfilter_large_imageZ
area_thresZimage_indexZimg_areaZfiltered_boxesZfiltered_masksZfiltered_polygon_pointsrM   r_   Zlabel_indexr   r   r   r   r   Zbox_areaZformula_indexZcategory_indexZlayout_modeZ
sorted_idxZsorted_boxesZsorted_masksrm   r   )r   r   r   rl   rY   r   apply  s  0
(


	



$





























(






zLayoutAnalysisProcess.applybatch_outputsdatasfilter_overlap_boxesr   c
                 C   s   g }
t t||D ]`\}\}}|}d|v r|d }d}n"d|v r'd}|d }nd}|dkr:|dvr:td| d d}d}| j|d	 |d
 |||||||d	}|rWt||}|	dur]|	nt}	t||	}|
| q	|
S )a  Apply the post-processing to a batch of outputs.

        Args:
            batch_outputs (List[dict]): The list of detection outputs.
            datas (List[dict]): The list of input data.

        Returns:
            List[Boxes]: The list of post-processed detection boxes.
        rl   NrY   rr   r   )rr   rz   zcThe model you are using does not support polygon output, but the layout_shape_mode is specified as z, which will be set to 'rect'rk   Zori_img_sizer   )	r?   rt   r	   warningr   r   SKIP_ORDER_LABELSr   r>   )r   r   r   r   r   r   r   r`   r   r   ZoutputsrM   dataoutputZcurrent_layout_shape_moderl   rY   rk   r   r   r   __call__  sH   



zLayoutAnalysisProcess.__call__)NN)Nrz   N)NNNNNNN)__name__
__module____qualname____doc__r   r   r   r7   r   r   r   r   r   r   r   Boxesr   r   __classcell__r   r   r   r   r     s    



	


  	

r   )r'   )r*   r+   )rR   T)N)r{   )r   )2typingr   r   r   r   r   numpyr    r   utilsr	   Z
utils.depsr
   r   Zutils.benchmarkr   Zobject_detection.processorsr   r   rT   r   r   r7   r   Numberr   r   r&   r)   rQ   rZ   rs   ru   re   rj   r   r   r   r   r   r   r   rC   rG   r   r   r   r   Ztimeitr   r   r   r   r   <module>   s   


g;
=!


-:	
&

1
>
