§
    �WêjÕV  ã            
      ó   — U d Z ddlmZ ddlmZ ddlm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 d2d„Z G d„ d¦  «        Zedk    �r0ddlZddlZ ej        d¬¦  «        Ze                     dd¬¦  «         e                     dd¬¦  «         e                     dedd¬¦  «         e                     d ed!d"¬¦  «         e                     d#d$g d%¢d&¬'¦  «         e                     ¦   «         Z eej        ej        ej        ¬(¦  «        Z  eej!        ¦  «        Z!g Z"d)e#d*<   ej$        D ]|Z%e" &                     e'e! (                    d+e%› �¦  «        ¦  «        ¦  «         e" &                     e'e! (                    d+e% )                    ¦   «         › �¦  «        ¦  «        ¦  «         Œ} e' e*e"¦  «        ¦  «        Z"e"s e+d,e!› �¦  «         n e+d- e,e"¦  «        › d.�¦  «         e"D ]’Z- ej.         e/e-¦  «        ¦  «        Z0e0€ e+d/e-j1        › �¦  «         Œ1e  2                    e0¦  «        Z3 e+e-j1        › d0 e,e3j4        ¦  «        › d1 e,e3j5        ¦  «        › �¦  «         e  6                    e0e3¦  «         Œ‘dS dS )3aæ  
TableGridExtractor.py

Loads an exported GridModelV1 ONNX model and predicts horizontal / vertical
grid boundary positions from a cropped table image.

Post-processing pipeline
------------------------
1. Resize input image to model input size.
2. Run ONNX inference -> h_heatmap (H,), v_heatmap (W,).
3. Apply threshold to each 1D heatmap.
4. Run 1D Connected Component Labeling (CCL) on the thresholded signal.
5. Compute weighted centroid of each component -> boundary coordinate.

é    )Úannotations)ÚPath)ÚOptionalNé   )Úresize_imageÚto_grayé   )ÚGridPredictionÚCellInfo)Úmake_sessionÚheatmapú
np.ndarrayÚ	thresholdÚfloatÚreturnúlist[float]c                ó  — | |k    }g }d}g }g }t          t          | |¦  «        ¦  «        D ]Í\  }\  }}	|	r:d}|                     t          |¦  «        ¦  «         |                     |¦  «         ŒD|r‡t	          |¦  «        }
|
dk    r+t	          d„ t          ||¦  «        D ¦   «         ¦  «        |
z  }n,t          t	          |¦  «        ¦  «        t          |¦  «        z  }|                     |¦  «         g }g }d}ŒÎ|rƒ|r�t	          |¦  «        }
|
dk    r+t	          d„ t          ||¦  «        D ¦   «         ¦  «        |
z  }n,t          t	          |¦  «        ¦  «        t          |¦  «        z  }|                     |¦  «         t          |¦  «        S )aK  
    Apply threshold to a 1D heatmap, find connected components, and return
    the weighted centroid of each component.

    Parameters
    ----------
    heatmap   : 1D float32 array
    threshold : minimum value to consider active

    Returns
    -------
    Sorted list of centroid positions (float, 0-based index space).
    FTr   c              3  ó&   K  — | ]\  }}||z  V — Œd S ©N© ©Ú.0ÚvÚis      ú˜/Users/tedpeters/Documents/Projects/Claude Projects/TPC Houses/house-viewer/.venv/lib/python3.11/site-packages/pymupdf/layout/onnx/TableGridExtractor.pyú	<genexpr>z$_ccl_1d_centroids.<locals>.<genexpr>C   s*   è è € Ð"QÐ"Q©T¨Q° 1 q¡5Ð"QÐ"QÐ"QÐ"QÐ"QÐ"Qó    c              3  ó&   K  — | ]\  }}||z  V — Œd S r   r   r   s      r   r   z$_ccl_1d_centroids.<locals>.<genexpr>O   s*   è è € ÐIÐI¡T Q¨˜1˜q™5ÐIÐIÐIÐIÐIÐIr   )Ú	enumerateÚzipÚappendr   ÚsumÚlenÚsorted)r   r   ÚactiveÚ	centroidsÚin_groupÚ
group_valsÚ
group_idxsr   ÚvalÚ	is_activeÚtotalÚcentroids               r   Ú_ccl_1d_centroidsr.   !   s©  € ð" ˜	Ò!€FØ€Ià€HØ €JØ €Jå(­¨W°fÑ)=Ô)=Ñ>Ô>ð !ð !ÑˆÑˆC�Øð 	!ØˆHØ×Ò�e C™jœjÑ)Ô)Ð)Ø×Ò˜aÑ Ô Ð Ð àð 
!å˜J™œ�Ø˜1’9�9Ý"Ð"QÐ"QµS¸ÀZÑ5PÔ5PÐ"QÑ"QÔ"QÑQÔQÐTYÑY�H�Hå$¥S¨¡_¤_Ñ5Ô5½¸J¹¼ÑG�HØ× Ò  Ñ*Ô*Ð*Ø�
Ø�
Ø �øð ð #�Jð #Ý�J‘”ˆØ�1Š9ˆ9ÝÐIÐI­S°¸ZÑ-HÔ-HÐIÑIÔIÑIÔIÈEÑQˆHˆHå�S ™_œ_Ñ-Ô-µ°J±´Ñ?ˆHØ×Ò˜Ñ"Ô"Ð"å�)ÑÔÐr   c                  óh   — e Zd ZdZ	 	 	 d.d/d„Zd0d„Zed1d„¦   «         Zd2d „Z	 	 	 d3d4d&„Z		 	 d5d6d-„Z
dS )7ÚTableGridExtractorzÏ
    ONNX-based table grid boundary extractor.

    Usage
    -----
    extractor = TableGridExtractor("grid_model_v1.onnx")
    pred = extractor.predict(image_bgr)
    print(pred.h_lines, pred.v_lines)
    çffffffÖ?çÍÌÌÌÌÌÜ?NÚ	onnx_pathú
str | PathÚh_on_thresholdr   Úv_on_thresholdÚ	providersúOptional[list[str]]r   ÚNonec                ó†  — t          |¦  «        | _        || _        || _        |€dg}t	          t          | j        ¦  «        |¦  «        | _        | j                             ¦   «         d         }t          |j	        d         ¦  «        | _
        t          |j	        d         ¦  «        | _        t          j        dd| j
        | j        ft          j        ¬¦  «        }| j                             dd|i¦  «        }t          |d         j	        d         ¦  «        | _        t          |d         j	        d         ¦  «        | _        dS )	ae  
        Parameters
        ----------
        onnx_path      : path to the exported .onnx model file
        hmap_threshold : activation threshold for h_heatmap CCL
        vmap_threshold : activation threshold for v_heatmap CCL
        providers      : ONNX Runtime execution providers
                         (default: ["CPUExecutionProvider"])
        NÚCPUExecutionProviderr   r   é   r	   ©ÚdtypeÚimage)r   r3   r5   r6   r   ÚstrÚ_sessÚ
get_inputsÚintÚshapeÚ_input_hÚ_input_wÚnpÚzerosÚfloat32ÚrunÚ_out_hÚ_out_w)Úselfr3   r5   r6   r7   ÚinpÚdummyÚoutputss           r   Ú__init__zTableGridExtractor.__init__g   s  € õ  # 9™oœoˆŒØ,ˆÔØ,ˆÔàÐØ/Ð0ˆIå!¥# d¤nÑ"5Ô"5°yÑAÔAˆŒ
ð œ
×-Ò-Ñ/Ô/°Ô2ˆÝ˜CœI aœLÑ)Ô)ˆŒÝ˜CœI aœLÑ)Ô)ˆŒõ ”(˜A˜q $¤-°´Ð?ÅrÄzÐRÑRÔRˆØ”*—.’. ¨°Ð'7Ñ8Ô8ˆÝ˜' !œ*Ô*¨1Ô-Ñ.Ô.ˆŒÝ˜' !œ*Ô*¨1Ô-Ñ.Ô.ˆŒˆˆr   Ú	image_bgrr   r
   c                ó  ‡ ‡‡— |j         dd…         \  ŠŠt          |‰ j        ‰ j        f¦  «        }|dd…dd…ddd…f                              t
          j        ¦  «        }|                     ¦   «         |                     ¦   «         }}||k    r||z
  ||z
  z  }nt          j	        |¦  «        }| 
                    ddd¦  «        t
          j        dd…f         }‰ j                             dd|i¦  «        }|d         d         }|d         d         }	t          |‰ j        ¦  «        }
t          |	‰ j        ¦  «        }ˆˆ fd„|
D ¦   «         }ˆˆ fd„|D ¦   «         }t#          t%          |¦  «        t%          |¦  «        ||	¬	¦  «        S )
zý
        Run inference on a single BGR image.

        Parameters
        ----------
        image_bgr : H x W x 3 uint8 BGR image (any size)

        Returns
        -------
        GridPrediction with h_lines and v_lines in input image space.
        Nr   éÿÿÿÿr   r	   r?   c                ó*   •— g | ]}|‰z  ‰j         z  ‘ŒS r   )rK   )r   ÚcÚorig_hrM   s     €€r   ú
<listcomp>z3TableGridExtractor.predict_grid.<locals>.<listcomp>¸   ó$   ø€ ÐEÐEÐE°�1�v‘: ¤Ñ+ÐEÐEÐEr   c                ó*   •— g | ]}|‰z  ‰j         z  ‘ŒS r   )rL   )r   rV   Úorig_wrM   s     €€r   rX   z3TableGridExtractor.predict_grid.<locals>.<listcomp>¹   rY   r   ©Úh_linesÚv_linesÚ	h_heatmapÚ	v_heatmap)rD   r   rF   rE   ÚastyperG   rI   ÚminÚmaxÚ
zeros_likeÚ	transposeÚnewaxisrA   rJ   r.   r5   r6   r
   r$   )rM   rR   Úimg_resizedÚimg_rgbÚmnÚmxrN   rP   r_   r`   Úh_centroids_outÚv_centroids_outr]   r^   rW   r[   s   `             @@r   Úpredict_gridzTableGridExtractor.predict_grid�   s�  øøø€ ð #œ¨¨!¨Ô,‰ˆ�õ #ØØŒ]˜DœMÐ*ñ
ô 
ˆð ˜a˜a˜a    D D b D˜jÔ)×0Ò0µ´Ñ<Ô<ˆØ—+’+‘-”- §¢¡¤ˆBˆØ�Š7ˆ7Ø ‘|¨¨R©Ñ0ˆGˆGå”m GÑ,Ô,ˆGð ×Ò  1 aÑ(Ô(­¬°Q°Q°Q¨Ô7ˆð ”J—N’N 4¨'°3¨Ñ8Ô8ˆØ˜A”J˜q”Mˆ	Ø˜A”J˜q”Mˆ	õ ,¨I°tÔ7JÑKÔKˆÝ+¨I°tÔ7JÑKÔKˆð FÐEÐEÐEÐE°_ÐEÑEÔEˆØEÐEÐEÐEÐE°_ÐEÑEÔEˆåÝ˜7‘O”OÝ˜7‘O”OØØð	
ñ 
ô 
ð 	
r   Úlinesr   ÚcentersÚ
image_sizec                ó˜  ‡‡— | s| S t          | ¦  «        }d}|�r/d}|s�n)dg|z   t          |¦  «        gz   Št          ‰¦  «        dz
  }ˆˆfd„t          |¦  «        D ¦   «         }|d         r|d         dk    rd|d<   d}Œj|d         r|r|                     ¦   «          d}Œ‹g }d}t          t          |¦  «        ¦  «        D ]t}	|rd}Œ||	dz            }
|
rE|	dz   t          |¦  «        k     r/|                     ||	         ||	dz            z   dz  ¦  «         d}d}ŒY|                     ||	         ¦  «         Œut          |¦  «        }|�°/|S )	a†  
        Remove adjacent line pairs that have no bbox center between them,
        and handle empty outer gaps:

        - If the gap between 0 and the first line contains no bbox center,
          the first line is moved to 0.0 (collapsed to the image edge).
        - If the gap between the last line and image_size contains no bbox
          center, the last line is removed entirely.
        - For inner lines: when two adjacent lines share an empty gap between
          them, they are replaced by their midpoint.

        The process repeats until stable.

        Parameters
        ----------
        lines      : sorted list of boundary coordinates
        centers    : list of bbox center coordinates (along same axis)
        image_size : image dimension along this axis (H or W)

        Returns
        -------
        Filtered and possibly merged list of boundary lines (sorted).
        TFç        r	   c                óL   •‡— g | ]Št          ˆˆfd „‰D ¦   «         ¦  «         ‘Œ S )c              3  óV   •K  — | ]#}‰‰         |cxk     o‰‰d z            k     nc V — Œ$dS )r	   Nr   )r   rV   Úedgesr   s     €€r   r   zDTableGridExtractor._filter_empty_lines.<locals>.<listcomp>.<genexpr>ô   sK   øè è € ÐEÐE¸˜˜aœ 1Ð3Ð3Ò3Ð3 u¨Q°©U¤|Ò3Ð3Ð3Ð3ÐEÐEÐEÐEÐEÐEr   )Úany)r   r   ro   ru   s    @€€r   rX   z:TableGridExtractor._filter_empty_lines.<locals>.<listcomp>ó   sM   øø€ ð ð ð àõ ÐEÐEÐEÐEÐE¸WÐEÑEÔEÑEÔEÐEðð ð r   r   rT   ç       @)r$   r   r#   ÚrangeÚpopr!   )rn   ro   rp   ÚcurrentÚchangedÚn_gapsÚ	gap_emptyÚmergedÚ	skip_nextr   Úgap_right_emptyru   s    `         @r   Ú_filter_empty_linesz&TableGridExtractor._filter_empty_linesÆ   s¿  øø€ ð: ð 	ØˆLå˜‘-”-ˆØˆàñ -	%ØˆGØð Ùð �E˜G‘O¥u¨ZÑ'8Ô'8Ð&9Ñ9ˆEÝ˜‘Z”Z !‘^ˆFðð ð ð ð å˜v™œðñ ô ˆIð ˜Œ|ð  ¨¤
¨cÒ 1Ð 1Ø �˜‘
Ø�Øð ˜Œ}ð  ð Ø—’‘”�Ø�Øð #%ˆFØˆIå�3˜w™<œ<Ñ(Ô(ð .ð .�Øð Ø %�IØà"+¨A°©EÔ"2�Ø"ð . q¨1¡u­s°7©|¬|Ò';Ð';à—M’M 7¨1¤:°¸¸A¹´Ñ#>À#Ñ"EÑFÔFÐFØ $�IØ $�G�Gà—M’M '¨!¤*Ñ-Ô-Ð-Ð-å˜V‘n”nˆGð[ ñ -	%ð^ ˆr   Úbboxes_pageÚgridÚcrop_x0Úcrop_y0Úcrop_hÚcrop_wÚspan_thresholdúlist[CellInfo]c                ó  — t          |j        ¦  «        }t          |j        ¦  «        }	dg|z   |gz   }
dg|	z   |gz   }t          t          t	          |
¦  «        ¦  «        ¦  «        }
t          t          t	          |¦  «        ¦  «        ¦  «        }t          |
¦  «        dk     rd|g}
t          |¦  «        dk     rd|g}dd	„}g }t          |¦  «        D �]6\  }}t          |d
         ¦  «        t          |d         ¦  «        t          |d         ¦  «        t          |d         ¦  «        f\  }}}}||z
  }||z
  }||z
  }||z
  }||z   dz  }||z   dz  } |||
¦  «        } |||¦  «        }|}|dz   }|}|dz   }|} | d
k    r@|
|          }!|
|          |
| dz
           z
  }"|"d
k    r|!|z
  |"z  |k    r| dz
  }| dz  } nn| d
k    °@|} | t          |
¦  «        dz
  k     rS|
| dz            }#|
| dz            |
|          z
  }"|"d
k    r||#z
  |"z  |k    r| dz   }| dz  } nn| t          |
¦  «        dz
  k     °S|}$|$d
k    r@||$         }%||$         ||$dz
           z
  }&|&d
k    r|%|z
  |&z  |k    r|$dz
  }|$dz  }$nn|$d
k    °@|}$|$t          |¦  «        dz
  k     rS||$dz            }'||$dz            ||$         z
  }&|&d
k    r||'z
  |&z  |k    r|$dz   }|$dz  }$nn|$t          |¦  «        dz
  k     °S|                     t          |||||||¬¦  «        ¦  «         �Œ8|S )aÀ  
        Assign each bbox to a grid cell (row, col) and compute span.

        Steps
        -----
        1. Convert each bbox from page space to crop space.
        2. Locate the cell that contains the bbox center point.
        3. If the bbox extends beyond the center cell by more than
           span_threshold of that cell's dimension, expand the span.

        Parameters
        ----------
        bboxes_page    : (N, 4) array of [x0, y0, x1, y1] in page space
        grid           : GridPrediction with h_lines / v_lines in crop space
        crop_x0        : left edge of the table crop in page space
        crop_y0        : top  edge of the table crop in page space
        crop_h         : height of the crop image in pixels
        crop_w         : width of the crop image in pixels
        span_threshold : fractional overlap required to expand span (e.g. 0.1)

        Returns
        -------
        List of CellInfo, one per bbox.
        rr   r   Úposr   ru   r   r   rC   c                óÌ   — t          t          |¦  «        dz
  ¦  «        D ]%}||         | cxk    r||dz            k     rn Œ!|c S Œ&t          dt          |¦  «        dz
  ¦  «        S )z4Return 0-based index of the interval containing pos.r	   r   r   )rx   r#   rc   )r‹   ru   r   s      r   Úfind_cell_idxz<TableGridExtractor._post_process_grid.<locals>.find_cell_idxJ  sy   € å�3˜u™:œ:¨™>Ñ*Ô*ð ð �Ø˜”8˜sÐ1Ð1Ò1Ð1 U¨1¨q©5¤\Ò1Ð1Ð1Ð1Ð1Ø�H�H�Hð 2å�q�#˜e™*œ* q™.Ñ)Ô)Ð)r   r   r	   r<   rw   )Úbbox_idxÚ	row_startÚrow_endÚ	col_startÚcol_endÚrowÚcol)r‹   r   ru   r   r   rC   )
r$   r]   r^   ÚlistÚsetr#   r   r   r!   r   )(rM   r‚   rƒ   r„   r…   r†   r‡   rˆ   Ú_h_lines_sortedÚ_v_lines_sortedÚ	row_edgesÚ	col_edgesr�   Úresultsr   ÚbboxÚx0_pÚy0_pÚx1_pÚy1_pÚx0Úy0Úx1Úy1ÚcxÚcyÚbase_rowÚbase_colr�   r�   r‘   r’   ÚrÚcell_topÚcell_heightÚcell_bottomrV   Ú	cell_leftÚ
cell_widthÚ
cell_rights(                                           r   Ú_post_process_gridz%TableGridExtractor._post_process_grid  sñ  € õD ! ¤Ñ.Ô.ˆÝ  ¤Ñ.Ô.ˆà�E˜OÑ+¨v¨hÑ6ˆ	Ø�E˜OÑ+¨v¨hÑ6ˆ	õ �4¥ I¡¤Ñ/Ô/Ñ0Ô0ˆ	Ý�4¥ I¡¤Ñ/Ô/Ñ0Ô0ˆ	åˆy‰>Œ>˜AÒÐØ˜f˜ˆIÝˆy‰>Œ>˜AÒÐØ˜f˜ˆIð	*ð 	*ð 	*ð 	*ð #%ˆå  Ñ-Ô-ð J	ñ J	‰GˆAˆtÝ%*¨4°¬7¡^¤^µU¸4À¼7±^´^Ý',¨T°!¬W¡~¤~µu¸TÀ!¼W±~´~ð&FÑ"ˆD�$˜˜dð ˜‘ˆBØ˜‘ˆBØ˜‘ˆBØ˜‘ˆBà�r‘'˜S‘ˆBØ�r‘'˜S‘ˆBð %�} R¨Ñ3Ô3ˆHØ$�} R¨Ñ3Ô3ˆHà ˆIØ  1™ˆGØ ˆIØ  1™ˆGð ˆAØ�a’%�%Ø'¨œl�Ø'¨œl¨Y°q¸1±uÔ-=Ñ=�Ø ’?�?¨°2©¸Ñ'DÀ~Ò'UÐ'UØ ! A¡�IØ˜‘F�A�Aàð �a’%�%ð ˆAØ•c˜)‘n”n qÑ(Ò(Ð(Ø'¨¨A©Ô.�Ø'¨¨A©Ô.°¸1´Ñ=�Ø ’?�?¨¨[Ñ(8¸KÑ'GÈ.Ò'XÐ'XØ !™e�GØ˜‘F�A�Aàð •c˜)‘n”n qÑ(Ò(Ð(ð ˆAØ�a’%�%Ø& qœ\�	Ø& qœ\¨I°a¸!±eÔ,<Ñ<�
Ø ’>�> y°2¡~¸Ñ&CÀnÒ&TÐ&TØ ! A¡�IØ˜‘F�A�Aàð �a’%�%ð ˆAØ•c˜)‘n”n qÑ(Ò(Ð(Ø& q¨1¡uÔ-�
Ø& q¨1¡uÔ-°	¸!´Ñ<�
Ø ’>�> r¨J¡¸*Ñ&DÀ~Ò&UÐ&UØ !™e�GØ˜‘F�A�Aàð •c˜)‘n”n qÑ(Ò(Ð(ð �NŠN�8ØØ%Ø#Ø%Ø#Ø$Ø$ðñ ô ñ ô ð ñ ð ˆr   çš™™™™™¹?ÚbboxesúOptional[np.ndarray]Útextsú%tuple[GridPrediction, list[CellInfo]]c           	     óÊ  — |                       |¦  «        }|�t          |¦  «        dk    r|g fS t          j        |t          j        ¬¦  «        }t          |j        d         ¦  «        }t          |j        d         ¦  «        }t          d„ |D ¦   «         ¦  «        }	t          d„ |D ¦   «         ¦  «        }
|                      |j	        |
|¦  «        }|                      |j
        |	|¦  «        }t          |||j        |j        ¬¦  «        }|                      ||dd|||¬	¦  «        }|�9|D ]6}d|j        cxk    rt          |¦  «        k     rn Œ$||j                 |_        Œ7||fS )
a¢  
        Predict grid boundaries and optionally assign bboxes to grid cells.

        Parameters
        ----------
        image_bgr      : cropped table BGR image (any size)
        bboxes         : (N, 4) array of [x0, y0, x1, y1] in crop space.
                         If None, only grid prediction is performed.
        texts          : list of text strings aligned with bboxes.
                         If provided, each CellInfo.text is populated.
        span_threshold : fractional overlap to trigger span expansion (default 0.1)

        Returns
        -------
        (GridPrediction, list[CellInfo])
        CellInfo list is empty when bboxes is None.
        Nr   r=   r	   c              3  ór   K  — | ]2}t          |d          ¦  «        t          |d         ¦  «        z   dz  V — Œ3dS )r   r   rw   N©r   ©r   Úbs     r   r   z-TableGridExtractor.predict.<locals>.<genexpr>Ã  ó@   è è € ÐOÐO¸q�%  !¤™+œ+­¨a°¬d©¬Ñ3°sÑ:ÐOÐOÐOÐOÐOÐOr   c              3  ór   K  — | ]2}t          |d          ¦  «        t          |d         ¦  «        z   dz  V — Œ3dS )r	   r<   rw   Nr¸   r¹   s     r   r   z-TableGridExtractor.predict.<locals>.<genexpr>Ä  r»   r   r\   rr   )r‚   rƒ   r„   r…   r†   r‡   rˆ   )rm   r#   rG   ÚasarrayrI   r   rD   r$   r�   r]   r^   r
   r_   r`   r°   rŽ   Útext)rM   rR   r²   r´   rˆ   rƒ   Ú
bboxes_arrr†   r‡   Úcx_listÚcy_listÚ
filtered_hÚ
filtered_vÚcellsÚcells                  r   ÚpredictzTableGridExtractor.predict¡  s�  € ð0 × Ò  Ñ+Ô+ˆàˆ>�S ™[œ[¨AÒ-Ð-Ø˜�8ˆOå”Z ­b¬jÐ9Ñ9Ô9ˆ
Ý�y” qÔ)Ñ*Ô*ˆÝ�y” qÔ)Ñ*Ô*ˆõ ÐOÐOÀJÐOÑOÔOÑOÔOˆÝÐOÐOÀJÐOÑOÔOÑOÔOˆð ×-Ò-¨d¬l¸GÀVÑLÔLˆ
Ø×-Ò-¨d¬l¸GÀVÑLÔLˆ
åØØØ”nØ”nð	
ñ 
ô 
ˆð ×'Ò'Ø"ØØØØØØ)ð (ñ 
ô 
ˆð ÐØð 5ð 5�Ø˜œÐ2Ð2Ò2Ð2­¨E©
¬
Ò2Ð2Ð2Ð2Ð2Ø % d¤mÔ 4�D”Iøà�Uˆ{Ðr   éè  ÚpredÚwindow_titler@   Úmax_dimrC   c                óô  — ddl }|j        dd…         \  }}|                     ¦   «         }|j        D ]6}	t	          t          |	¦  «        ¦  «        }
 |j        |d|
f||
fdd¦  «         Œ7|j        D ]6}t	          t          |¦  «        ¦  «        } |j        ||df||fdd¦  «         Œ7 |j        |j	        dd…t          j        f         ||f|j        ¬¦  «        } |j        |dz                       dd¦  «                             t          j        ¦  «        |j        ¦  «        } |j        |d	| j        d
›�d|j        ddd¦  «          |j        |j        t          j        dd…f         ||f|j        ¬¦  «        } |j        |dz                       dd¦  «                             t          j        ¦  «        |j        ¦  «        } |j        |d| j        d
›�d|j        ddd¦  «         t          j        ||dft          j        ¬¦  «        }dt1          |j        ¦  «        › �dt1          |j        ¦  «        › �g}t3          |¦  «        D ].\  }} |j        ||dd|dz  z   f|j        ddd|j        ¦  «         Œ/t          j        ||gd¬¦  «        }t          j        ||gd¬¦  «        }t          j        ||gd¬¦  «        }|j        dd…         \  }}||k    s||k    ri|t9          ||¦  «        z  } |j        |t9          dt	          ||z  ¦  «        ¦  «        t9          dt	          ||z  ¦  «        ¦  «        f|j        ¬¦  «        } |j        ||¦  «          |j        d¦  «          |j         |¦  «         |S )a¼  
        Draw predicted grid lines on the image and display via OpenCV.

        Layout (2x2 grid, all panels same size)
        ----------------------------------------
        (1,1) input image with predicted grid lines overlaid
        (1,2) h_heatmap tiled to 2D  (rows = H axis)
        (2,1) v_heatmap tiled to 2D  (cols = W axis)
        (2,2) summary info panel

        Parameters
        ----------
        image_bgr    : original BGR image
        pred         : GridPrediction from predict()
        window_title : OpenCV window title
        max_dim      : maximum panel dimension before downscaling

        Returns
        -------
        The composed BGR visualization array.
        r   Nr   )r   éÿ   r   r	   )rÌ   r   r   )ÚinterpolationrÌ   zh_thr=z.2f)é   é   çš™™™™™Ù?)rÌ   rÌ   rÌ   zv_thr=r<   r=   z
h_lines : z
v_lines : é
   é   é   gš™™™™™á?)éÈ   rÔ   rÔ   )Úaxis)!Úcv2rD   Úcopyr]   rC   ÚroundÚliner^   Úresizer_   rG   rf   ÚINTER_LINEARÚapplyColorMapÚclipra   Úuint8ÚCOLORMAP_JETÚputTextr5   ÚFONT_HERSHEY_SIMPLEXr`   r6   rH   r#   r   ÚLINE_AAÚconcatenaterc   Ú
INTER_AREAÚimshowÚwaitKeyÚdestroyWindow)rM   rR   rÈ   rÉ   rÊ   rÖ   Úimg_hÚimg_wÚoverlayÚyÚy_pxÚxÚx_pxÚh_heatmap_resizedÚh_panelÚv_heatmap_resizedÚv_panelÚ
info_panelÚsummaryr   ÚtxtÚtop_rowÚbot_rowÚcomposedÚchÚcwÚscales                              r   Ú	visualizezTableGridExtractor.visualizeè  s÷  € ð8 	ˆ
ˆ
ˆ
à ” r¨ rÔ*‰ˆˆuð —.’.Ñ"Ô"ˆØ”ð 	Hð 	HˆAÝ•u˜Q‘x”x‘=”=ˆDØˆCŒH�W˜q $˜i¨%°¨¸ÀQÑGÔGÐGÐGØ”ð 	Hð 	HˆAÝ•u˜Q‘x”x‘=”=ˆDØˆCŒH�W˜t Q˜i¨$°¨¸ÀQÑGÔGÐGÐGð '˜CœJØŒN˜1˜1˜1�bœj˜=Ô)¨E°5¨>ØÔ*ð
ñ 
ô 
Ðð $�#Ô#Ø Ñ$×*Ò*¨1¨cÑ2Ô2×9Ò9½"¼(ÑCÔCÀSÔEUñ
ô 
ˆð 	ˆŒ�GÐ? dÔ&9Ð?Ð?Ð?Ø˜SÔ5°s¸OÈQñ	Pô 	Pð 	Pð '˜CœJØŒN�2œ: q q q˜=Ô)¨E°5¨>ØÔ*ð
ñ 
ô 
Ðð $�#Ô#Ø Ñ$×*Ò*¨1¨cÑ2Ô2×9Ò9½"¼(ÑCÔCÀSÔEUñ
ô 
ˆð 	ˆŒ�GÐ? dÔ&9Ð?Ð?Ð?Ø˜SÔ5°s¸OÈQñ	Pô 	Pð 	Põ ”X˜u e¨QÐ/µr´xÐ@Ñ@Ô@ˆ
à,�˜Tœ\Ñ*Ô*Ð,Ð,Ø,�˜Tœ\Ñ*Ô*Ð,Ð,ð
ˆõ   Ñ(Ô(ð 	%ð 	%‰FˆAˆsØˆCŒK˜
 C¨"¨b°1°r±6©kÐ):ØÔ0°$¸ÈØœñ%ô %ð %ð %õ
 ”> 7¨GÐ"4¸1Ð=Ñ=Ô=ˆÝ”> 7¨JÐ"7ÀÐCÑCÔCˆÝ”> 7¨GÐ"4¸1Ð=Ñ=Ô=ˆð ”   Ô#‰ˆˆBØ�Š<ˆ<˜2 š<˜<Ø¥ R¨¡¤Ñ,ˆEØ!�s”zØÝ�Q�˜B ™J™œÑ(Ô(­#¨aµ°R¸%±Z±´Ñ*AÔ*AÐBØ!œnðñ ô ˆHð 	ˆŒ
�< Ñ*Ô*Ð*ØˆŒ�A‰ŒˆØˆÔ˜,Ñ'Ô'Ð'àˆr   )r1   r2   N)
r3   r4   r5   r   r6   r   r7   r8   r   r9   )rR   r   r   r
   )rn   r   ro   r   rp   r   r   r   )r‚   r   rƒ   r
   r„   r   r…   r   r†   r   r‡   r   rˆ   r   r   r‰   )NNr±   )
rR   r   r²   r³   r´   r8   rˆ   r   r   rµ   )r0   rÇ   )
rR   r   rÈ   r
   rÉ   r@   rÊ   rC   r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__rQ   rm   Ústaticmethodr�   r°   rÆ   rü   r   r   r   r0   r0   \   sè   € € € € € ðð ð !%Ø $Ø)-ð"/ð "/ð "/ð "/ð "/ðP1
ð 1
ð 1
ð 1
ðn ðQð Qð Qñ „\ðQðfEð Eð Eð EðT (,Ø%)Ø #ðAð Að Að Að AðV 1Øð]ð ]ð ]ð ]ð ]ð ]ð ]r   r0   Ú__main__z4Run TableGridExtractor on all images in a directory.)Údescriptionr3   z!Path to the exported .onnx model.)ÚhelpÚ	image_dirz"Directory containing input images.z--hmap_thresholdg333333Ó?z6Activation threshold for h_heatmap CCL (default: 0.3).)ÚtypeÚdefaultr  z--vmap_thresholdrÐ   z6Activation threshold for v_heatmap CCL (default: 0.4).z--extensionsÚ*)ÚpngÚjpgÚjpegÚbmpÚtifÚtiffzImage file extensions to scan.)Únargsr  r  )r3   Úhmap_thresholdÚvmap_thresholdz
list[Path]Ú	img_pathsz*.zNo images found in: zFound z$ image(s). Press any key to advance.zCannot read: z
  h_lines=z
  v_lines=)r   r   r   r   r   r   )7r   Ú
__future__r   Úpathlibr   Útypingr   ÚnumpyrG   ÚonnxruntimeÚortÚcommon_utilr   r   Útable_grid_typesr
   r   r   r.   r0   rý   ÚargparserÖ   ÚArgumentParserÚparserÚadd_argumentr   Ú
parse_argsÚargsr3   r  r  Ú	extractorr  r  Ú__annotations__Ú
extensionsÚextÚextendr$   ÚglobÚupperr–   Úprintr#   Úimg_pathÚimreadr@   Úimg_bgrÚnamerm   rÈ   r]   r^   rü   r   r   r   ú<module>r-     s  ððð ð ð  #Ð "Ð "Ð "Ð "Ð "à Ð Ð Ð Ð Ð Ø Ð Ð Ð Ð Ð à Ð Ð Ð Ø Ð Ð Ð à /Ð /Ð /Ð /Ð /Ð /Ð /Ð /Ø 6Ð 6Ð 6Ð 6Ð 6Ð 6Ð 6Ð 6Ø %Ð %Ð %Ð %Ð %Ð %ð3ð 3ð 3ð 3ðvið ið ið ið iñ iô ið ið` ˆzÒÑØ€O€O€OØ€J€J€Jà$ˆXÔ$ØJðñ ô €Fð ×Ò˜Ð+NÐÑOÔOÐOØ
×Ò˜Ð+OÐÑPÔPÐPØ
×ÒØ °ØEð ñ ô ð ð ×ÒØ °ØEð ñ ô ð ð ×ÒØ˜cØ<Ð<Ð<Ø-ð ñ ô ð ð
 ×ÒÑÔ€Dà"Ð"Ø”.ØÔ*ØÔ*ðñ ô €Ið ��T”^Ñ$Ô$€IØ€IÐÐÐÑØŒð Eð EˆØ×Ò˜˜ 	§¢¨z°C¨z¨zÑ :Ô :Ñ;Ô;Ñ<Ô<Ð<Ø×Ò˜˜ 	§¢Ð/A°C·I²I±K´KÐ/AÐ/AÑ BÔ BÑCÔCÑDÔDÐDÐDØ��s�s˜9‘~”~Ñ&Ô&€Iàð MØˆÐ0 YÐ0Ð0Ñ1Ô1Ð1Ð1àˆÐK�s�s˜9‘~”~ÐKÐKÐKÑLÔLÐLàð +ð +ˆØ�#”*˜S˜S ™]œ]Ñ+Ô+ˆØˆ?ØˆEÐ1 (¤-Ð1Ð1Ñ2Ô2Ð2Øà×%Ò% gÑ.Ô.ˆØˆØŒ}ð Hð HØ�s˜4œ<Ñ(Ô(ðHð HØ47°C¸¼Ñ4EÔ4EðHð Hñ	
ô 	
ð 	
ð 	×Ò˜G TÑ*Ô*Ð*Ð*ðk ÐðT+ð +r   