
    ^j->                       U d Z ddlmZ ddlZddlZddlmZ ddlmZ ddl	Z
ddlmZ ddlmZ ddlmZ dd	lmZ  e       Z eed
e      j,                  Zg dZded<   g dZded<   ddZddZddZ	 d	 	 	 	 	 	 	 ddZ	 d	 	 	 	 	 	 	 ddZy)a`  TFLite inference helpers for RF-DETR exported models.

These functions handle interpreter creation, image preprocessing, and decoding of detection and segmentation-mask
outputs without requiring PyTorch or the RF-DETR training stack: only ``tflite-runtime`` (or ``tensorflow``), ``numpy``,
``supervision``, and ``Pillow`` are needed at inference time.
    )annotationsN)Path)Any)NDArray)Image)
Detections)
get_logger
Resampling)g
ףp=
?gv/?gCl?zlist[float]_IMAGENET_MEAN)gZd;O?gy&1?g?_IMAGENET_STDc           	        d}g }dD ]H  \  }}t        j                  t              5  t        t	        j
                  |      |      }	 ddd        n |'dj                  d |D              }t        d| d       |t        |       	      }|j                          |j                         }|j                         }t        j                  d
|d   d   |d   d   j                         |D ],  }	t        j                  d|	d   |	j!                  dd             . |S # 1 sw Y   nxY w|j                  |j                  d      d          G)aw  Load a TFLite model, allocate tensors, and log I/O shapes.

    Tries ``tflite_runtime`` first (lightweight; preferred on edge devices), then falls back to ``tensorflow.lite``
    (pre-installed on Colab / full TF environments).

    Args:
        model_path: Path to the ``.tflite`` model file.

    Returns:
        An allocated TFLite interpreter ready for inference.
    N))zai_edge_litert.interpreterInterpreter)ztflite_runtime.interpreterr   )ztensorflow.liter   .r   z, c              3  (   K   | ]
  }d | d   yw)'N ).0ps     j/var/www/ramen.bs-engineer-server.com/venv/lib/python3.12/site-packages/rfdetr/export/_tflite/inference.py	<genexpr>z&_create_interpreter.<locals>.<genexpr><   s     8A1#Qx8s   zVTFLite inference requires 'ai_edge_litert', 'tflite-runtime', or 'tensorflow' (tried: zN). Install one: `pip install ai_edge_litert`  OR  `pip install tflite-runtime`)
model_pathzInput  : %s  %sshapedtypezOutput : %s  name=%sname	<unnamed>)
contextlibsuppressImportErrorgetattr	importlibimport_moduleappendsplitjoinstrallocate_tensorsget_input_detailsget_output_detailsloggerdebug__name__get)
r   _Interpreter_tried_pkg_attr
_tried_strinterpinp_detout_detods
             r   _create_interpreterr6   $   sX    LF *e
   - 	"9#:#:4#@%HL	 	* YY888
!l #ZZ
 	
 S_5F
&&(G'')G
LL"GAJw$7G9L9U9UV W+R["&&:UVWM'	 	 	djjoa()s   !DD&	c                   | j                   d   | j                   d   }}t        j                  |t        j                        dz   ||z  z  dz
  }t        j                  |t        j                        dz   ||z  z  dz
  }t        j                  |d|dz
        }t        j                  |d|dz
        }t        j
                  |      j                  t        j                        }t        j
                  |      j                  t        j                        }t        j                  |dz   |dz
        }	t        j                  |dz   |dz
        }
||z
  dddf   }||z
  dddf   }| d|dddf   |dddf   f   }| d|dddf   |
dddf   f   }| d|	dddf   |dddf   f   }| d|	dddf   |
dddf   f   }d|z
  d|z
  |z  ||z  z   z  |d|z
  |z  ||z  z   z  z   }t        j                  |t        j                        S )	aL  Numpy bilinear resize matching ``F.interpolate(mode="bilinear", align_corners=False)``.

    Half-pixel center convention. Used by ``_decode_masks`` only when ``torch`` is not importable.

    Args:
        src: Source array of shape ``(K, src_h, src_w)``.
        out_h: Target height in pixels.
        out_w: Target width in pixels.

    Returns:
        Float32 array of shape ``(K, out_h, out_w)``.

    Note:
        Replaces ``PIL.Image.resize(BILINEAR)``, which uses a corner-aligned half-pixel convention and
        produced border-pixel discrepancies vs ``F.interpolate``.
    r   g      ?           N.)
r   nparangefloat32clipfloorastypeint64minimumasarray)srcout_hout_wsrc_hsrc_wsrc_ysrc_xy0x0y1x1dydxabcdouts                     r   _bilinear_resize_half_pixelrX   M   s   " 99R=#))B-5EYYuBJJ/#5%%-H3NEYYuBJJ/#5%%-H3NEGGE3	*EGGE3	*E	%			)B	%			)B	BFEAI	&B	BFEAI	&B
"*ag	B
"*dAg	BCAtGbqk)*ACAtGbqk)*ACAtGbqk)*ACAtGbqk)*Ar6q2vlR!V+
,ra"f\BF5J/K
KC::c,,    c                   | j                   dk7  rt        d| j                   d      |\  }}| j                  d   dk(  r(t        j                  d||ft        j
                        S 	 ddl}ddlmc m	} |j                         5  |j                  | j                  t        j                              j                  d      }|j                  |||fdd	      }ddd       t        j                   j#                  d      j%                         t        j                        }|d
kD  S # 1 sw Y   PxY w# t&        $ r1 t)        | j                  t        j                        ||      }Y |d
kD  S w xY w)a  Upsample mask logits to image size and threshold at zero.

    Matches ``PostProcess.forward``: bilinear upsample with ``align_corners=False`` followed by ``> 0``.
    Uses ``torch.nn.functional.interpolate`` when torch is importable for bit-exact parity, and falls
    back to the pure-NumPy ``_bilinear_resize_half_pixel`` otherwise.

    Args:
        mask_logits: Raw mask logits of shape ``(K, Hm, Wm)``.
        out_size: Target ``(width, height)`` in pixels.

    Returns:
        Boolean mask array of shape ``(K, height, width)``.

    Raises:
        ValueError: If *mask_logits* is not rank-3.

    Note:
        ``out_size`` follows PIL convention ``(width, height)``; the returned array uses
        NumPy/PyTorch convention ``(K, height, width)``.
       z4_decode_masks expects rank-3 (K, Hm, Wm); got shape za. This usually means the rank-4 mask-output heuristic in _run_inference matched the wrong tensor.r   r:   NbilinearF)sizemodealign_cornersr;   )ndim
ValueErrorr   r=   zerosbool_torchtorch.nn.functionalnn
functionalno_grad
from_numpyrB   r?   	unsqueezeinterpolaterE   squeezenumpyr   rX   )mask_logitsout_sizewidthheightrd   _Ftresizeds           r   _decode_masksru   q   sW   * 1B;CTCTBU Vn n
 	
 ME6q xxFE*"((;;	]((]]_ 	^  !3!3BJJ!?@JJ1MAqZW\]A	^ (*zz!))A,2D2D2Fbjj'Y S=	^ 	^  ]-k.@.@.LfV[\S=]s,   )D6 AD*A
D6 *D3/D6 63E0/E0c                $   |\  }}|dk(  rdnd}| j                  |      }d}	 ddl}ddlmc m}	 |j                         5  |	j                  |      }
|	j                  |
t        |            }
t        |      D cg c]  }t        |dz      }}t        |      D cg c]  }t        |dz      }}|	j                  |
||      }
ddd       t        j                  
j                  d      j!                         j#                         t        j$                        }|7t        j                  |j)                  dddd      t        j$                        S t        j*                  |j                  ||ft,              t        j$                        d	z  }|j.                  dk(  r|ddddt        j0                  f   }t        j*                  t        |      D cg c]  }t        |dz      c}t        j$                        }t        j*                  t        |      D cg c]  }t        |dz      c}t        j$                        }||z
  |z  t        j0                     S c c}w c c}w # 1 sw Y   xY w# t&        $ r Y hw xY wc c}w c c}w )
a!  Resize and ImageNet-normalise an image to match ``RFDETR.predict()``.

    Uses ``torchvision.transforms.functional`` when importable for bit-exact parity, and falls back
    to ``PIL.Image.resize`` with BILINEAR for torch-free deployments.

    Args:
        pil_img: Source PIL image at native resolution.
        hw: Target ``(height, width)`` from the interpreter's input shape.
        channels: Channel count (3 for RGB, 1 for grayscale).

    Returns:
        Float32 array of shape ``(1, height, width, channels)`` in NHWC.

    Note:
        The PIL fallback uses BILINEAR resize, which does not perfectly match PyTorch's ``F.resize``
        (different coordinate conventions). For bit-exact parity with ``RFDETR.predict()``, ensure
        ``torch`` and ``torchvision`` are importable.
    r<   LRGBNr   r[   r:      g     o@)convertrd   !torchvision.transforms.functional
transformsrg   rh   	to_tensorresizelistranger   r   	normalizer=   rE   rj   cpurm   r?   r   	transposearray_PIL_BILINEARr`   newaxis)pil_imghwchannelsrq   rp   pil_modepil_rgb
nchw_floatrd   rr   rs   i	mean_liststd_listarrmeanstds                    r   _preprocess_imager      s
   . MFE!msHooh'G-1J66]]_ 	5W%A		!T"X&A8=hH1A.HIH6;HoFa!e,FHFQ	84A	5 ZZA 2 2 4 : : <BJJO
 zz*..q!Q:"**MM ((7>>5&/=A
TW\
\C
xx1}!Q

"#88E(ODq^AE*DBJJWD
((%/BQM!a%(B"**
UC4Z3

++' IF		5 	5   EBsT   I8  :I+:I!I+I&/I+AI8 JJ!
I++I50I8 8	JJc           
        | j                         }| j                         }|d   d   \  }}}}t        j                  }	|d   d   }
|
|	k7  rt	        d|
j
                   d      t        j                  |      }t        |t        |      t        |      ft        |            }| j                  |d   d   |       | j                          |D cg c]  }t        |j                  dd             }}t        d	 t        |      D        d
      }t        d t        |      D        d
      }||t         j#                  d|       t        |      D cg c]%  \  }}t%        |d         dk(  s|d   d   dk(  s$|' }}}t        |      D cg c]%  \  }}t%        |d         dk(  s|d   d   dk7  s$|' }}}t%        |      dk(  rt%        |      dk(  r|d   }|d   }nQt%        |      dk(  rt         j#                  d       d}d}n)|D cg c]  }t'        |d          }}t	        d|       | j)                  ||   d         d   }t+        |j-                               dkD  st+        |j/                               dk  rqt         j#                  dt+        |j-                               | j)                  ||   d         j0                  d   dz
         ||}}| j)                  ||   d         d   }| j)                  ||   d         dd
d
d
df   }t         j#                  d|j0                  t+        |j/                               t+        |j-                               t+        |j3                                      t        j4                  d|j6                        }||t        j8                  |j;                  dd             z   z  }|j-                  d      }|j=                  d      }t         j#                  dt+        |j/                               t+        |j-                               |t        ||kD  j?                                      ||kD  }||   j@                  \  }}}}|jB                  \  } }!t        jD                  ||dz  z
  ||dz  z
  ||dz  z   ||dz  z   gd      }"|"t        jF                  | |!| |!gt        j                        z  }"t        d t        |      D        d
      }#|#pt        |      D cg c]  \  }}t%        |d         dk(  s| }$}}t%        |$      dk(  r|$d   }#n-t%        |$      dk\  rt         jI                  dt%        |$             d
}%|#;|jK                         r+| j)                  ||#   d         d   }&tM        |&|   | |!f      }%tO        |"||   ||   jQ                  t              |%      }'|'|fS c c}w c c}}w c c}}w c c}w c c}}w ) a  Preprocess one image, run TFLite inference, and decode detections.

    Reads input shape from the interpreter (NHWC ``float32``), resizes and normalises the image with ImageNet
    statistics, invokes the model, then decodes the ``dets`` / ``labels`` output tensors into a
    :class:`supervision.Detections` object with pixel-space ``xyxy`` boxes. For segmentation exports the ``masks``
    output is also decoded into ``Detections.mask``.

    Args:
        interp: Allocated TFLite interpreter returned by ``_create_interpreter``.
        image_path: Path to the input image (any format supported by Pillow).
        threshold: Confidence threshold; detections below this are discarded.

    Returns:
        A tuple of ``(detections, pil_img)`` where ``detections`` contains pixel-space ``xyxy`` boxes (and ``mask`` for
        segmentation models) and ``pil_img`` is the original PIL image at its original resolution.
    r   r   r   zF_run_inference only supports float32 input tensors, but model expects zV. Export the model with float32 quantization or implement input quantization manually.indexr   r   c              3  b   K   | ]'  \  }}d t        |j                  dd            v s$| ) yw)detsr    Nr%   r,   r   r   r5   s      r   r   z!_run_inference.<locals>.<genexpr>   s-     ]EAr6SPVXZI[E\;\a]   %//Nc              3  b   K   | ]'  \  }}d t        |j                  dd            v s$| ) yw)labelsr   r   Nr   r   s      r   r   z!_run_inference.<locals>.<genexpr>   s-     `UQHBFFSY[]L^H_<_q`r   zXName-based output matching failed (available: %s). Falling back to shape-based matching.r[   r9      r<   ry   zKShape-based matching ambiguous. Using positional order (0=boxes, 1=logits).zShape-based TFLite output matching failed. Expected exactly one rank-3 tensor with last dim == 4 (boxes) and one rank-3 tensor with last dim != 4 (logits). Available output shapes: g       @g       u   Box tensor max=%.2f exceeds [0,1] — swapping boxes/logits assignment (num_classes==%d likely caused ambiguous positional fallback).z2Logits stats: shape=%s min=%.3f max=%.3f mean=%.3fr:   iX   )axisuG   Scores stats: min=%.3f max=%.3f — detections above threshold %.2f: %dc              3  b   K   | ]'  \  }}d t        |j                  dd            v s$| ) yw)masksr   r   Nr   r   s      r   r   z!_run_inference.<locals>.<genexpr>O  s-     ]51b'SPVXZI[E\:\Q]r   zyAmbiguous rank-4 outputs (%d candidates); skipping mask decode. Name your mask output to contain 'masks' to disambiguate.)xyxy
confidenceclass_idmask))r'   r(   r=   r?   ra   r+   PILImageopenr   int
set_tensorinvoker%   r,   next	enumerater)   r*   lenr   
get_tensorfloatmaxminr   r   rE   r   expr@   argmaxsumTr]   stackr   warninganyru   r   rB   )(r2   
image_path	thresholdr3   r4   _rq   rp   r   expected_dtypeactual_dtyper   
inp_tensorr5   available_output_names	boxes_idx
logits_idxr   shape_boxes_candidatesshape_logits_candidatesavailable_shapes	boxes_cwhlogitsone
scores_allscoresclskeepcxcybwbhowohr   mask_idxrank4_candidatesr   	raw_masks
detectionss(                                           r   _run_inferencer      s   * &&(G'')G!(G!4AvuhZZN1:g&L~%TUaUjUjTk lc c
 	

 mmJ'G"7S[#e*,Es8}UJ
gaj):6
MMO JQQ2c"&&"=>QQ]Yw%7]_cdI`i&8`bfgJJ. 	f"	
 2;71C!v2s2g;GW[\G\acdkalmoaptuau!!v!v2;G2D"wBBwKHX\]H]bdelbmnpbquvbv1"w"w%&!+4K0LPQ0Q.q1I03J\Q LLfgIJ<CDbR[ 1DD,,<+=? 
 !!')"4W"=>qAI Y]]_#uY]]_'='DM)--/"gj1':;AA"EI		
 !+I:	%%gi&8&AB1E	 wz27;<Q3B3YGF LL<fjjlfjjlfkkm **Qfll
+Cbfffkk#r&:%:;;<J^^^$F




$C
LLQfjjlfjjlVi$$&' IDt_&&NBB\\FB88R"q&["rAv+rBF{BaKHqQDBHHb"b"%RZZ88D ]Ig$6]_cdH+4W+=W%!RR[AQUVAVAWW A%'*H!"a'NNL$%
 E
%%gh&7&@A!D	ioBx8&,TIYIYZ]I^ejkJwE R "w"w  Et Xs<   "WW.W:WW)W5WW#W(W()r   
str | Pathreturnr   )rF   NDArray[np.float32]rG   r   rH   r   r   r   )rn   zNDArray[Any]ro   tuple[int, int]r   zNDArray[np.bool_])r[   )r   zPILImage.Imager   r   r   r   r   r   )g333333?)r2   r   r   r   r   r   r   z!tuple[Detections, PILImage.Image]) __doc__
__future__r   r   r    pathlibr   typingr   rm   r=   numpy.typingr   PILr   r   supervisionr   rfdetr.utilities.loggerr	   r)   r   BILINEARr   r   __annotations__r   r6   rX   ru   r   r   r   rY   r   <module>r      s    #        ! " .	 ,9BB3 32{ 2&R!-H'Z 7,7,7, 7, 	7,z KKK K '	KrY   