§
    �ØjR‘  ã                   óÆ   — d Z ddlZddlZddlZddlmZmZ ddlm	Z	m
Z
 ddlmZ dZd„ Zd	Zd
ZdZd	Zd
Zdd„Z	 dd„Zdd„Zd„ Z	 	 dd„Zd„ Zd„ Zefd„Zefd„Zdedfd„ZdS ) ap  
Youngmin's Features (YF) extraction
Maintained by: AI Researchers
Purpose: Spatial feature maps from PDF page layout analysis

No OpenCV dependency: ruling-line detection uses PyMuPDF's own vector
drawing objects (get_vector_lines/merge_lines, PDF-native) instead of
Sobel/morphology on a rasterized page image, and per-channel diffusion
(previously done via cv2.GaussianBlur with a hand-picked kernel per channel)
is superseded by apply_multiscale_pyramid()'s FPN-style multi-scale
concatenation, which diffuses every channel uniformly via nearest-neighbor
downsample+upsample rather than a per-channel-tuned blur radius.
é    N)ÚCounterÚdefaultdicté   )Úget_vector_linesÚmerge_lines)Ú$extract_bbox_features_by_roi_pooling)ç      à?ç      Ð?g      À?c                 óš   — |dk    rdS t          | d¦  «        }||z  }t          j        |¦  «        }ddt          j        | ¦  «        z   z  S )a�  
    Log-sigmoid normalization of val relative to a page-derived baseline
    (mode_val): returns 0.5 when val == mode_val, approaching 1 as val
    grows much larger than the baseline and 0 as it shrinks much smaller.
    Used in YF for font_distance and width/height_diff_distance.
    NOTE: margin_l/r/t/b, vector_margin_l/r/t/b, column_degree, and
    line_indent_degree deliberately do NOT go through this anymore. Page-
    local mode/boundary baselines were unstable on sparse pages, so they
    instead go through suppress_extremes() below, which caps outliers using
    a FIXED corpus-wide constant rather than a per-page mode.
    r   r	   gü©ñÒMbP?ç      ð?)ÚmaxÚmathÚlog2Úexp)ÚvalÚmode_valÚsafe_valÚratioÚdiff_logs        ú“/Users/tedpeters/Documents/Projects/Claude Projects/Misc Tools/notename-sheets/.venv/lib/python3.11/site-packages/pymupdf/layout/pymupdf_util_yf.pyÚget_centered_featurer      sT   € ð �1‚}€}ØˆsÝ�3˜‰Œ€HØ�xÑ€EÝŒy˜ÑÔ€HØ�#�œ ( Ñ+Ô+Ñ+Ñ,Ð,ó    g      Y@g      I@ç      @Úlog1pc                 óæ   — t          | d¦  «        }|dk    rt          j        ||z  ¦  «        S |dk    rt          j        ||z  ¦  «        S |dk    rt	          ||¦  «        S t          d|› �¦  «        ‚)a™  
    Suppress large/outlier values with a FIXED (page-independent) squashing
    function -- the middle ground between raw unbounded values and
    get_centered_feature's page-local mode normalization.

    Unlike get_centered_feature, `scale` here must be a constant decided
    once from corpus-wide statistics, never recomputed per page/document.
    Recomputing it per page reintroduces the exact instability (noisy
    reference on sparse pages) that motivated removing get_centered_feature
    from margin_l/r/t/b, vector_margin_l/r/t/b, column_degree, and
    line_indent_degree in the first place.

    mode='log1p' (default): log1p(val / scale). Unbounded but grows very
        slowly past `scale` -- never fully saturates, so two very large
        values (e.g. two different isolated-line sentinel gaps) still end
        up numerically distinguishable, just compressed. Safest default.
    mode='tanh': tanh(val / scale). Hard-bounded to [0, 1). Fully saturates
        for val >> scale, so very large values collapse to ~1 and become
        indistinguishable from each other -- same saturating behavior as
        the removed get_centered_feature, but referenced to a fixed
        constant instead of a per-page mode.
    mode='clip': min(val, scale). Simplest possible cap -- linear/raw below
        `scale`, hard-clipped above it. Easiest to reason about but throws
        away all information above the cap.
    ç        r   ÚtanhÚclipz unknown suppress_extremes mode: )r   r   r   r   ÚminÚ
ValueError)r   ÚscaleÚmoder   s       r   Úsuppress_extremesr#   ;   s}   € õ4 �3˜‰}Œ}€HØˆw‚€ÝŒz˜( UÑ*Ñ+Ô+Ð+Ø	�ŠˆÝŒy˜ EÑ)Ñ*Ô*Ð*Ø	�ŠˆÝ�8˜UÑ#Ô#Ð#åÐB¸DÐBÐBÑCÔCÐCr   ç333333Ó?c                 ó˜  — t          | ¦  «        }t          j        d„ | D ¦   «         ¦  «        }t          j        d„ | D ¦   «         ¦  «        }t          j        d„ | D ¦   «         ¦  «        }t          j        d„ | D ¦   «         ¦  «        }	|	|z
  }
||z
  }||	z   dz  }||z   dz  }t          j        ||t          j        ¬¦  «        }t          j        ||t          j        ¬¦  «        }t          j        ||t          j        ¬¦  «        }t          j        ||t          j        ¬¦  «        }t          j        |t          ¬¦  «        }t          j        |t          ¬¦  «        }t          j        |t          ¬¦  «        }t          j        |t          ¬¦  «        }t          |¦  «        D �]Ÿ}|
|         }|||         ||z  z
  k    ||	|         ||z  z   k    z  }d||<   ||||         k    z  }t          j        |¦  «        r+||         ||          	                    ¦   «         z
  ||<   d||<   ||||         k    z  }t          j        |¦  «        r+||          
                    ¦   «         ||         z
  ||<   d||<   ||         }|||         ||z  z
  k    |||         ||z  z   k    z  }d||<   ||	||         k    z  }t          j        |¦  «        r+||         |	|          	                    ¦   «         z
  ||<   d||<   |||	|         k    z  }t          j        |¦  «        r+||          
                    ¦   «         |	|         z
  ||<   d||<   �Œ¡||||||||fS )	aÌ  
    Compute per-line margin_l/r/t/b: the gap to the nearest neighboring line
    in each direction (not the distance to the physical page edge).

    Row/column band tolerance mirrors get_edge_by_directional_nn's
    vertical_gap convention: a candidate neighbor for left/right search must
    have its center_y within the line's own height * vertical_gap of the
    line's y-range (and symmetrically, center_x within width * horizontal_gap
    for top/bottom search).

    When no neighbor is found in a direction, the raw gap is set to the
    page dimension (page_width for l/r, page_height for t/b) as a sentinel --
    NOT the line's actual distance to the physical page edge. This is
    deliberate: "no neighbor in this direction" is the meaningful signal
    (isolation), and using the page dimension guarantees a large, distinct
    raw value regardless of where the line happens to physically sit on
    the page. NOTE: this raw value is emitted as-is now (no page-mode
    normalization -- see get_centered_feature docstring).

    Known perf note: O(L^2) via per-line masking, matching the existing
    style of v_l/v_r counting in this module. Left as a follow-up
    optimization item, consistent with prior review of this file.

    Returns:
        raw_l, raw_r, raw_t, raw_b: np.ndarray (L,) raw gap values
        found_l, found_r, found_t, found_b: np.ndarray (L,) bool, True where
            an actual neighbor was found (i.e. the value is NOT the sentinel)
    c                 ó0   — g | ]\  }}|d          d         ‘ŒS ©Úbboxr   © ©Ú.0ÚlÚfs      r   ú
<listcomp>z0_compute_directional_margins.<locals>.<listcomp>~   ó$   € Ð:Ð:Ð:¡T Q¨�A�f”I˜a”LÐ:Ð:Ð:r   c                 ó0   — g | ]\  }}|d          d         ‘ŒS )r(   r   r)   r*   s      r   r.   z0_compute_directional_margins.<locals>.<listcomp>   r/   r   c                 ó0   — g | ]\  }}|d          d         ‘ŒS ©r(   é   r)   r*   s      r   r.   z0_compute_directional_margins.<locals>.<listcomp>€   r/   r   c                 ó0   — g | ]\  }}|d          d         ‘ŒS )r(   é   r)   r*   s      r   r.   z0_compute_directional_margins.<locals>.<listcomp>�   r/   r   ç       @©ÚdtypeFT)ÚlenÚnpÚarrayÚfullÚfloat64ÚzerosÚboolÚrangeÚanyr   r   )Úall_raw_dataÚ
page_widthÚpage_heightÚvertical_gapÚhorizontal_gapÚnÚxs1Úys1Úxs2Úys2ÚheightsÚwidthsÚcyÚcxÚraw_lÚraw_rÚraw_tÚraw_bÚfound_lÚfound_rÚfound_tÚfound_bÚiÚh_iÚrow_bandÚ	left_maskÚ
right_maskÚw_iÚcol_bandÚtop_maskÚbottom_masks                                  r   Ú_compute_directional_marginsra   _   sV  € õ< 	ˆLÑÔ€AÝ
Œ(Ð:Ð:¨\Ð:Ñ:Ô:Ñ
;Ô
;€CÝ
Œ(Ð:Ð:¨\Ð:Ñ:Ô:Ñ
;Ô
;€CÝ
Œ(Ð:Ð:¨\Ð:Ñ:Ô:Ñ
;Ô
;€CÝ
Œ(Ð:Ð:¨\Ð:Ñ:Ô:Ñ
;Ô
;€CØ�C‰i€GØ�3‰Y€FØ
�‰)�sÑ	€BØ
�‰)�sÑ	€BåŒG�A�z­¬Ð4Ñ4Ô4€EÝŒG�A�z­¬Ð4Ñ4Ô4€EÝŒG�A�{­"¬*Ð5Ñ5Ô5€EÝŒG�A�{­"¬*Ð5Ñ5Ô5€EÝŒh�q¥Ð%Ñ%Ô%€GÝŒh�q¥Ð%Ñ%Ô%€GÝŒh�q¥Ð%Ñ%Ô%€GÝŒh�q¥Ð%Ñ%Ô%€Gå�1‰XŒXð ñ ˆØ�aŒjˆØ˜#˜aœ& 3¨Ñ#5Ñ5Ò5¸"ÀÀAÄÈÈ|ÑI[Ñ@[Ò:[Ñ\ˆØˆ�‰à  s¨1¤v¢Ñ.ˆ	ÝŒ6�)ÑÔð 	Ø˜1”v  I¤× 2Ò 2Ñ 4Ô 4Ñ4ˆE�!‰HØˆG�A‰Jà ¨¨A¬¢Ñ/ˆ
ÝŒ6�*ÑÔð 	Ø˜:”×*Ò*Ñ,Ô,¨s°1¬vÑ5ˆE�!‰HØˆG�A‰Jà�QŒiˆØ˜#˜aœ& 3¨Ñ#7Ñ7Ò7¸BÀ#ÀaÄ&È3ÐQ_ÑK_ÑB_Ò<_Ñ`ˆØˆ�‰à˜s c¨!¤fš}Ñ-ˆÝŒ6�(ÑÔð 	Ø˜1”v  H¤× 1Ò 1Ñ 3Ô 3Ñ3ˆE�!‰HØˆG�A‰Jà #¨¨Q¬¢-Ñ0ˆÝŒ6�+ÑÔð 	Ø˜;Ô'×+Ò+Ñ-Ô-°°A´Ñ6ˆE�!‰HØˆG�A‰Jùà�%˜  w°¸À'ÐIÐIr   r5   c                 ó  — t          | ¦  «        }t          j        d„ | D ¦   «         t          j        ¬¦  «        }t          j        d„ | D ¦   «         t          j        ¬¦  «        }t          j        d„ | D ¦   «         t          j        ¬¦  «        }	t          j        d„ | D ¦   «         t          j        ¬¦  «        }
t          j        ||t          j        ¬¦  «        }t          j        ||t          j        ¬¦  «        }t          j        ||t          j        ¬¦  «        }t          j        ||t          j        ¬¦  «        }t          j        |t          ¬¦  «        }t          j        |t          ¬¦  «        }t          j        |t          ¬¦  «        }t          j        |t          ¬¦  «        }|�r't          j        d„ |D ¦   «         ¦  «        }t          j        d„ |D ¦   «         ¦  «        }t          j        d„ |D ¦   «         ¦  «        }t          |¦  «        D ]½}|||         |z
  k    ||
|         |z   k    z  }||||         k    z  }t          j        |¦  «        r+||         ||          	                    ¦   «         z
  ||<   d	||<   |||	|         k    z  }t          j        |¦  «        r+||          
                    ¦   «         |	|         z
  ||<   d	||<   Œ¾|�r't          j        d
„ |D ¦   «         ¦  «        }t          j        d„ |D ¦   «         ¦  «        }t          j        d„ |D ¦   «         ¦  «        }t          |¦  «        D ]½}|||         |z
  k    ||	|         |z   k    z  }||||         k    z  }t          j        |¦  «        r+||         ||          	                    ¦   «         z
  ||<   d	||<   |||
|         k    z  }t          j        |¦  «        r+||          
                    ¦   «         |
|         z
  ||<   d	||<   Œ¾||||||||fS )aV  
    Per-bbox gap to the nearest vector line in each direction (all
    coordinates already in feature-map canvas space):
      vector_margin_l/r: nearest VERTICAL line whose y-range overlaps the
          bbox's y-range (+/- tolerance), to the left/right.
      vector_margin_t/b: nearest HORIZONTAL line whose x-range overlaps the
          bbox's x-range (+/- tolerance), above/below.

    Same sentinel convention as _compute_directional_margins: no matching
    line in a direction -> raw gap = canvas_w (l/r) or canvas_h (t/b), a
    clean, deterministic extreme value rather than an arbitrary small
    distance-to-page-edge value. NOTE: this raw value is emitted as-is now
    (no page-mode normalization -- see get_centered_feature docstring).

    Args:
        bboxes: list of [x1, y1, x2, y2], canvas-scaled.
        h_lines_scaled, v_lines_scaled: list of (x0, y0, x1, y1) tuples,
            canvas-scaled (h_lines are ~zero-height, v_lines ~zero-width).

    Returns:
        raw_l, raw_r, raw_t, raw_b, found_l, found_r, found_t, found_b
        (each an np.ndarray of length len(bboxes)).
    c                 ó   — g | ]
}|d          ‘ŒS ©r   r)   ©r+   Úbs     r   r.   z+_compute_vector_margins.<locals>.<listcomp>É   ó   € Ð)Ð)Ð)˜Q�A�a”DÐ)Ð)Ð)r   r7   c                 ó   — g | ]
}|d          ‘ŒS ©r   r)   re   s     r   r.   z+_compute_vector_margins.<locals>.<listcomp>Ê   rg   r   c                 ó   — g | ]
}|d          ‘ŒS ©r3   r)   re   s     r   r.   z+_compute_vector_margins.<locals>.<listcomp>Ë   rg   r   c                 ó   — g | ]
}|d          ‘ŒS ©r5   r)   re   s     r   r.   z+_compute_vector_margins.<locals>.<listcomp>Ì   rg   r   c                 ó6   — g | ]}|d          |d         z   dz  ‘ŒS )r   r3   r6   r)   ©r+   Úrs     r   r.   z+_compute_vector_margins.<locals>.<listcomp>Ø   ó)   € ÐCÐCÐC¨q˜˜!œ˜q œt™ sÑ*ÐCÐCÐCr   c                 ó   — g | ]
}|d          ‘ŒS ri   r)   ro   s     r   r.   z+_compute_vector_margins.<locals>.<listcomp>Ù   ó   € Ð5Ð5Ð5 ˜˜!œÐ5Ð5Ð5r   c                 ó   — g | ]
}|d          ‘ŒS rm   r)   ro   s     r   r.   z+_compute_vector_margins.<locals>.<listcomp>Ú   rs   r   Tc                 ó6   — g | ]}|d          |d         z   dz  ‘ŒS )r   r5   r6   r)   ro   s     r   r.   z+_compute_vector_margins.<locals>.<listcomp>ç   rq   r   c                 ó   — g | ]
}|d          ‘ŒS rd   r)   ro   s     r   r.   z+_compute_vector_margins.<locals>.<listcomp>è   rs   r   c                 ó   — g | ]
}|d          ‘ŒS rk   r)   ro   s     r   r.   z+_compute_vector_margins.<locals>.<listcomp>é   rs   r   )r9   r:   r;   r=   r<   r>   r?   r@   rA   r   r   ) ÚbboxesÚh_lines_scaledÚv_lines_scaledÚcanvas_wÚcanvas_hÚ	tolerancerG   Úbx1Úby1Úbx2Úby2rP   rQ   rR   rS   rT   rU   rV   rW   ÚvxÚvy0Úvy1rX   Ú	y_overlapr[   r\   ÚhyÚhx0Úhx1Ú	x_overlapr_   r`   s                                    r   Ú_compute_vector_marginsrŠ   °   sâ  € õ0 	ˆF‰Œ€AÝ
Œ(Ð)Ð) &Ð)Ñ)Ô)µ´Ð
<Ñ
<Ô
<€CÝ
Œ(Ð)Ð) &Ð)Ñ)Ô)µ´Ð
<Ñ
<Ô
<€CÝ
Œ(Ð)Ð) &Ð)Ñ)Ô)µ´Ð
<Ñ
<Ô
<€CÝ
Œ(Ð)Ð) &Ð)Ñ)Ô)µ´Ð
<Ñ
<Ô
<€CåŒG�A�x¥r¤zÐ2Ñ2Ô2€EÝŒG�A�x¥r¤zÐ2Ñ2Ô2€EÝŒG�A�x¥r¤zÐ2Ñ2Ô2€EÝŒG�A�x¥r¤zÐ2Ñ2Ô2€EÝŒh�q¥Ð%Ñ%Ô%€GÝŒh�q¥Ð%Ñ%Ô%€GÝŒh�q¥Ð%Ñ%Ô%€GÝŒh�q¥Ð%Ñ%Ô%€Gàñ "ÝŒXÐCÐC°NÐCÑCÔCÑDÔDˆÝŒhÐ5Ð5 nÐ5Ñ5Ô5Ñ6Ô6ˆÝŒhÐ5Ð5 nÐ5Ñ5Ô5Ñ6Ô6ˆÝ�q‘”ð 		"ð 		"ˆAØ  A¤¨Ñ 2Ò2°s¸cÀ!¼fÀyÑ>PÒ7PÑQˆIØ! R¨3¨q¬6¢\Ñ2ˆIÝŒv�iÑ Ô ð "Ø˜qœ6 B y¤M×$5Ò$5Ñ$7Ô$7Ñ7��a‘Ø!�˜‘
Ø" b¨C°¬F¢lÑ3ˆJÝŒv�jÑ!Ô!ð "Ø˜jœ>×-Ò-Ñ/Ô/°#°a´&Ñ8��a‘Ø!�˜‘
øàñ "ÝŒXÐCÐC°NÐCÑCÔCÑDÔDˆÝŒhÐ5Ð5 nÐ5Ñ5Ô5Ñ6Ô6ˆÝŒhÐ5Ð5 nÐ5Ñ5Ô5Ñ6Ô6ˆÝ�q‘”ð 		"ð 		"ˆAØ  A¤¨Ñ 2Ò2°s¸cÀ!¼fÀyÑ>PÒ7PÑQˆIØ  B¨#¨a¬&¢LÑ1ˆHÝŒv�hÑÔð "Ø˜qœ6 B x¤L×$4Ò$4Ñ$6Ô$6Ñ6��a‘Ø!�˜‘
Ø# r¨S°¬V¢|Ñ4ˆKÝŒv�kÑ"Ô"ð "Ø˜kœ?×.Ò.Ñ0Ô0°3°q´6Ñ9��a‘Ø!�˜‘
øà�%˜  w°¸À'ÐIÐIr   c                 óø  ‡J‡K— g }dŠJd}d}| d         }| d         }t          j        d¦  «        }g }g g }	}g g }}
t          ¦   «         }t          ¦   «         }| d         D �]ç}|d         d	k    rŒ|d
         D �]Í}|d         \  }ŠK}}t	          |¦  «        t	          ‰K¦  «        t	          |¦  «        t	          |¦  «        f}||v rŒO|                     |¦  «         t          ||z
  d¦  «        t          |‰Kz
  d¦  «        }}d                     d„ |d         D ¦   «         ¦  «        }d                     |                     ¦   «         ¦  «        }t          |¦  «        }|d	k    ret          t          j
        d|¦  «        ¦  «        }||z  }|dk    p|dk     o|dk    }|s*|
                     |¦  «         |                     |¦  «         |                     |¦  «         |	                     ‰K¦  «         |d         rK||d         d	         d         xx         dz  cc<   |                     ||d         d	         d         f¦  «         �ŒÏ�Œé|r:t          ˆJfd„|D ¦   «         ¦  «                             d¦  «        d	         d	         nd	}|
r.t          |
¦  «                             d¦  «        d	         d	         nd}|r.t          |¦  «                             d¦  «        d	         d	         nd}d„ |                     ¦   «         D ¦   «         }d„ t          |¦  «        D ¦   «         } t          |¦  «        dz
  }!t          |||¦  «        \  }"}#}$}%}&}'}(})d„ }*t          t           ¦  «        }+|D ]~\  }},|d         d         ŠKd}-|+                     ¦   «         D ]7}.t%          |.‰Kz
  ¦  «        ‰Jk    r|+|.                              |¦  «         d}- nŒ8|-s|+‰K                              |¦  «         Œt          |¦  «        D �]†\  }/\  }},|d         \  }ŠK}}||z
  |‰Kz
  }}d                     d„ |d         D ¦   «         ¦  «        }d                     |                     ¦   «         ¦  «        }t          |¦  «        t          |¦  «        }1}0|1d	k    r%t          t          j
        d|¦  «        ¦  «        |1z  nd}2|0d	k    r|0|1z
  |0z  dz  nd}3|                     |                     ¦   «         ¦  «        }4t+          ˆJˆKfd„|+                     ¦   «         D ¦   «         ¦  «        }5t          |5¦  «        }6t/          d „ |5D ¦   «         ¦  «        }7||z  |k    r|4s|2|k    s|6dk    r|7rdnd}8|6dk    r"t1          |6dz
  d!z  |8z  d|3z
  z  |2z  d¦  «        nd}9 |*|d"„ |D ¦   «         ‰J¦  «        }: |*|d#„ |D ¦   «         ‰J¦  «        };t3          |:|;¦  «        dk    r-t1          t3          |:|;¦  «        d$z  |8z  d|3z
  z  |2z  d¦  «        nd}<d|2z
  }=t5          ||¦  «        }>t5          ||¦  «        }?t7          |"|/         t8          ¦  «        }@t7          |#|/         t8          ¦  «        }At7          |$|/         t8          ¦  «        }Bt7          |%|/         t8          ¦  «        }C|&|/         rdnd}D|'|/         rdnd}E|(|/         rdnd}F|)|/         rdnd}Gt;          d%„ |D ¦   «         ¦  «        }H|Ht          |¦  «        z  }I|                     i d|‰K||g“d&d'„ |d         D ¦   «         “d(|2“d)|I“d*|4rdnd“d+|!d	k    r| |,         |!z  nd“d,|9“d-|<“d.|>“d/|?“d0|@“d1|A“d2|B“d3|C“d4|D“d5|E“d6|F“|G|3t7          t%          ||z
  ¦  «        t<          ¦  «        |=d7œ¥¦  «         �Œˆ|S )8zLCreate statistical and structural information from PDF page for YF features.g      @r
   çš™™™™™É?ÚwidthÚheightu:   ^(\d+[\.\)]|\(\d+\)|[a-zA-Z][\.\)]|\([a-zA-Z]\)|[-â– â—�])ÚblocksÚtyper   Úlinesr(   r   ú c                 ó   — g | ]
}|d          ‘ŒS ©Útextr)   ©r+   Úspans     r   r.   z*create_pdf_information.<locals>.<listcomp>  s   € Ð!IÐ!IÐ!I°4 $ v¤,Ð!IÐ!IÐ!Ir   ÚspansÚ ú\dçš™™™™™é?r5   Úfontc                 ó:   •— g | ]}t          |‰z  ¦  «        ‰z  ‘ŒS r)   )Úround)r+   Úxr}   s     €r   r.   z*create_pdf_information.<locals>.<listcomp>)  s*   ø€ ÐSÐSÐSÀA�u Q¨¡]Ñ3Ô3°iÑ?ÐSÐSÐSr   r   c                 ó   — g | ]
}|d          ‘ŒS rd   r)   )r+   r-   s     r   r.   z*create_pdf_information.<locals>.<listcomp>-  s   € Ð<Ð<Ð<˜Q�A�a”DÐ<Ð<Ð<r   c                 ó   — i | ]\  }}||“Œ	S r)   r)   )r+   rX   rœ   s      r   ú
<dictcomp>z*create_pdf_information.<locals>.<dictcomp>.  s   € ÐCÐCÐC¡  4�D˜!ÐCÐCÐCr   c                 ó>   ‡ ‡— t          ˆ ˆfd„|D ¦   «         ¦  «        S )Nc              3   óH   •K  — | ]}t          |‰z
  ¦  «        ‰k    ¯d V — ŒdS )r   N©Úabs)r+   ÚcÚtargetÚtols     €€r   ú	<genexpr>zIcreate_pdf_information.<locals>.count_within_tolerance.<locals>.<genexpr>B  s7   øè è € ÐCÐC˜­C°°F±
©O¬O¸sÒ,BÐ,B�1Ð,BÐ,BÐ,BÐ,BÐCÐCr   )Úsum)r¨   Ú
coord_listr©   s   ` `r   Úcount_within_tolerancez6create_pdf_information.<locals>.count_within_toleranceA  s*   øø€ ÝÐCÐCÐCÐCÐC˜jÐCÑCÔCÑCÔCÐCr   FTc                 ó   — g | ]
}|d          ‘ŒS r”   r)   r–   s     r   r.   z*create_pdf_information.<locals>.<listcomp>T  s   € ÐEÐEÐE¨t˜d 6œlÐEÐEÐEr   r   r3   c              3   óN   •K  — | ]\  }}t          |‰z
  ¦  «        ‰k    ¯|V — Œ d S ©Nr¥   )r+   Úref_yÚitemsr}   Úy1s      €€r   rª   z)create_pdf_information.<locals>.<genexpr>\  s=   øè è € ÐdÐd¡< 5¨%ÅsÈ5ÐSUÉ:ÁÄÐZcÒGcÐGc˜ÐGcÐGcÐGcÐGcÐdÐdr   c              3   ó¾  K  — | ]Ø}t          t          j        d d                     d                     d„ |d         D ¦   «         ¦  «                             ¦   «         ¦  «        ¦  «        ¦  «        t          dt          d                     d                     d„ |d         D ¦   «         ¦  «                             ¦   «         ¦  «        ¦  «        ¦  «        z  dk    V — ŒÙdS )	rš   r™   r’   c                 ó   — g | ]
}|d          ‘ŒS r”   r)   ©r+   Úss     r   r.   z4create_pdf_information.<locals>.<genexpr>.<listcomp>^  s   € ÐGfÐGfÐGfÐVWÈÈ&Ì	ÐGfÐGfÐGfr   r˜   r   c                 ó   — g | ]
}|d          ‘ŒS r”   r)   r¶   s     r   r.   z4create_pdf_information.<locals>.<genexpr>.<listcomp>_  s   € Ð<[Ð<[Ð<[È1¸Q¸v¼YÐ<[Ð<[Ð<[r   r›   N)r9   ÚreÚfindallÚjoinÚsplitr   )r+   r,   s     r   rª   z)create_pdf_information.<locals>.<genexpr>^  sâ   è è € ð  4ð  4à$%õ !$¥B¤J¨u°b·g²g¸c¿hºhÐGfÐGfÐ[\Ð]dÔ[eÐGfÑGfÔGfÑ>gÔ>g×>mÒ>mÑ>oÔ>oÑ6pÔ6pÑ$qÔ$qÑ rÔ rÝ # A¥s¨2¯7ª7°3·8²8Ð<[Ð<[ÐPQÐRYÔPZÐ<[Ñ<[Ô<[Ñ3\Ô3\×3bÒ3bÑ3dÔ3dÑ+eÔ+eÑ'fÔ'fÑ gÔ gñ!hØjmò!nð  4ð  4ð  4ð  4ð  4ð  4r   g…ëQ¸Õ?c                 ó0   — g | ]\  }}|d          d         ‘ŒS r'   r)   r*   s      r   r.   z*create_pdf_information.<locals>.<listcomp>j  ó$   € Ð)PÐ)PÐ)P¹4¸1¸a¨!¨F¬)°A¬,Ð)PÐ)PÐ)Pr   c                 ó0   — g | ]\  }}|d          d         ‘ŒS r2   r)   r*   s      r   r.   z*create_pdf_information.<locals>.<listcomp>k  r¾   r   r   c              3   óJ   K  — | ]}|                      ¦   «         °|d v¯dV — ŒdS ))ú,ú.r   N)Úisalnum)r+   Úchars     r   rª   z)create_pdf_information.<locals>.<genexpr>‡  s:   è è € ÐfÐf $¸D¿LºL¹N¼NÐfÈtÐ[eÐOeÐOe˜AÐOeÐOeÐOeÐOeÐfÐfr   r•   c                 ó   — g | ]
}|d          ‘ŒS r”   r)   r–   s     r   r.   z*create_pdf_information.<locals>.<listcomp>Œ  s   € Ð<Ð<Ð< d�T˜&”\Ð<Ð<Ð<r   Ú	num_ratioÚ	sym_ratioÚstart_list_prefixÚfont_distanceÚhorizontal_grid_densityÚvertical_grid_densityÚwidth_diff_distanceÚheight_diff_distanceÚmargin_lÚmargin_rÚmargin_tÚmargin_bÚmargin_l_foundÚmargin_r_foundÚmargin_t_found)Úmargin_b_foundÚwhitespace_ratioÚline_indent_degreeÚtext_density)r¹   Úcompiler   ÚsetÚintÚaddrž   r»   r¼   r9   rº   ÚappendÚmost_commonÚ	enumeratera   r   ÚlistÚkeysr¦   ÚmatchÚstripÚnextr²   rA   r   r   r   r#   ÚMARGIN_SUPPRESS_SCALEr«   ÚINDENT_SUPPRESS_SCALE_PDF)LÚ	page_dictÚ	info_listÚwidth_threshold_ratioÚnum_threshold_ratiorC   rD   Úlist_prefix_patternrB   Ú	x1_coordsÚ	y1_coordsrM   rL   Úfont_countsÚseen_bboxesÚblockÚlineÚx1Úx2Úy2Úbbox_keyÚwÚhÚ	full_textÚ
clean_textÚtext_lenÚ	num_countÚcurrent_num_ratioÚis_noise_for_modeÚindent_baselineÚmode_wÚmode_hÚsorted_fontsÚfont_to_rankÚmax_font_rankÚraw_margin_lÚraw_margin_rÚraw_margin_tÚraw_margin_brT   rU   rV   rW   r­   Úy_groupsrœ   Úfoundr±   Úline_idxÚlen_fullÚ	len_cleanrÆ   Úws_ratioÚis_listÚ	row_itemsÚ	row_countÚhas_strong_anchorÚis_grid_candidateÚh_grid_densityÚv_lÚv_rÚv_grid_densityrØ   Úw_diff_distanceÚh_diff_distancerÎ   rÏ   rÐ   rÑ   rÒ   rÓ   rÔ   rÕ   Úsymbols_countrÇ   r}   r³   sL                                                                             @@r   Úcreate_pdf_informationr  ø   se	  øø€ à€IØ€IØ ÐØÐØ˜7Ô#€JØ˜HÔ%€KÝœ*Ð%bÑcÔcÐà€LØ˜rˆy€IØ˜"ˆG€FÝ‘)”)€Kå‘%”%€KØ˜8Ô$ð Fñ FˆØ�Œ=˜AÒÐ˜xØ˜'”Nð 	Fñ 	FˆDØ! &œ\‰NˆB��B˜å˜B™œ¥ R¡¤­#¨b©'¬'µ3°r±7´7Ð;ˆHØ˜;Ð&Ð&ØØ�OŠO˜HÑ%Ô%Ð%å˜˜b™ !Ñ$Ô$¥e¨B°©G°QÑ&7Ô&7ˆqˆAàŸšÐ!IÐ!I¸4À¼=Ð!IÑ!IÔ!IÑJÔJˆIØŸš §¢Ñ!2Ô!2Ñ3Ô3ˆJÝ˜:‘”ˆHà˜!Š|ˆ|Ý¥¤
¨5°*Ñ =Ô =Ñ>Ô>�	Ø$-°Ñ$8Ð!à%6¸Ò%<Ð$lÐBSÐVYÒBYÐBkÐ^fÐjkÒ^kÐ!à(ð &Ø—M’M !Ñ$Ô$Ð$Ø—N’N 1Ñ%Ô%Ð%à×Ò˜RÑ Ô Ð Ø×Ò˜RÑ Ô Ð Ø�GŒ}ð FØ˜D œM¨!Ô,¨VÔ4Ð5Ð5Ô5¸Ñ:Ð5Ð5Ñ5Ø×#Ò# T¨4°¬=¸Ô+;¸FÔ+CÐ$DÑEÔEÐEùñ9	Fð@ ð•gÐSÐSÐSÐSÈÐSÑSÔSÑTÔT×`Ò`ÐabÑcÔcÐdeÔfØ	ôð Øð à5;ÐD�W�V‰_Œ_×(Ò(¨Ñ+Ô+¨AÔ.¨qÔ1Ð1À€FØ6=ÐF�W�WÑÔ×)Ò)¨!Ñ,Ô,¨QÔ/°Ô2Ð2À3€FØ<Ð< +×"9Ò"9Ñ";Ô";Ð<Ñ<Ô<€LØCÐC­9°\Ñ+BÔ+BÐCÑCÔC€LÝ˜Ñ%Ô%¨Ñ)€Mõ ,HØ�j +ñ,/ô ,/ñ)€\�< ¨|Øˆg�w ðDð Dð Dõ �4Ñ Ô €HØ"ð 0ð 0‰
ˆˆdØ�&Œ\˜!Œ_ˆØˆØ—]’]‘_”_ð 	ð 	ˆEÝ�5˜2‘:‰Œ )Ò+Ð+Ø˜”×&Ò& tÑ,Ô,Ð,Ø�Ø�ð ,ð Ð/�h˜r”l×)Ò)¨$Ñ/Ô/Ð/øõ #,¨LÑ"9Ô"9ð Rñ RÑˆ‘,�4˜Ø˜fœ‰ˆˆB��BØ�B‰w˜˜R™ˆ1ˆØ—H’HÐEÐE°t¸G´}ÐEÑEÔEÑFÔFˆ	Ø—W’W˜YŸ_š_Ñ.Ô.Ñ/Ô/ˆ
Ý! )™nœn­c°*©o¬o�)ˆàFOÐRSÂmÀm•C�œ
 5¨*Ñ5Ô5Ñ6Ô6¸ÑBÐBÐY\ˆ	Ø>FÈºl¸l�X 	Ñ)¨XÑ5¸Ñ:Ð:ÐPSˆØ%×+Ò+¨I¯OªOÑ,=Ô,=Ñ>Ô>ˆåÐdÐdÐdÐdÐd°8·>²>Ñ3CÔ3CÐdÑdÔdÑdÔdˆ	Ý˜	‘N”Nˆ	Ýð  4ð  4à)2ð 4ñ  4ô  4ñ 4ô 4Ðð
 �Z‘Ð$9Ò9Ð9À'Ð9ØÐ1Ò1Ð1°iÀ1²n°nÐIZ°nð  ˜Cð ð 	ð &/°!¢^ ^õ ˜i¨!™m¨tÑ3Ð6GÑGÈ1ÈxÉ<ÑXÐ[dÑdØ ñ"ô "ð "Ø9<ð 	ð %Ð$ RÐ)PÐ)PÀ<Ð)PÑ)PÔ)PÐR[Ñ\Ô\ˆØ$Ð$ RÐ)PÐ)PÀ<Ð)PÑ)PÔ)PÐR[Ñ\Ô\ˆÝmpÐqtØqtñnvô nvØyzòn{ð n{��c # s™mœm¨cÑ1Ð5FÑFÈ!ÈhÉ,ÑWÐZcÑcÐehÑiÔiÐið ADð 	ð ˜9‘}ˆå.¨q°&Ñ9Ô9ˆÝ.¨q°&Ñ9Ô9ˆõ % \°(Ô%;Õ=RÑSÔSˆÝ$ \°(Ô%;Õ=RÑSÔSˆÝ$ \°(Ô%;Õ=RÑSÔSˆÝ$ \°(Ô%;Õ=RÑSÔSˆð !(¨Ô 1Ð:˜˜°sˆØ '¨Ô 1Ð:˜˜°sˆØ '¨Ô 1Ð:˜˜°sˆØ '¨Ô 1Ð:˜˜°sˆåÐfÐf¨*ÐfÑfÔfÑfÔfˆØ!¥C¨	¡N¤NÑ2ˆ	à×Òð 
Ø�R˜˜R Ð$ð
àÐ<Ð<¨d°7¬mÐ<Ñ<Ô<ð
ð ˜ð
ð ˜ð	
ð
  ¨Ð!8  °Sð
ð À=ÐSTÒCTÐCT˜\¨$Ô/°-Ñ?Ð?ÐZ]ð
ð & ~ð
ð $ ^ð
ð " ?ð
ð # Oð
ð ˜ð
ð ˜ð
ð ˜ð
ð ˜ð
ð ˜nð
ð  ˜nð!
ð" ˜nð#
ð$ -Ø (õ #4Ý�B˜Ñ(Ñ)Ô)Õ+Dñ#Fô #Fà(ð1
ð 
ð 
ñ 	ô 	ð 	ñ 	ð6 Ðr   é,  c                 ó<  ‡‡@‡A‡B— | j         d         | j         d         }}||z  ŠA||z  Š@g }	|D ]`}
|
                     ¦   «         }|
d         }|d         ‰Az  |d         ‰@z  |d         ‰Az  |d         ‰@z  g|d<   |	                     |¦  «         Œa||}}t          ‰¦  «        }t	          j        |||ft          j        ¬¦  «        }h d£}h d£}d	‰v �r‰                     d	¦  «        }d
„ |                     ¦   «         D ¦   «         }|D ]à}t          |d         ‰Az  ¦  «        }t          |d         ‰@z  ¦  «        }t          |d         ‰Az  ¦  «        }t          |d         ‰@z  ¦  «        }t          d|¦  «        t          ||¦  «        }}t          d|¦  «        t          ||¦  «        }}t          dt          ‰A‰@¦  «        z  ¦  «        }||z
  |k    r||z
  |k    rd||||…||…f<   Œát          ˆfd„dD ¦   «         ¦  «        �r{|�|nt          |d¬¦  «        \  }}|€$t          |dd¬¦  «        }t          |dd¬¦  «        }ˆ@ˆAfd„|D ¦   «         }ˆ@ˆAfd„|D ¦   «         }d„ |	D ¦   «         }t          |||||¦  «        \  } }!}"}#}$}%}&}'| |!|"|#dœ}(|(                     ¦   «         D ]Û\  })}*|)‰vrŒ
‰                     |)¦  «        }t#          |	¦  «        D ]¬\  }+}
t%          t          |
d         ¦  «        \  }}}}t          d|¦  «        t          ||¦  «        }}t          d|¦  «        t          ||¦  «        }}t'          |*|+         t(          ¦  «        },t	          j        ||||…||…f         |,¦  «        ||||…||…f<   Œ­ŒÜ|	D ]÷}
t%          t          |
d         ¦  «        \  }}}}t          d|¦  «        t          ||¦  «        }}t          d|¦  «        t          ||¦  «        }}t#          ‰¦  «        D ]…\  }-})|)dv rŒ
|
|)         },|,dk    rŒ||-||…||…f         }.|)|v rt	          j        |.|,¦  «        }.n7|)|v rt	          j        |.|,z   dd¦  «        }.nt	          j        |.|,z   dd¦  «        }.|.||-||…||…f<   Œ†Œød‰v �r‰                     d¦  «        }t          |	¦  «        }/dg}0|/dk    �rñd„ |	D ¦   «         }1|1d„ |	D ¦   «         z  }1|1rnt/          |1¦  «        }2|/dz  ŠBt1          ˆBfd„|2                     ¦   «         D ¦   «         ¦  «        }3t1          t3          t5          dg|3z   ¦  «        ¦  «        ¦  «        }0|0|gz   }4t7          t          |4¦  «        dz
  ¦  «        D ]\}+t'          t9          |+dz   ¦  «        t:          ¦  «        }5|5||dd…t          |4|+         ¦  «        t          |4|+dz            ¦  «        …f<   Œ]d‰v rà‰                     d¦  «        }6|	D ]È}
t%          t          |
d         ¦  «        \  }}}}t	          j        |0|d z   ¦  «        }7t          d|7dz
  ¦  «        }8|0|8         }9t?          ||9z
  ¦  «        }:t'          |:t@          ¦  «        };t          d|¦  «        t          ||¦  «        }=}<t          d|¦  «        t          ||¦  «        }?}>|;||6|>|?…|<|=…f<   ŒÉ|S )!av  Create multi-channel spatial feature map for YF features.

    Args:
        vector_lines: optional pre-computed (h_lines, v_lines) tuple (as
            returned by get_vector_lines()+merge_lines()), e.g. cached in
            data_dict['vector_lines'] by pymupdf_util_base.extract_base_elements
            when 'vec_line' was in input_type. Passing this avoids
            re-parsing page.get_drawings() and re-rasterizing
            page.get_pixmap() (needed internally by get_vector_lines just to
            sample a background color) a second time for the same page. If
            not given, computed here as before.
    r   r   r(   r3   r5   r7   >   rÑ   rÎ   rÏ   rÐ   rÆ   rÉ   rÕ   rÒ   rÓ   rÔ   Úvector_margin_bÚvector_margin_lÚvector_margin_rÚvector_margin_trÈ   r×   rÌ   rÍ   >   rØ   Úimage_densityrË   rÊ   r!  c                 ó   — g | ]
}|d          ‘ŒS ©r(   r)   )r+   Úitms     r   r.   z&create_feature_map.<locals>.<listcomp>Ú  s   € ÐCÐCÐC c�c˜&”kÐCÐCÐCr   é   r   c              3   ó    •K  — | ]}|‰v V — Œ	d S r°   r)   )r+   rG   Ú	fet_namess     €r   rª   z%create_feature_map.<locals>.<genexpr>ê  s'   øè è € Ð
pÐ
p˜aˆ1�	ˆ>Ð
pÐ
pÐ
pÐ
pÐ
pÐ
pr   )r  r  r   r  NT)Úomit_invisibler÷   )Úorientationr}   Úvc                 ó\   •— g | ](}|j         ‰z  |j        ‰z  |j        ‰z  |j        ‰z  f‘Œ)S r)   ©Úx0Úy0rò   r³   ©r+   rp   Úscale_hÚscale_ws     €€r   r.   z&create_feature_map.<locals>.<listcomp>  ó<   ø€ ÐlÐlÐlÐ_`˜1œ4 '™>¨1¬4°'©>¸1¼4À'¹>È1Ì4ÐRYÉ>ÐZÐlÐlÐlr   c                 ó\   •— g | ](}|j         ‰z  |j        ‰z  |j        ‰z  |j        ‰z  f‘Œ)S r)   r,  r/  s     €€r   r.   z&create_feature_map.<locals>.<listcomp>  r2  r   c                 ó   — g | ]
}|d          ‘ŒS r#  r)   )r+   Úinfos     r   r.   z&create_feature_map.<locals>.<listcomp>  s   € Ð?Ð?Ð? d�T˜&”\Ð?Ð?Ð?r   )Úcolumn_degreer!  r  r  r   r  r   r6  c                 óz   — g | ]8}|                      d d¦  «        dk    ¯t          |d         d         d¦  «        ‘Œ9S )rÆ   r   rŒ   r(   r   ©Úgetrž   ©r+   rX   s     r   r.   z&create_feature_map.<locals>.<listcomp>?  sH   € ÐrÐrÐr¸!ÐST×SXÒSXÐYdÐfiÑSjÔSjÐnqÒSqÐSq�u Q v¤Y¨q¤\°1Ñ5Ô5ÐSqÐSqÐSqr   c                 óz   — g | ]8}|                      d d¦  «        dk    ¯t          |d         d         d¦  «        ‘Œ9S )rÆ   r   rŒ   r(   r3   r   r8  r:  s     r   r.   z&create_feature_map.<locals>.<listcomp>@  sH   € ÐsÐsÐs¸1ÐTU×TYÒTYÐZeÐgjÑTkÔTkÐorÒTrÐTr¥ a¨¤i°¤l°AÑ 6Ô 6ÐTrÐTrÐTrr   r
   c                 ó&   •— g | ]\  }}|‰k    ¯|‘ŒS r)   r)   )r+   rŸ   r§   Ú	thresholds      €r   r.   z&create_feature_map.<locals>.<listcomp>E  s)   ø€ Ð*_Ð*_Ð*_±°°AÐQRÐU^ÒQ^ÐQ^¨1ÐQ^ÐQ^ÐQ^r   r×   r   )!ÚshapeÚcopyrÝ   r9   r:   r>   Úfloat32ÚindexÚget_image_inforÛ   r   r   rA   r   r   rŠ   r²   rß   Úmapr#   ÚVECTOR_MARGIN_SUPPRESS_SCALEÚmaximumr   r   Úsortedrà   rÚ   r@   ÚfloatÚCOLUMN_DEGREE_SUPPRESS_SCALEÚsearchsortedr¦   ÚINDENT_SUPPRESS_SCALE_CANVAS)CÚpage_imgÚpager'  rè   Ú
fmap_widthÚfmap_heightÚvector_linesÚ
original_hÚ
original_wÚinfo_list_scaledr5  Úinfo_scaledr(   Úpage_hÚpage_wÚnum_channelsÚfeature_mapÚNON_ACCUMULATIVE_FEATURESÚACCUMULATIVE_FEATURESÚidxÚ
img_bboxesÚrectrò   r³   ró   rô   Úmin_sizeÚh_linesÚv_linesry   rz   Ú	vm_bboxesÚvm_raw_lÚvm_raw_rÚvm_raw_tÚvm_raw_bÚ
vm_found_lÚ
vm_found_rÚ
vm_found_tÚ
vm_found_bÚvm_channel_dataÚnameÚraw_arrrX   r   Úch_idxÚroiÚtotal_bboxesÚ
boundariesÚfiltered_coordsÚcoord_countsÚfound_boundariesÚextendedÚ
degree_valÚli_idxÚ
insert_idxÚb_idxÚlocal_baselineÚindent_distr×   Úx1_fÚx2_fÚy1_fÚy2_fr0  r1  r=  sC     `                                                             @@@r   Úcreate_feature_mapr~  ¨  sâ  øøøø€ ð &œ^¨AÔ.°´¸qÔ0A�
€Jà˜:Ñ%€GØ˜JÑ&€GàÐØð 	-ð 	-ˆØ—i’i‘k”kˆØ�FŒ|ˆà�ŒG�gÑØ�ŒG�gÑØ�ŒG�gÑØ�ŒG�gÑð	
ˆ�FÑð 	×Ò Ñ,Ô,Ð,Ð,à  *ˆF€FÝ�y‘>”>€LÝ”(˜L¨&°&Ð9ÅÄÐLÑLÔL€Kð!ð !ð !Ððð ð Ðð
 ˜)Ð#Ñ#Ø�oŠo˜oÑ.Ô.ˆØCÐC¨T×-@Ò-@Ñ-BÔ-BÐCÑCÔCˆ
Øð 	5ð 	5ˆDÝ�T˜!”W˜wÑ&Ñ'Ô'ˆBÝ�T˜!”W˜wÑ&Ñ'Ô'ˆBÝ�T˜!”W˜wÑ&Ñ'Ô'ˆBÝ�T˜!”W˜wÑ&Ñ'Ô'ˆBå˜˜B‘Z”Z¥ V¨R¡¤�ˆBÝ˜˜B‘Z”Z¥ V¨R¡¤�ˆBå˜2¥ G¨WÑ 5Ô 5Ñ5Ñ6Ô6ˆHØ�R‘˜HÒ$Ð$¨"¨r©'°hÒ)>Ð)>Ø14�˜C  B ¨¨2¨Ð-Ñ.øõ Ð
pÐ
pÐ
pÐ
pÐ#oÐ
pÑ
pÔ
pÑpÔpñ 3að& ,8Ð+C˜<˜<ÕIYÐZ^ÐosÐItÑItÔItÑˆ�ØÐÝ! '°sÀaÐHÑHÔHˆGÝ! '°sÀaÐHÑHÔHˆGàlÐlÐlÐlÐlÐdkÐlÑlÔlˆØlÐlÐlÐlÐlÐdkÐlÑlÔlˆà?Ð?Ð.>Ð?Ñ?Ô?ˆ	å;RØ�~ ~°v¸vñ<Gô <Gñ	9ˆ�8˜X xØ	�Z ¨Zð  (Ø'Ø'Ø'ð	
ð 
ˆð -×2Ò2Ñ4Ô4ð 		að 		a‰MˆD�'Ø˜9Ð$Ð$ØØ—/’/ $Ñ'Ô'ˆCÝ$Ð%5Ñ6Ô6ð að a‘��4Ý!$¥S¨$¨v¬,Ñ!7Ô!7‘��B˜˜BÝ˜Q ™œ¥S¨°¡_¤_�B�Ý˜Q ™œ¥S¨°¡_¤_�B�Ý'¨°¬
Õ4PÑQÔQ�Ý13´¸KÈÈRÐPRÈUÐTVÐWYÐTYÐHYÔ<ZÐ\_Ñ1`Ô1`�˜C  B ¨¨2¨Ð-Ñ.Ð.ðað !ð 4ð 4ˆÝ�S $ v¤,Ñ/Ô/‰ˆˆB��BÝ�Q˜‘”�S ¨™_œ_ˆBˆÝ�Q˜‘”�S ¨™_œ_ˆBˆå% iÑ0Ô0ð 	4ð 	4‰LˆF�DØð cð cð càà�t”*ˆCà�aŠxˆx˜à˜f b¨ e¨R°¨UÐ2Ô3ˆCàÐ0Ð0Ð0Ý”j  cÑ*Ô*��ØÐ.Ð.Ð.Ý”g˜c C™i¨¨cÑ2Ô2��å”g˜c C™i¨¨cÑ2Ô2�à03ˆK˜  2  r¨" uÐ,Ñ-Ð-ð%	4ð( ˜)Ð#Ñ#Ø�oŠo˜oÑ.Ô.ˆÝÐ+Ñ,Ô,ˆà�Sˆ
à˜!ÒÑØrÐrÐ?OÐrÑrÔrˆOØÐsÐsÐ@PÐsÑsÔsÑsˆOàð GÝ& Ñ7Ô7�Ø(¨4Ñ/�	Ý#)Ð*_Ð*_Ð*_Ð*_¸×9KÒ9KÑ9MÔ9MÐ*_Ñ*_Ô*_Ñ#`Ô#`Ð Ý#¥D­¨a¨SÐ3CÑ-CÑ)DÔ)DÑ$EÔ$EÑFÔF�
à! V HÑ,ˆHÝ�3˜x™=œ=¨1Ñ,Ñ-Ô-ð Xð X�õ /­u°Q¸±U©|¬|Õ=YÑZÔZ�
ØMW�˜C   ¥C¨°¬Ñ$4Ô$4µS¸À!ÀaÁ%¼Ñ5IÔ5IÐ$IÐIÑJÐJà# yÐ0Ð0Ø"ŸšÐ)=Ñ>Ô>�Ø,ð Sð S�DÝ%(­¨d°6¬lÑ%;Ô%;‘N�B˜˜B å!#¤°¸RÀ#¹XÑ!FÔ!F�JÝ  :°¡>Ñ2Ô2�EØ%/°Ô%6�Nõ #& b¨>Ñ&9Ñ":Ô":�KÝ):¸;ÕHdÑ)eÔ)eÐ&å!$ Q¨¡¤­S°¸©_¬_˜$�DÝ!$ Q¨¡¤­S°¸©_¬_˜$�DØ@R�K ¨¨T¨	°4¸°9Ð <Ñ=Ð=ð Ðr   c                 ó¬  — | j         d         | j         d         }}t          j        |¦  «        |z  |z                       t          j        ¦  «                             d|dz
  ¦  «        }t          j        |¦  «        |z  |z                       t          j        ¦  «                             d|dz
  ¦  «        }| d|dd…df         |ddd…f         f         S )aX  Nearest-neighbor resize of a (..., H, W) array via pure numpy indexing.
    No interpolation, no image library -- deliberately the cheapest possible
    resampling operator. Used only for the UPSAMPLE step in
    apply_multiscale_pyramid: broadcasting an already-aggregated coarse
    value back out doesn't need filtering, just a cheap repeat.éþÿÿÿéÿÿÿÿr   r   .N)r>  r:   ÚarangeÚastypeÚintpr   )ÚarrÚout_hÚout_wÚin_hÚin_wÚrow_idxÚcol_idxs          r   Ú
_nn_resizerŒ  l  s¿   € ð ”˜2” ¤	¨"¤ˆ$€DÝŒy˜ÑÔ $Ñ&¨Ñ.×6Ò6µr´wÑ?Ô?×DÒDÀQÈÈqÉÑQÔQ€GÝŒy˜ÑÔ $Ñ&¨Ñ.×6Ò6µr´wÑ?Ô?×DÒDÀQÈÈqÉÑQÔQ€GØˆs�G˜A˜A˜A˜t˜GÔ$ g¨d°A°A°A¨gÔ&6Ð6Ô7Ð7r   c           	      óŠ  — | j         \  }}}t          j        ||dz   |dz   ft          j        ¬¦  «        }t          j        | d|dd…dd…dd…f         ¬¦  «         t          j        |dd…dd…dd…f         d|dd…dd…dd…f         ¬¦  «         t          j        d||dz   ¦  «        }t          j        d||dz   ¦  «        }t          j        |dd…         ¦  «                             t          j        ¦  «        }	t          j	        t          j
        |dd…         ¦  «                             t          j        ¦  «        |	dz   ¦  «                             d|¦  «        }
t          j        |dd…         ¦  «                             t          j        ¦  «        }t          j	        t          j
        |dd…         ¦  «                             t          j        ¦  «        |dz   ¦  «                             d|¦  «        }t          j        |||ft          j        ¬¦  «        }t          |¦  «        D ]–}|dd…|
|         dd…f         |dd…|	|         dd…f         z
  }|
|         |	|         z
  }t          |¦  «        D ]H}|||         ||         z
  z  }|dd…||         f         |dd…||         f         z
  }||z  |dd…||f<   ŒIŒ—|S )aŠ  
    Area-average downsample of a (C, H, W) array to (C, out_h, out_w),
    via a summed-area table (same integral-image technique used in
    roi_pooling.py's SAT path).

    This is deliberately NOT nearest-neighbor: NN downsampling is point
    sampling, not filtering -- for a sparse/thin signal (e.g. a 1px-wide
    isolated region in an otherwise mostly-zero channel), the coarse sampling grid can
    simply miss it entirely, silently zeroing the signal out at every
    downstream scale (classic aliasing from decimating without a lowpass
    step first). Averaging over each output cell's full input footprint is
    the minimal "filter" that CNN pooling layers rely on to make a
    downsampled representation still reflect everything underneath it,
    rather than one arbitrary sample of it.

    Handles non-integer downsample ratios (e.g. 300 -> 38) by using
    fractional-but-rounded bin edges; this is an approximation (edge pixels
    can be a cell off) rather than exact sub-pixel area weighting, which is
    an acceptable simplification given feature map values are already
    smooth/near-binary indicators rather than precise imagery.
    r   r7   N)ÚaxisÚoutr3   r   r�  )r>  r:   r>   r=   ÚcumsumÚlinspaceÚfloorrƒ  r„  rE  Úceilr   Úemptyr@  r@   )r…  r†  r‡  ÚCÚHÚWÚsatÚ	row_edgesÚ	col_edgesÚr0Úr1Úc0Úc1r�  rX   rZ   Úarea_hÚjÚareaÚcell_sums                       r   Ú_average_pool_resizer£  x  s§  € ð, Œi�G€A€qˆ!Ý
Œ(�A�q˜1‘u˜a !™eÐ$­B¬JÐ
7Ñ
7Ô
7€CÝ„Iˆc˜˜s 1 1 1 a b b¨!¨"¨" 9œ~Ð.Ñ.Ô.Ð.Ý„Iˆc�!�!�!�Q�R�R˜˜˜�)Œn 1¨#¨a¨a¨a°°°°Q°R°R¨i¬.Ð9Ñ9Ô9Ð9å”˜A˜q %¨!¡)Ñ,Ô,€IÝ”˜A˜q %¨!¡)Ñ,Ô,€IÝ	Œ�)˜C˜R˜C”.Ñ	!Ô	!×	(Ò	(­¬Ñ	1Ô	1€BÝ	Œ•B”G˜I a b bœMÑ*Ô*×1Ò1µ"´'Ñ:Ô:¸BÀ¹FÑ	CÔ	C×	HÒ	HÈÈAÑ	NÔ	N€BÝ	Œ�)˜C˜R˜C”.Ñ	!Ô	!×	(Ò	(­¬Ñ	1Ô	1€BÝ	Œ•B”G˜I a b bœMÑ*Ô*×1Ò1µ"´'Ñ:Ô:¸BÀ¹FÑ	CÔ	C×	HÒ	HÈÈAÑ	NÔ	N€Bå
Œ(�A�u˜eÐ$­B¬JÐ
7Ñ
7Ô
7€CÝ�5‰\Œ\ð +ð +ˆØ�q�q�q˜"˜Qœ%   �{Ô# c¨!¨!¨!¨R°¬U°A°A°A¨+Ô&6Ñ6ˆØ�A”˜˜Aœ‘ˆÝ�u‘”ð 	+ð 	+ˆAØ˜R œU R¨¤U™]Ñ+ˆDØ    2 a¤5 Ô)¨H°Q°Q°Q¸¸1¼°XÔ,>Ñ>ˆHØ# d™?ˆC����1�a�‰LˆLð	+ð €Jr   c           
      óv  — | j         \  }}}| g}|D ]“}t          dt          t          ||z  ¦  «        ¦  «        ¦  «        }t          dt          t          ||z  ¦  «        ¦  «        ¦  «        }t	          | ||¦  «        }	t          |	||¦  «        }
|                     |
¦  «         Œ”t          j        |d¬¦  «        S )a$  
    FPN-style multi-scale context: for each scale, downsample feature_map
    via area-averaging (a box filter -- see _average_pool_resize) then
    upsample it back to the original resolution via nearest-neighbor
    broadcast, and concatenate every scale's result -- plus the original --
    along the channel axis.

    Downsampling averages, rather than point-samples, so every output cell
    reflects everything in its input footprint -- this is what makes the
    pyramid a genuine (if very shallow) approximation of CNN pooling's
    bottom-up aggregation, rather than lossy decimation. Upsampling only
    needs to broadcast an already-aggregated value back out, so nearest-
    neighbor is sufficient and cheap there.

    This replaces the old approach of picking a hand-tuned Gaussian blur
    kernel per channel (see create_feature_map's former per-channel blur
    loop, now removed): every channel gets the identical set of scales
    here, and which scale is actually useful for which channel/class is
    left for the downstream model to learn, rather than fixed by a
    human-chosen kernel size.

    Args:
        feature_map: (C, H, W) float32
        scales: tuple of downsample factors in (0, 1), e.g. the default
            (0.5, 0.25, 0.125) for 1/2, 1/4, 1/8 resolution pyramids.

    Returns:
        (C * (1 + len(scales)), H, W) float32 -- original channels first,
        followed by each scale's upsampled-back version, in the order
        `scales` was given. Use build_pyramid_fet_names() for the matching
        channel name list.
    r   r   )rŽ  )	r>  r   rÛ   rž   r£  rŒ  rÝ   r:   Úconcatenate)rW  Úscalesr•  r–  r—  Úpartsr!   Údown_hÚdown_wÚdownsampledÚ	upsampleds              r   Úapply_multiscale_pyramidr¬  ¥  s»   € ðB Ô�G€A€qˆ!ØˆM€EØð  ð  ˆÝ�Q��E ! e¡)Ñ,Ô,Ñ-Ô-Ñ.Ô.ˆÝ�Q��E ! e¡)Ñ,Ô,Ñ-Ô-Ñ.Ô.ˆÝ*¨;¸ÀÑGÔGˆÝ˜{¨A¨qÑ1Ô1ˆ	Ø�Š�YÑÔÐÐÝŒ>˜% aÐ(Ñ(Ô(Ð(r   c                 ó®   ‡— t          | ¦  «        }t          dt          |¦  «        dz   ¦  «        D ]#Š|                     ˆfd„| D ¦   «         ¦  «         Œ$|S )zö
    Expand a base channel name list to match apply_multiscale_pyramid()'s
    output channel order: original names, then each scale's names suffixed
    with '_ds{i}' (1-based index into `scales`, e.g. '_ds1' for the first
    scale given).
    r   c              3   ó&   •K  — | ]}|› d ‰› �V — ŒdS )Ú_dsNr)   )r+   rG   rX   s     €r   rª   z*build_pyramid_fet_names.<locals>.<genexpr>Ú  s-   øè è € Ð5Ð5 a˜�\�\˜a�\�\Ð5Ð5Ð5Ð5Ð5Ð5r   )rà   r@   r9   Úextend)r'  r¦  ÚnamesrX   s      @r   Úbuild_pyramid_fet_namesr²  Ñ  sb   ø€ õ �‰OŒO€EÝ�1•c˜&‘k”k A‘oÑ&Ô&ð 6ð 6ˆØ�ŠÐ5Ð5Ð5Ð5¨9Ð5Ñ5Ô5Ñ5Ô5Ð5Ð5Ø€Lr   FTc           	      ó  — g d¢}|r|g d¢z  }| d         }|j         d         |j         d         }	}t          |¦  «        }
t          |||
||                      d¦  «        ¬¦  «        }|r|S t	          ||¬¦  «        }t          ||¦  «        }| d	         }t          |d
         ||	|d¬¦  «        }t          | d         ¦  «        D ]?\  }}||         }t          |¦  «        D ]"\  }}t          ||         ¦  «        }||d|z   <   Œ#Œ@| S )a¶  
    Extract Youngmin's Features (YF) - spatial feature maps.

    Args:
        pyramid_scales: downsample factors passed to apply_multiscale_pyramid().
            Applied ONLY to the node/edge feature path below -- NOT to the
            raw feature_map returned when return_fet_map=True. That raw map
            feeds IMF's aug_fetmap channel and must keep its original,
            model-expected channel count; changing it would silently break
            any ymf-trained network's expected input shape.
        include_margin_found_flags: adds margin_l_found/r/t/b -- explicit
            binary "was an actual neighboring line found in this direction"
            channels, separate from margin_l/r/t/b's (now compressed) raw
            gap value. Default True.
            *** CHANNEL-COUNT-CHANGING FLAG ***: this adds 4 channels
            (21 -> 25 base channels, 84 -> 100 with the default pyramid).
            Any model/pipeline already trained against the old channel
            count/order -- in particular the IMF aug_fetmap path fed by
            return_fet_map=True -- MUST either be retrained or called with
            include_margin_found_flags=False to keep the old shape.
    )rÆ   rÈ   rÉ   rØ   rÊ   rË   rÌ   rÖ   rÍ   rÇ   r6  r×   rÎ   rÏ   rÐ   rÑ   r  r  r   r  r!  )rÒ   rÓ   rÔ   rÕ   Úimager   r   rO  )rè   r'  rO  )r¦  rx   )N.)Úmean)Úpooling_opsÚcustom_featuresÚyf_)	r>  r  r~  r9  r¬  r²  r   rß   rG  )Ú	data_dictrL  rç   Úreturn_fet_mapÚpyramid_scalesÚinclude_margin_found_flagsr'  rK  rT  rU  Úpdf_inforW  Úpyramid_mapÚpyramid_fet_namesÚoriginal_bboxesÚyf_features_origrX   Úcustom_featureÚorig_vectorÚf_idxÚf_namer   s                         r   Úextract_yf_featuresrÆ  Þ  sk  € ð0ð ð €Ið "ð ^ØÐ]Ð]Ð]Ñ]ˆ	à˜Ô!€HØ”^ AÔ&¨¬°qÔ(9ˆF€Få% iÑ0Ô0€HÝ$ X¨t¸xÐS\Ø2;·-²-ÀÑ2OÔ2OðQñ Qô Q€Kð ð ØÐå*¨;¸~ÐNÑNÔN€KÝ/°	¸>ÑJÔJÐà Ô)€OÝ;Ø�IÔØØØØðñ ô Ðõ ' yÐ1BÔ'CÑDÔDð 1ð 1Ñˆˆ>Ø& qÔ)ˆå&Ð'8Ñ9Ô9ð 	1ð 	1‰MˆE�6Ý˜ EÔ*Ñ+Ô+ˆCØ-0ˆN˜5 6™>Ñ*Ð*ð	1ð Ðr   )r   )r$   r$   rm   )r  r  N)Ú__doc__r¹   r   Únumpyr:   Úcollectionsr   r   Úpymupdf_util_baser   r   Úroi_poolingr   ÚDEFAULT_PYRAMID_SCALESr   rå   rD  rH  ræ   rJ  r#   ra   rŠ   r  r~  rŒ  r£  r¬  r²  rÆ  r)   r   r   ú<module>rÍ     s»  ððð ð 
€	€	€	Ø €€€Ø Ð Ð Ð Ø ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,à <Ð <Ð <Ð <Ð <Ð <Ð <Ð <Ø =Ð =Ð =Ð =Ð =Ð =à+Ð ð-ð -ð -ð4 Ð Ø#Ð Ø"Ð Ø!Ð Ø#Ð ð"Dð "Dð "Dð "DðJ CFðNJð NJð NJð NJðbEJð EJð EJð EJðPmð mð mð` Z]Ø$(ðAð Að Að AðH	8ð 	8ð 	8ð*ð *ð *ðZ 2Hð ))ð ))ð ))ð ))ðX /Eð 
ð 
ð 
ð 
ð DIØ'=Ø37ðJð Jð Jð Jð Jð Jr   