§
    �Øj·1  ã                   ó°   — d Z ddlZddlZddlmZ ddlZddlZg d¢Z	dZ
dZd„ Zdd	„Z G d
„ d¦  «        Zd„ Zd„ Zd„ Zd„ Zedk    rdZ ee¦  «         dS dS )a‹  
LayoutProbAnalyzer
Purpose: Analyze per-class layout probability maps from a PDF page using an ONNX model.

The underlying network accepts a grayscale page image and returns a combined
output tensor containing internal feature channels followed by segmentation
logit channels. This class extracts only the segmentation head output
(the last num_classes channels) and converts it to per-pixel probability maps.

Usage:
    analyzer = LayoutProbAnalyzer()                  # uses default ONNX path
    analyzer = LayoutProbAnalyzer("custom.onnx")     # explicit path
    prob_map = analyzer.get_layout_prob(page)        # (H_page, W_page, num_classes)
é    N)ÚPath)Ú
backgroundÚtextÚtitleÚpictureÚtablez	list-itemzpage-headerzpage-footerzsection-headerÚfootnoteÚcaptionÚformulaé   Úhotc                 ó6  — | j         dd…         \  }}| j        dk    }|r| dd…dd…t          j        f         } t          j        |¦  «        dz   ||z  z  dz
  }t          j        |¦  «        dz   ||z  z  dz
  }t          j        t          j        |¦  «                             t          j        ¦  «        d|dz
  ¦  «        }t          j        |dz   d|dz
  ¦  «        }	t          j        t          j        |¦  «                             t          j        ¦  «        d|dz
  ¦  «        }
t          j        |
dz   d|dz
  ¦  «        }||z
                       t          j	        ¦  «        dd…t          j        f         }||
z
                       t          j	        ¦  «        t          j        dd…f         }|  
                    ddd¦  «                             t          j	        ¦  «        }|dd…|dd…f         dd…dd…|
f         d|z
  z  |dd…|dd…f         dd…dd…|f         |z  z   }|dd…|	dd…f         dd…dd…|
f         d|z
  z  |dd…|	dd…f         dd…dd…|f         |z  z   }|d|z
  z  ||z  z    
                    ddd¦  «        }|r|dd…dd…df         }|S )ad  
    Resize a 2-D or 3-D numpy array to (target_h, target_w) using bilinear
    interpolation. No external libraries required.

    Args:
        img:      np.ndarray, shape (H, W) or (H, W, C)
        target_h: int
        target_w: int

    Returns:
        np.ndarray of shape (target_h, target_w) or (target_h, target_w, C),
        dtype float32.
    Né   g      à?r   é   ç      ð?)ÚshapeÚndimÚnpÚnewaxisÚarangeÚclipÚfloorÚastypeÚint32Úfloat32Ú	transpose)ÚimgÚtarget_hÚtarget_wÚsrc_hÚsrc_wÚis_2dÚ
row_coordsÚ
col_coordsÚrow0Úrow1Úcol0Úcol1ÚdrÚdcÚimg_chwÚtopÚbottomÚouts                     ú›/Users/tedpeters/Documents/Projects/Claude Projects/Misc Tools/notename-sheets/.venv/lib/python3.11/site-packages/pymupdf/layout/onnx/LayoutProbAnalyzer.pyÚ_resize_bilinearr0   &   s·  € ð ”9˜R˜a˜R”=�L€Eˆ5ØŒH˜ŠM€EØð $Ø�!�!�!�Q�Q�Q�œ
Ð"Ô#ˆå”)˜HÑ%Ô%¨Ñ+°¸Ñ0@ÑAÀCÑG€JÝ”)˜HÑ%Ô%¨Ñ+°¸Ñ0@ÑAÀCÑG€JåŒ7•2”8˜JÑ'Ô'×.Ò.­r¬xÑ8Ô8¸!¸UÀQ¹YÑGÔG€DÝŒ7�4˜!‘8¸!¸UÀQ¹YÑGÔG€DÝŒ7•2”8˜JÑ'Ô'×.Ò.­r¬xÑ8Ô8¸!¸UÀQ¹YÑGÔG€DÝŒ7�4˜!‘8¸!¸UÀQ¹YÑGÔG€Dà
�tÑ
×	#Ò	#¥B¤JÑ	/Ô	/°°°µ2´:°Ô	>€BØ
�tÑ
×	#Ò	#¥B¤JÑ	/Ô	/µ´
¸A¸A¸A°Ô	>€Bð �mŠm˜A˜q !Ñ$Ô$×+Ò+­B¬JÑ7Ô7€GØ�Q�Q�Q˜˜a˜a˜a�ZÔ     A A A t Ô,°°b±Ñ9Ø�Q�Q�Q˜˜a˜a˜a�ZÔ     A A A t Ô,¨rÑ1ñ2€Cà�Q�Q�Q˜˜a˜a˜a�ZÔ     A A A t Ô,°°b±Ñ9Ø�Q�Q�Q˜˜a˜a˜a�ZÔ     A A A t Ô,¨rÑ1ñ2€Fà�#˜‘(Ñ˜f r™kÑ)×
4Ò
4°Q¸¸1Ñ
=Ô
=€Càð Ø�!�!�!�Q�Q�Q˜�'ŒlˆØ€Jó    r   c                 óÚ   — | |z  }|                      dd¬¦  «        }t          j        ||z
  ¦  «        }|                     dd¬¦  «        }||z                       t          j        ¦  «        S )a  
    Apply temperature-scaled softmax across the class axis (axis 0).

    The input is expected to be raw segmentation logits, which may contain
    negative values. No ReLU masking is applied; standard numerically stable
    softmax is used directly.

    Temperature controls the sharpness of the distribution per pixel:
        T < 1 : sharper  (winner-takes-all strengthened)
        T = 1 : standard softmax
        T > 1 : smoother (probability spread more evenly across classes)

    Args:
        seg_logits:  np.ndarray, shape (num_classes, H, W), raw logits (may be negative)
        temperature: float, must be > 0 (default 1.0)

    Returns:
        np.ndarray, shape (num_classes, H, W), float32, values in [0, 1],
        summing to 1 along axis 0 at every pixel.
    r   T)ÚaxisÚkeepdims)Úmaxr   ÚexpÚsumr   r   )Ú
seg_logitsÚtemperatureÚscaledÚsafe_maxr6   Údenoms         r/   Ú_softmax_over_classesr=   R   sh   € ð* ˜+Ñ%€Fð �zŠz˜q¨4ˆzÑ0Ô0€HÝŒv�f˜xÑ'Ñ(Ô(€CØ�wŠw˜A¨ˆwÑ-Ô-€Eà�%‰K×Ò¥¤
Ñ+Ô+Ð+r1   c                   ó    — e Zd ZdZdd„Zd„ ZdS )ÚLayoutProbAnalyzeraI  
    Loads an ONNX segmentation model and produces per-class probability maps
    for a given PDF page.

    The network output is a combined tensor of internal feature channels and
    segmentation logit channels. Only the last num_classes channels (the
    segmentation head output) are used; all preceding feature channels are
    discarded.

    Per-pixel probabilities are computed via temperature-scaled softmax across
    the class axis, so all classes compete and probabilities sum to 1 per pixel.
    A higher temperature smooths the distribution (less winner-takes-all).
    Nr   c                 ó@  — |€5t          t          ¦  «                             ¦   «         j        j        }|› d�}t	          |d¦  «        | _        | j                             ¦   «         d         j        }|d         | _        |d         | _	        || _
        t          | _        dS )aF  
        Args:
            onnx_path:   str or None.
                         If None, defaults to
                         <repo_root>/resources/onnx/feature_imf1.onnx
                         where <repo_root> is two directories above this file.
            temperature: float > 0 (default 1.0).
                         Controls softmax sharpness across classes per pixel.
                         T > 1 spreads probability more evenly (less winner-takes-all).
                         T = 1 is standard softmax.
                         T < 1 sharpens the distribution.
        Nz!/resources/onnx/feature_imf1.onnxr   r   é   )r   Ú__file__ÚresolveÚparentÚmake_sessionÚ_sessionÚ
get_inputsr   Ú	_target_hÚ	_target_wÚ_temperatureÚ_CLASS_NAMESÚclass_names)ÚselfÚ	onnx_pathr9   Ú
script_dirÚinput_shapes        r/   Ú__init__zLayoutProbAnalyzer.__init__„   s�   € ð ÐÝ�h™œ×/Ò/Ñ1Ô1Ô8Ô?ˆJØ&ÐIÐIÐIˆIå(¨°DÑ9Ô9ˆŒØ œM×4Ò4Ñ6Ô6°qÔ9Ô?ˆØ'¨œNˆŒØ'¨œNˆŒØ'ˆÔÝ(ˆÔÐÐr1   c                 óú  — |                      ¦   «         }t          j        |j        t          j        ¬¦  «        }|                     |j        |j        |j        ¦  «        }|j	        dd…         \  }}|j	        d         dk    rŠ|dd…dd…df          
                    t          j        ¦  «        |dd…dd…df          
                    t          j        ¦  «        z   |dd…dd…df          
                    t          j        ¦  «        z   dz  }n,|dd…dd…df          
                    t          j        ¦  «        }t          || j        | j        ¦  «        }|                     ¦   «         |                     ¦   «         }
}	|
|	k    r||	z
  |
|	z
  z  }n t          j        |t          j        ¬¦  «        }|t          j        t          j        dd…dd…f         }| j                             ¦   «         d         j        }| j                             d||i¦  «        d         }t/          t0          ¦  «        }|d| d…dd…dd…f         }t3          || j        ¦  «        }t          j        |d¦  «        }t          |||¦  «        }|S )	a™  
        Compute per-class layout probability maps for a PyMuPDF page.

        Pipeline:
            1. Render the page to a numpy array at its default resolution.
            2. Convert to grayscale and resize to the model input resolution
               using numpy-only bilinear interpolation.
            3. Normalize the grayscale image to [0, 1].
            4. Run ONNX inference; slice the last num_classes channels from
               the combined output tensor to obtain segmentation logits.
            5. Apply temperature-scaled softmax to convert logits to
               per-pixel class probabilities.
            6. Resize the probability map back to the original page resolution.

        Args:
            page: fitz.Page (PyMuPDF page object)

        Returns:
            np.ndarray of shape (H_page, W_page, num_classes), float32.
            The last axis is aligned with self.class_names.
        ©ÚdtypeNr   rA   r   r   g      @)r   r   r   )Ú
get_pixmapr   Ú
frombufferÚsamplesÚuint8ÚreshapeÚheightÚwidthÚnr   r   r   r0   rH   rI   Úminr5   Ú
zeros_liker   rF   rG   ÚnameÚrunÚlenrK   r=   rJ   r   )rM   ÚpageÚpixÚ
bytes_dataÚpage_imgÚpage_hÚpage_wÚgrayÚgray_resizedÚloÚhiÚnn_inputÚ
input_nameÚraw_outÚ	n_classesr8   Úprob_mapÚprob_map_hwcÚprob_resizeds                      r/   Úget_layout_probz"LayoutProbAnalyzer.get_layout_prob    sX  € ð. —_’_Ñ&Ô&ˆÝ”] 3¤;µb´hÐ?Ñ?Ô?ˆ
Ø×'Ò'¨¬
°C´I¸s¼uÑEÔEˆØ!œ¨¨¨Ô+‰ˆ�ð Œ>˜!Ô Ò!Ð!Ø˜Q˜Q˜Q    1˜WÔ%×,Ò,­R¬ZÑ8Ô8Ø˜q˜q˜q ! ! ! Q˜wÔ'×.Ò.­r¬zÑ:Ô:ñ;à˜q˜q˜q ! ! ! Q˜wÔ'×.Ò.­r¬zÑ:Ô:ñ;à>AñBˆDˆDð ˜A˜A˜A˜q˜q˜q !˜GÔ$×+Ò+­B¬JÑ7Ô7ˆDõ (¨¨d¬n¸d¼nÑMÔMˆØ×!Ò!Ñ#Ô# \×%5Ò%5Ñ%7Ô%7ˆBˆØ�Š7ˆ7Ø(¨2Ñ-°"°r±'Ñ:ˆLˆLåœ=¨½R¼ZÐHÑHÔHˆLð "¥"¤*­b¬j¸!¸!¸!¸Q¸Q¸QÐ">Ô?ˆØ”]×-Ò-Ñ/Ô/°Ô2Ô7ˆ
Ø”]×&Ò& t¨j¸(Ð-CÑDÔDÀQÔGˆå�Ñ%Ô%ˆ	Ø˜Q  
  ¨Q¨Q¨Q°°°Ð1Ô2ˆ
õ )¨°TÔ5FÑGÔGˆõ ”| H¨iÑ8Ô8ˆÝ'¨°f¸fÑEÔEˆàÐr1   )Nr   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__rQ   rs   © r1   r/   r?   r?   u   sA   € € € € € ðð ð)ð )ð )ð )ð8>ð >ð >ð >ð >r1   r?   c                 ó¸   — | j         d         dk    r| dd…dd…dd…f         S | j         d         dk    rt          j        | dd¬¦  «        S | dd…dd…dd…f         S )zGReturn (H, W, 3) uint8 suitable for imshow from a pymupdf pixmap array.r   é   NrA   r   )r3   )r   r   Úrepeat)re   s    r/   Ú_page_img_to_rgbr|   å   sw   € à„~�aÔ˜AÒÐØ˜˜˜˜1˜1˜1˜b˜q˜b˜Ô!Ð!Ø„~�aÔ˜AÒÐÝŒy˜ 1¨1Ð-Ñ-Ô-Ð-Ø�A�A�A�q�q�q˜"˜1˜"�HÔÐr1   c                 óp  — ddl m} t          |¦  «        }|t          z   dz
  t          z  }d|z   }|                     |t          t          dz  |dz  fd¬¦  «        \  }	}
|	                     |› d|dz   › �dd	¬
¦  «         |
d         d                              | ¦  «         |
d         d                              dd¬¦  «         |
d         d                              d¦  «         t          dt          ¦  «        D ]#}|
d         |                              d¦  «         Œ$t          |¦  «        D ]š\  }}d|t          z  z   }|t          z  }|
|         |         }|                     |dd…dd…|f         t          dd¬¦  «        }|                     |d¬¦  «         |                     d¦  «         |                     ||dd¬¦  «         Œ›|t          z  }|r<t          |t          ¦  «        D ]&}|
|dz
           |                              d¦  «         Œ'|                     ¦   «          |                     ¦   «          dS )a  
    Display the original page image and per-class probability heatmaps.

    Args:
        page_img_rgb: np.ndarray (H, W, 3) uint8
        prob_map:     np.ndarray (H, W, C) float32
        class_names:  list[str]
        pdf_name:     str
        page_idx:     int, 0-based
    r   Nr   rA   F)ÚfigsizeÚsqueezez
  |  page é   g)\�Âõ(ð?)ÚfontsizeÚyÚoriginalé	   )r�   Úoffg        r   )ÚcmapÚvminÚvmaxé   gZd;ßO�§?g{®Gáz¤?)ÚaxÚfractionÚpad)Úmatplotlib.pyplotÚpyplotra   Ú	_VIZ_COLSÚsubplotsÚsuptitleÚimshowÚ	set_titler3   ÚrangeÚ	enumerateÚ	_VIZ_CMAPÚcolorbarÚtight_layoutÚshow)Úpage_img_rgbrp   rL   Úpdf_nameÚpage_idxÚpltÚnum_classesÚ
class_rowsÚ
total_rowsÚfigÚaxesÚcolÚidxr_   ÚrowrŠ   ÚimÚ	remainders                     r/   Ú_visualize_pager¨   î   sV  € ð $Ð#Ð#Ð#Ð#Ð#å�kÑ"Ô"€KØ¥Ñ*¨QÑ.µ9Ñ<€JØ�j‘.€Jà—’Ø•IÝ˜Q‘ 
¨Q¡Ð/Øð ñ ô �I€Cˆð
 ‡L‚L�HÐ6Ð6¨°1©Ð6Ð6ÀÀt€LÑLÔLÐLð 	ˆ„GˆA„J×Ò�lÑ#Ô#Ð#Øˆ„GˆA„J×Ò˜¨aÐÑ0Ô0Ð0Øˆ„GˆA„J‡O‚O�EÑÔÐÝ�Q�	Ñ"Ô"ð !ð !ˆØˆQŒ�Œ×Ò˜%Ñ Ô Ð Ð õ ˜{Ñ+Ô+ð :ð :‰	ˆˆTØ�#�Ñ"Ñ"ˆØ•I‰oˆØ�3Œi˜ŒnˆØ�iŠi˜    A A A s Ô+µ)À#ÈCˆiÑPÔPˆØ
�Š�T AˆÑ&Ô&Ð&Ø
�Š�‰ŒˆØ�Š�R˜B¨°DˆÑ9Ô9Ð9Ð9ð �iÑ'€IØð 2Ý˜¥IÑ.Ô.ð 	2ð 	2ˆCØ�˜a‘Ô  Ô%×*Ò*¨5Ñ1Ô1Ð1Ð1à×ÒÑÔÐØ‡H‚H�J„J€J€J€Jr1   c           	      ó  — t          t          j        t          j                             | dd¦  «        d¬¦  «        ¦  «        }|s?t          t          j        t          j                             | d¦  «        ¦  «        ¦  «        }|S )zBReturn a sorted list of PDF paths found recursively under pdf_dir.z**z*.pdfT)Ú	recursive)ÚsortedÚglobÚosÚpathÚjoin)Úpdf_dirÚpathss     r/   Ú
_scan_pdfsr²   !  se   € å•4”9�RœWŸ\š\¨'°4¸ÑAÔAÈTÐRÑRÔRÑSÔS€EØð BÝ•t”y¥¤§¢¨g°wÑ!?Ô!?Ñ@Ô@ÑAÔAˆØ€Lr1   c           	      óú  — dd l }t          | ¦  «        }|st          d| › �¦  «         d S t          dt          |¦  «        › d�¦  «         t	          ¦   «         }|D �]}t
          j                             |¦  «        }t          d|› �¦  «         |                     |¦  «        }t          t          |¦  «        ¦  «        D ]¥}||         }| 
                    ¦   «         }	t          j        |	j        t          j        ¬¦  «        }
|
                     |	j        |	j        |	j        ¦  «        }|                     |¦  «        }t)          |¦  «        }t+          ||t,          ||¦  «         Œ¦|                     ¦   «          �Œ!d S )Nr   zNo PDF files found in: zFound z PDF file(s).zProcessing: rS   )Úfitzr²   Úprintra   r?   r­   r®   ÚbasenameÚopenr”   rU   r   rV   rW   rX   rY   rZ   r[   r\   rs   r|   r¨   rK   Úclose)r°   r´   Ú	pdf_pathsÚanalyzerÚpdf_pathr›   Údocrœ   rb   rc   rd   re   rp   rš   s                 r/   Ú	_run_testr½   )  so  € Ø€K€K€Kå˜7Ñ#Ô#€IØð ÝÐ1¨Ð1Ð1Ñ2Ô2Ð2Øˆå	Ð
0•3�y‘>”>Ð
0Ð
0Ð
0Ñ1Ô1Ð1Ý!Ñ#Ô#€Hàð ñ ˆÝ”7×#Ò# HÑ-Ô-ˆÝÐ'˜XÐ'Ð'Ñ(Ô(Ð(Ø�iŠi˜Ñ!Ô!ˆå�c #™hœh™œð 		Vð 		VˆHØ�x”=ˆDàŸšÑ*Ô*ˆCÝœ s¤{½"¼(ÐCÑCÔCˆJØ#×+Ò+¨C¬J¸¼	À3Ä5ÑIÔIˆHà#×3Ò3°DÑ9Ô9ˆHÝ+¨HÑ5Ô5ˆLÝ˜L¨(µLÀ(ÈHÑUÔUÐUÐUà�	Š	‰Œˆ‰ð!ð r1   Ú__main__z'/media/win/PTMP/PDF/BOKDataset/book/PDF)r   )rw   r¬   r­   Úpathlibr   Únumpyr   ÚonnxruntimeÚortrK   r�   r–   r0   r=   r?   r|   r¨   r²   r½   rt   r°   rx   r1   r/   ú<module>rÃ      s-  ððð ð €€€Ø 	€	€	€	Ø Ð Ð Ð Ð Ð à Ð Ð Ð Ø Ð Ð Ð ðð ð €ð €	Ø€	ð)ð )ð )ðX,ð ,ð ,ð ,ðFið ið ið ið iñ iô ið ið`ð ð ð0ð 0ð 0ðfð ð ðð ð ð< ˆzÒÐØ7€GØ€IˆgÑÔÐÐÐð Ðr1   