
    +j                        % S r SSKrSSKJr  SSKJrJr  SSKrSSK	r	SSK
Js  Jr  SSKJr  SSK	JrJr  Sr\\S4   \S	'   S
r\\S4   \S'   SrSrSrSrSrSrSrSrSrSrSr Sr!Sr"\"\"-  r#Sr$Sr%Sr&Sr'Sr(Sr)Sr*Sr+S\S\S\S\4S jr,/ SQr- " S  S!\R\                  5      r/ " S" S#\R\                  5      r0 " S$ S%\R\                  5      r1/ S&Qr2S'r3S(r4S)S)/S*S*/S+//r5S,\S-\S.\S\4S/ jr6 " S0 S1\R\                  5      r7\" SS29S\Rp                  4S3 j5       r9\ 4S4\Rp                  S5\Rp                  S6\:S\Rp                  4S7 jjr;/ S8Qr< " S9 S:\R\                  5      r= " S; S<\R\                  5      r>S=r?S>r@S?rAS@rBSArCSBrDSCrESDrF " SE SF\R\                  5      rG " SG SH\R\                  5      rH\" SS29S\Rp                  4SI j5       rI\ 4S4\Rp                  S5\Rp                  S6\:S\Rp                  4SJ jjrJScSK\Rp                  SL\:S\Rp                  4SM jjrKSN\Rp                  SO\SP\S\\:\:\:\:\:4   4SQ jrLSR\SS\ST\SU\S\4
SV jrM\&4SR\SW\:SX\:SY\:SZ\:S[\:S\\S\4S] jjrN\4S^\S_\S\\\:\:\:4   4S` jjrO " Sa Sb\R\                  5      rPg)du   Pure-PyTorch port of MediaPipe's face_landmarker_v2_with_blendshapes.task:
BlazeFace detector → FaceMesh v2 → ARKit-52 blendshapes.    N)	lru_cache)ListTuple)expit)Tensornn)r                     
               !   %   '   (   .   4   5   6   7   :   =   ?   A   B   C   F   N   P   Q   R   T   W   X   [   ]   _   g   i   k   m                                                                                                            i  i  i  i  i  i  i  i  i  i   i#  i%  i'  i(  i)  i,  i4  i6  i7  i8  i:  i=  i>  iA  iC  iD  iL  iN  iP  iR  id  ii  ij  im  iu  iv  iw  iy  iz  i{  i|  i}  i~    i  i  i  i  i    i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  ._BS_INPUT_INDICES)4_neutralbrowDownLeftbrowDownRightbrowInnerUpbrowOuterUpLeftbrowOuterUpRight	cheekPuffcheekSquintLeftcheekSquintRighteyeBlinkLefteyeBlinkRighteyeLookDownLefteyeLookDownRighteyeLookInLefteyeLookInRighteyeLookOutLefteyeLookOutRighteyeLookUpLefteyeLookUpRighteyeSquintLefteyeSquintRighteyeWideLefteyeWideRight
jawForwardjawLeftjawOpenjawRight
mouthClosemouthDimpleLeftmouthDimpleRightmouthFrownLeftmouthFrownRightmouthFunnel	mouthLeftmouthLowerDownLeftmouthLowerDownRightmouthPressLeftmouthPressRightmouthPucker
mouthRightmouthRollLowermouthRollUppermouthShrugLowermouthShrugUppermouthSmileLeftmouthSmileRightmouthStretchLeftmouthStretchRightmouthUpperUpLeftmouthUpperUpRightnoseSneerLeftnoseSneerRightBLENDSHAPE_NAMESr
      )r      r   r         ?)      ?r   g      `@g      Y@   0   g      h@r	   g      ?        xkernelstridereturnc           	      ,   U R                   S   U R                   S   pC[        X2-   S-
  U-  S-
  U-  U-   U-
  S5      n[        XB-   S-
  U-  S-
  U-  U-   U-
  S5      nUS:X  a  US:X  a  U $ [        R                  " XS-  XfS-  -
  US-  XUS-  -
  45      $ )zRTF SAME pad (asymmetric on stride-2; PyTorch's symmetric pad undershoots by 1 px).r	   r      )shapemaxFpad)r   r   r   HWpad_hpad_ws          F/home/wildlama/comfy/ComfyUI/comfy_extras/mediapipe/face_landmarker.py_tf_same_padr   O   s    772;q!*q.V+a/69FBQFJE!*q.V+a/69FBQFJEzeqj55aZ!!3UaZRSASTUU    ))   r   r	   )r      r	   )r       r   )r   $   r	   )r   *   r	   )r   r   r   )r   8   r	   )r   @   r	   )r   H   r	   )r   r%   r	   )r%   r*   r	   )r*   `   r   r   r   r	   r   r   r   c                   R   ^  \ rS rSrSrSS\S\S\4U 4S jjjrS\S\4S	 jrS
r	U =r
$ )BlazeFaceBlockc   zUDW 3x3 + PW + residual. Residual max-pools on stride>1, channel-pads on out_ch>in_ch.in_chout_chr   c                    > [         TU ]  5         Ub  UO[        nXUsU l        U l        U l        UR                  XSUSUSXES9	U l        UR                  XSSSXES9U l        g )N   r   T)r   paddinggroupsbiasdevicedtyper	   )r   r   r   r   )	super__init__r   r   r   r   Conv2d	depthwise	pointwise)	selfr   r   r   r   r   
operationsops	__class__s	           r   r   BlazeFaceBlock.__init__f   sm    &2j/4f,
DKE!FAV[bfou  DE1adSYgr   r   r   c           
         U R                   S:  a  [        R                  " USS5      OUnU R                  U R                  :  a4  [        R
                  " USSSSSU R                  U R                  -
  45      nU R                   S:  a  [        USU R                   5      O[        R
                  " US5      n[        R                  " U R                  U R                  U5      5      U-   5      $ Nr	   r   r   r   r	   r	   r	   r	   )
r   r   
max_pool2dr   r   r   r   relur   r   r   r   residuals      r   forwardBlazeFaceBlock.forwardm   s    ,0KK!O1<<1a(;;#uuX1aAt{{TZZ7O'PQH/3{{QLAt{{+AEE!\DZvvdnnT^^A%67(BCCr   )r   r   r   r   r   NNN__name__
__module____qualname____firstlineno____doc__intr   r   r   __static_attributes____classcell__r   s   @r   r   r   c   sF    _hc h3 h h hD DF D Dr   r   c                   L   ^  \ rS rSrSrSU 4S jjrS\S\\\4   4S jrSr	U =r
$ )		BlazeFaceu   uH   Short-range BlazeFace: (B, 3, 128, 128) in [-1, 1] → 896 anchors x 17.c                   >^^^ [         TU ]  5         Tb  TO[        n[        TTS9nUR                  " SSSSS.UD6U l        [        R                  " UUU4S j[         5       5      U l        UR                  " SSSS	.UD6U l	        UR                  " S
SSS	.UD6U l
        UR                  " SSSS	.UD6U l        UR                  " SSSS	.UD6U l        g )Nr   r   )r   r   r   r   r   Tr   r   r   c           
   3   D   >#    U  H  u  pn[        XUTTTS 9v   M     g7fr   r   r   N)r   .0iosr   r   r   s       r   	<genexpr>%BlazeFace.__init__.<locals>.<genexpr>}   s,      $H5F	q %316QVcm$n5F    )r*   r   r	   r   r   )r   r   r	   )r*   r   r	   r   )r   r   r   dictr   stem
ModuleList_BLAZEFACE_BLOCKSblockscls_16cls_8reg_16reg_8r   r   r   r   r   kwr   s    ```  r   r   BlazeFace.__init__x   s    &2ju-JJN14N2N	mm $H5F$H H jjF14F2FZZE!$E"E
jjGADGBGZZF14F2F
r   image_chw_normalizedr   c           	      (   [         R                  " U R                  [        USS5      5      5      n[	        S5       H  nU R
                  U   " U5      nM     Un[	        SS5       H  nU R
                  U   " U5      nM     UnS n[        R                  " U" U R                  U5      SS5      U" U R                  U5      SS5      /SS9n[        R                  " U" U R                  U5      SS5      U" U R                  U5      SS5      /SS9nX4$ )	Nr   r      r   c                 t    U R                   u  p4pVU R                  SSSS5      R                  X5U-  U-  U5      $ )Nr   r   r   r	   )r   permutereshape)takB_r   r   s          r   flatBlazeFace.forward.<locals>.flat   s9    JA!99Q1a(00EAIqAAr   r	   r   dim)r   r   r   r   ranger   torchcatr   r   r   r   )	r   r   r   r   feat_16feat_8r  clsregs	            r   r   BlazeFace.forward   s    FF499\*>1EFGrAAq!A r2AAq!A 	B iidkk'2Aq94

6@RTUWX;YZ`abiidkk'2Ar:DFASUVXZ<[\bcdxr   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   tupler   r   r   r   s   @r   r   r   u   s-    RGF uVV^7L  r   r   c            	       V   ^  \ rS rSrSrSS\S\S\S\4U 4S jjjrS\S	\4S
 jrSr	U =r
$ )FRBlockr>   u   Double inverted residual: DW → PW(mid) → DW → PW(out) [+ residual].

Per source tflite: dw* have no fused activation, pw1 is always ReLU, pw2
is ReLU only when no residual (else ReLU fuses into the ADD).
r   mid_chr   r   c                 \  > [         T
U ]  5         Ub  UO[        n[        XVS9n	X:H  =(       a    US:H  U l        UR
                  " XS4USUSS.U	D6U l        UR
                  " XS4SSS.U	D6U l        UR
                  " X"S4SSUSS.U	D6U l        UR
                  " X#S4SSS.U	D6U l	        g )Nr   r	   r   r   Tr   r   r   r   r   )
r   r   r   r   has_residualr   dw1pw1dw2pw2)r   r   r  r   r   r   r   r   r   r   r   s             r   r   FRBlock.__init__   s    &2j-"_<1::eAgfaPU\`gdfg::eQKKK::fae1VZ^ebde::faLLLr   r   r   c           
         U R                   (       a  UOS n[        R                  " U R                  U R	                  [        R
                  " US5      5      5      5      nU R                  U R                  [        R
                  " US5      5      5      nUb  [        R                  " X-   5      $ [        R                  " U5      $ )Nr   )r  r   r   r  r  r   r  r  r   s      r   r   FRBlock.forward   s    ))1tFF488DHHQUU1l%;<=>HHTXXaeeA|456'/';qvval#JJr   )r  r  r  r  r  r   r   r   s   @r   r  r     sP    Mc M3 M MS M MK KF K Kr   r  )r   r   r   r	   r  )r   r   r   r   r   r   r   r	   r   )r   r   r   r   r   r   r   r	   r!  )r   r   r   r   r   r   r   r	   r"  )r   r   rU   r   rU   r   rU   r	   r#  r#  )r
   r   r   ))r   r   )r   r   )r   r   )r   r   r   r	   )r   r   r   r	   )r   r   r   r	   r   rc_outc                     U R                   u  p4pVU R                  X1XXV5      n U R                  SSSSSS5      R                  5       n U R                  X2XQ-  Xa-  5      $ )zTF DEPTH_TO_SPACE in DCR layout (input channels = (i, j, c_out)).
pixel_shuffle uses CRD which permutes output channels for c_out > 1.r   r   r
   r	   r   r   )r   r   r   
contiguous)r   r$  r%  B_r  H_W_s          r   _dcr_depth_to_spacer+     s[     GGMB2			"2*A			!Q1a#..0A99R//r   c                   L   ^  \ rS rSrSrSU 4S jjrS\S\\\4   4S jrSr	U =r
$ )	BlazeFaceFullRange   uS   Full-range face detector: (B, 3, 192, 192) in [-1, 1] → 2304 anchors x 17 values.c           	      (  >^^^^^^ [         TU ]  5         Tb  TO[        m[        TTS9mUUU4S jmTR                  " SSSSS.TD6U l        [        R                  " U4S j[         5       5      U l        [        R                  " UU4S	 j[         5       5      U l
        TR                  " S
SSS.TD6U l        [        R                  " U4S j[         5       5      U l        [        R                  " TR                  " SSSS.TD6TR                  " SSSS.TD6/5      U l        TR                  " SSSS.TD6U l        TR                  " SSSSSS.TD6U l        TR                  " SSSS.TD6U l        TR                  " SSSSSS.TD6U l        g )Nr   c           
         > [        XX#TTTS9$ )Nr   )r  )r   mr   r   r   r   r   s       r   <lambda>-BlazeFaceFullRange.__init__.<locals>.<lambda>   s    gaAuak&lr   )r   r   r   r   r   Tr   c              3   <   >#    U  H  u  pp4T" XX45      v   M     g 7fN r   r   r1  r   r   mk_blocks        r   r   .BlazeFaceFullRange.__init__.<locals>.<genexpr>   s!     %cOb|ahqQ&:&:Ob   c              3   V   >#    U  H  u  pTR                   " XS 4SSS.TD6v   M      g7f)r	   r   Tr   N)r   )r   r   r   r   r   s      r   r   r9     s/     *~i}_e`a3::aA+Zqt+ZWY+Zi}s   &))rU   r   r	   r   c              3   d   >#    U  H%  n[         R                  " U4S  jU 5       5      v   M'     g7f)c              3   <   >#    U  H  u  pp4T" XX45      v   M     g 7fr5  r6  r7  s        r   r   8BlazeFaceFullRange.__init__.<locals>.<genexpr>.<genexpr>   s     G3<A!(1..3r:  N)r   r   )r   lvlr8  s     r   r   r9     s'      ,
SeCBMMG3GGGSes   -0)r   r   r	   )r   r   r	   )r   r
   r	   )r
   r
   r   r
   r  )r   r   r	   )r   r   r   r   )r   r   r   r   r   r   r   _FR_BACKBONE_BLOCKSbackbone_FR_LATERAL_CHANNELSlateral_convstop_conv_FR_DECODER_BLOCKSdecoder_levelsdecoder_reduce_convscls_convcls_dwreg_convreg_dw)r   r   r   r   r   r8  r   r   s    ```@@@r   r   BlazeFaceFullRange.__init__   sg   &2ju-lJJN14N2N	%cOb%cc]]*~i}*~~

JqtJrJ mm ,
Se,
 
 %'MMJJ=!$="=JJ=!$="=3
 %!
 

HQTHRHjjYAadYVXY

IadIbIjj\1aQU\Y[\r   r   r   c                 *   [         R                  " U R                  [         R                  " US5      5      5      n[	        [
        5      n/ n[        U R                  5       H%  u  pVU" U5      nXS;   d  M  UR                  U5        M'     [         R                  " U R                  U5      5      n[        [        U5      5      n[        [        U R                  5      5      n	[        [        U R                  5      5       H  n
X   n[         R                   " X{R"                  SS  SSS9nU[         R                  " X   " U5      5      -   nU R                  U
    H  nU" U5      nM     U
[        U R$                  5      :  d  M  [         R                  " U R$                  U
   " U5      5      nM     U R'                  [         R                  " U R)                  U5      S5      5      n[+        USSS9nU R-                  [         R                  " U R/                  U5      S5      5      n[+        USS	S9nUR"                  S
   nUR1                  S
SSS5      R3                  U[4        S5      nUR1                  S
SSS5      R3                  U[4        S	5      nUU4$ )Nr   r   bilinearF)sizemodealign_cornersr   r	   )r$  r%  r   r   r   )r   r   r   r   set_FR_LATERAL_TAP_INDICES	enumeraterA  appendrD  listreversedrC  r  lenrF  interpolater   rG  rI  rH  r+  rK  rJ  r   r   _BF_FR_NUM_ANCHORS)r   r   r   tap_setlateralsr   blkplaterals_revlateral_convs_revlevellateralcr$  r  cls_outreg_outs                    r   r   BlazeFaceFullRange.forward   s   FF499QUU#7FGH-.!#.FAAA|" / FF4==#$HX./ $*<*<!=>3t2234E")GammBC&8zY^_AAFF,3G<==A**51F 2s44455FF444U;A>? 5 KKdmmA.=>Qa0KKdmmA.=>Qb1GGAJ))Aq!Q'//3EqI))Aq!Q'//3ErJr   )
rA  rH  rI  rF  rG  rC  rJ  rK  r   rD  r   r  r   s   @r   r-  r-     s-    ]]. F  uVV^7L    r   r-  )maxsizec                  b   [         n [        R                  " [        R                  " U [        R                  S9[        R                  " U [        R                  S9SS9u  pUS-   U -  US-   U -  [        R
                  " U5      pTn[        R                  " X4XU/SS9R                  [        S5      $ )zA2304 anchors over 48x48; anchor_w=anchor_h=1 (fixed_anchor_size).r   ijindexingr   r   axisr
   )	_BF_FR_GRIDnpmeshgridarangefloat32	ones_likestackr   rZ  )featyyxxcxcyoness         r   _blazeface_full_range_anchorsr|  
  s     D[[4rzz:BIIdRTR\R\<]hlmFBH$rCx4&7b9IDB88RT(r2::;MqQQr   
regressorsclassificatorsscore_threshc                 h   [        [        R                  " USS2S4   [        * [        5      5      nX2:  nUR	                  5       (       d#  [        R
                  " S[        R                  S9$ X   [        -  n[        5       U   nUSS2SS24   USS2SS24   USS2SS24   USS2SS24   4u  pxpUSS2SS24   U	-  U-   USS2SS24   U
-  U-   pUSS2SS24   U	-  USS2SS24   U
-  p[        R
                  " UR                  S   S	4[        R                  S9nXS-  -
  XS-  -
  XS-  -   XS-  -   4u  USS2SS24'   USS2SS24'   USS2SS24'   USS2SS24'   USS2[        SS24   U	-  U-   USS2SS
S24'   USS2[        S-   SS24   U
-  U-   USS2SS
S24'   X4   USS2S
4'   U$ )zCSame decode as short-range with 2304-anchor grid and box_scale=192.Nr   r   r   ri  r	   r   r   r
   r   r   r   )r   rp  clip_BF_FR_SCORE_CLIPanyemptyrs  _BF_FR_BOX_SCALEr|  r   _BF_KP_OFFSETr}  r~  r  scoreskeepr$  r   cxscysawsahsxcycwhouts                   r   _decode_blazeface_full_ranger    s    277>!Q$/2C1CEVWXF!D88::xxrzz22++A%'-A1ac6Aa1fIqAaCy!AqsF)CCcq!A#vY_s"Aa1fIOc$9Q!V9s?Aa1fIOq
((AGGAJ#2::
6C9;!eRa%ZQSZ[V[Q[]_fgbg]g9g6C1Q3KQ!Vc!QqS&k3q!A#v;q-***+c1C7C1R6	Nq-!+.Q../#5;C1R6	NC2JJr   )r   r   r	   r  )r   r   r   r   r   r	   r  )r   r   r   r   r   r	   r  )r   r   r   r   r   r	   r  r   r   r   r  r  r  r  r  c                   R   ^  \ rS rSrSrSS\S\S\4U 4S jjjrS\S\4S	 jrS
r	U =r
$ )FaceMeshBlocki0  zFPReLU BlazeBlock: PReLU between DW and PW, and after the residual add.r   r   r   c                 \  > [         T	U ]  5         Ub  UO[        n[        XES9nXUsU l        U l        U l        UR                  " XS4USUSS.UD6U l        [        R                  " S	SU0UD6U l
        UR                  " XS4SSS.UD6U l        [        R                  " S	SU0UD6U l        g )
Nr   r   r   Tr  num_parametersr	   r   r6  )r   r   r   r   r   r   r   r   r   PReLUprelu_dwiser   	prelu_out)
r   r   r   r   r   r   r   r   r   r   s
            r   r   FaceMeshBlock.__init__3  s    &2j-/4f,
DKE!mFAV[bfmjlm88?5?B?E1QadQbQ>>2>r   r   r   c           
         U R                   S:  a  [        R                  " USS5      OUnU R                  U R                  :  a4  [        R
                  " USSSSSU R                  U R                  -
  45      nU R                   S:  a  [        USU R                   5      O[        R
                  " US5      nU R                  U R                  U R                  U R                  U5      5      5      U-   5      $ r   )r   r   r   r   r   r   r   r  r   r  r   r   s      r   r   FaceMeshBlock.forward=  s    ,0KK!O1<<1a(;;#uuX1aAt{{TZZ7O'PQH/3{{QLAt{{+AEE!\DZ~~dnnT-=-=dnnQ>O-PQT\\]]r   )r   r   r   r   r  r  r   r   r   r   s   @r   r  r  0  sA    P?c ?3 ? ? ?^ ^F ^ ^r   r  c                   L   ^  \ rS rSrSrSU 4S jjrS\S\\\4   4S jrSr	U =r
$ )	FaceMeshiE  i  c           	      4  >^^^ [         TU ]  5         Tb  TO[        n[        TTS9nUR                  " SSSSS.UD6U l        [        R                  " SSS0UD6U l        [        R                  " UUU4S	 j[         5       5      U l
        UR                  " S
SSS.UD6U l        [        R                  " SSS0UD6U l        [        SSSTTTS9U l        UR                  " SSSS.UD6U l        UR                  " SU R                   S-  S4SSS.UD6U l        g )Nr   )r   r   r   r   r   Tr   r  r   c           
   3   D   >#    U  H  u  pn[        XUTTTS 9v   M     g7fr   )r  r   s       r   r   $FaceMesh.__init__.<locals>.<genexpr>N  s,      $G5E	q %2!&PUbl$m5Er   )r   r   r	   r   r   r	   r   )r   r	   r   r   r6  )r   r   r   r   r   r   r  
prelu_stemr   _FACEMESH_BLOCKSr   head_reduceprelu_head_reducer  
head_blockhead_presenceNUM_LANDMARKShead_landmarksr   s    ```  r   r   FaceMesh.__init__H  s   &2ju-JJN14N2N	((;";;mm $G5E$G G::LLL!#!A!Ab!A'1aeXbc ZZLLL!jjD,>,>,BAbqW[b_abr   face_chw_normalizedr   c           	         U R                  U R                  [        USS5      5      5      nU R                   H  nU" U5      nM     U R	                  U R                  U5      5      nU R                  U5      nUR                  S   nU R                  U5      R                  U5      nU R                  U5      R                  X@R                  S5      nXe4$ )uW   (B, 3, 192, 192) in [0, 1] → ((B, 478, 3) landmarks in 192-canonical, (B,) presence).r   r   r   )r  r   r   r   r  r  r  r   r  r   r  r  )r   r  r   r]  r  presencelmkss          r   r   FaceMesh.forwardV  s    OODIIl3F1&MNO;;CAA ""4#3#3A#67OOAGGAJ%%a(003""1%--a1C1CQG~r   )r   r  r  r  r  r  r  r   r   )r   r   r   r   r  r   r   r  r   r   r   r   s   @r   r  r  E  s/    Mc
6 
eFFN6K 
 
r   r  r8   r   a   r   rU      r   gư>c            	       X   ^  \ rS rSrSr SS\S\S\S\4U 4S jjjrS\S	\4S
 jrSr	U =r
$ )MlpMixerBlockio  u   MLP-Mixer block: token-mixing MLP (over tokens) → channel-mixing MLP (over dim).
Both pre-LN, both residual. LN has no beta (bias=False) to match MP.
num_tokens	token_dimtoken_hiddenchannel_hiddenc                   > [         T
U ]  5         Ub  UO[        n[        XVS9n	UR                  " U4[
        SS.U	D6U l        UR                  " U4[
        SS.U	D6U l        UR                  " X4SS0U	D6U l	        UR                  " X14SS0U	D6U l
        UR                  " X$4SS0U	D6U l        UR                  " XB4SS0U	D6U l        g )Nr   F)epsr   r   T)r   r   r   r   	LayerNorm
_BS_LN_EPSln1ln2Linear
token_mlp1
token_mlp2channel_mlp1channel_mlp2)r   r  r  r  r  r   r   r   r   r   r   s             r   r   MlpMixerBlock.__init__s  s    &2j-==M
M"M==M
M"M**ZODOBO**\ODOBOJJyRtRrRJJ~RtRrRr   r   r   c           
      Z   U R                  U5      R                  SS5      nXR                  [        R                  " U R                  U5      5      5      R                  SS5      -   nXR                  [        R                  " U R                  U R                  U5      5      5      5      -   $ )Nr	   r   )	r  	transposer  r   r   r  r  r  r  )r   r   ys      r   r   MlpMixerBlock.forward  s|    HHQK!!!Q'tq'9 :;EEaKK$$QVVD,=,=dhhqk,J%KLLLr   )r  r  r  r  r  r  r   r   r   s   @r   r  r  o  sW    L 6:S3 S3 Sc S[^ S SM MF M Mr   r  c                   Z   ^  \ rS rSrSU 4S jjr\S\S\4S j5       rS\S\4S jrSr	U =r
$ )	FaceBlendshapesrV   c                   >^^^ [         TU ]  5         Tb  TO[        n[        TTS9nUR                  " [
        [        4SS0UD6U l        UR                  " S[        4SS0UD6U l	        [        R                  " [        R                  " SS[        40 UD65      U l        [        R                  " UUU4S j[        S5       5       5      U l        UR                  " [        ["        4SS0UD6U l        g )Nr   r   Tr   r	   c              3   b   >#    U  H$  n[        [        [        [        [        TTTS 9v   M&     g7fr   )r  _BS_NUM_TOKENS_BS_TOKEN_DIM_BS_TOKEN_MIX_HIDDEN_BS_CHANNEL_MIX_HIDDEN)r   r  r   r   r   s     r   r   +FaceBlendshapes.__init__.<locals>.<genexpr>  s0      $
V^QR .-9MOe!'uMV^s   ,/r
   )r   r   r   r   r  _BS_NUM_INPUT_LANDMARKS_BS_NUM_TOKENS_REDUCEDtoken_reducer  token_embed	Parameterr	  zeros	cls_tokenr   r  r   _BS_NUM_BLENDSHAPESheadr   s    ```  r   r   FaceBlendshapes.__init__  s    &2ju-JJ'>@Vh]ahegh::aHTHRHekk!Q&L&LMmm $
V[\]V^$
 
 JJ}.ASSPRS	r   landmarks_2dr   c                     U R                  SSS9nX-
  n[        R                  " X"-  R                  SSS95      nUR                  SSS9nX$R	                  SS9-  S-  $ )Nr	   T)r  keepdimr   g-q=)minr   )meanr	  sqrtsumclamp)r  centroidr   magscales        r   _input_normalize FaceBlendshapes._input_normalize  si      $$D$9#jj!%T:;Q-KKEK**c11r   c                    U R                  U5      nU R                  UR                  SS5      5      R                  SS5      nU R                  U5      nU R                  R                  UR                  S   SS5      n[        R                  " X2/SS9nU R                   H  nU" U5      nM     [        R                  " U R                  USS2S4   5      5      $ )uV   (B, 146, 2) → (B, 52) in [0, 1]. Input units don't matter (centroid + L2 normalize).r	   r   r   r   r  N)r  r  r  r  r  expandr   r	  r
  r   sigmoidr  )r   r  r   r  r]  s        r   r   FaceBlendshapes.forward  s    !!,/akk!Q/0::1a@Qnn##AGGAJB7IIshA&;;CAA }}TYYqAw/00r   )r   r  r  r  r  r   )r   r   r   r   r   staticmethodr   r  r   r   r   r   s   @r   r  r    sC    T 2v 2& 2 2	1F 	1v 	1 	1r   r  c                  :   [        [        5      [        S:  a  SOS-   n / nSnU[        :  Ga7  [        U   nUnU[        :  a+  [        U   U:X  a  US-  nU[        :  a  [        U   U:X  a  M  XU-
  -  n[
        U-   S-
  U-  n[        R                  " [        R                  " U[        R                  S9[        R                  " U[        R                  S9SS9u  pxU[        -   U-  U[        -   U-  [        R                  " U5      pn	[        R                  " XX/SS9R                  SS5      nUR                  [        R                   " XSS95        UnU[        :  a  GM7  [        R"                  " USS9nUR$                  S	:X  d   UR$                  5       eU$ )
uQ   896 anchors per SsdAnchorsCalculator (fixed_anchor_size → anchor_w=anchor_h=1).r   r	   ri  rj  rk  r   rm  r
   )i  r
   )rX  _BF_ASPECT_RATIOS_BF_INTERP_SCALE_AR_BF_NUM_LAYERS_BF_STRIDES_BF_INPUT_SIZErp  rq  rr  rs  _BF_ANCHOR_OFFSET_X_BF_ANCHOR_OFFSET_Yrt  ru  r   rU  repeatconcatenater   )per_arlayer_anchorslayerr   lastper_cellrv  rw  rx  ry  rz  r{  cellr  s                 r   _blazeface_anchorsr    ss    "#,?!,CqKF&(ME
.
 U#^#D(9V(CAID ^#D(9V(CE\*'!+6RYYt2::>		$VXV`V`@alpq00D82@S;SW[:[]_]i]ijl]mxx,26>>r1ERYYtA>? .
  ..Q
/C99 +#))+ Jr   c                 h   [        [        R                  " USS2S4   [        * [        5      5      nX2:  nUR	                  5       (       d#  [        R
                  " S[        R                  S9$ X   [        -  n[        5       U   nUSS2SS24   USS2SS24   USS2SS24   USS2SS24   4u  pxpUSS2SS24   U	-  U-   USS2SS24   U
-  U-   pUSS2SS24   U	-  USS2SS24   U
-  p[        R
                  " UR                  S   S	4[        R                  S9nXS-  -
  XS-  -
  XS-  -   XS-  -   4u  USS2SS24'   USS2SS24'   USS2SS24'   USS2SS24'   USS2[        SS24   U	-  U-   USS2SS
S24'   USS2[        S-   SS24   U
-  U-   USS2SS
S24'   X4   USS2S
4'   U$ )uV   Decode (regs (896,16), cls (896,1)) → (N, 17) = [xyxy, kp0x..kp5y, score] in [0, 1].Nr   r  ri  r	   r   r   r
   r   r   r   )r   rp  r  _BF_SCORE_CLIPr  r  rs  _BF_BOX_SCALEr  r   r  r  s                   r   _decode_blazefacer    s    277>!Q$/..QRF!D88::xxrzz22=(AT"A1ac6Aa1fIqAaCy!AqsF)CCcq!A#vY_s"Aa1fIOc$9Q!V9s?Aa1fIOq
((AGGAJ#2::
6C9;!eRa%ZQSZ[V[Q[]_fgbg]g9g6C1Q3KQ!Vc!QqS&k3q!A#v;q-***+c1C7C1R6	Nq-!+.Q../#5;C1R6	NC2JJr   
detections
iou_threshc           
      |   U R                   S   S:X  a  U $ U [        R                  " U SS2S4   * 5         nUR                   S   n[        R                  " USS2S4   USS2S4   -
  SS5      [        R                  " USS2S4   USS2S4   -
  SS5      -  n/ n[        R                  " U[
        S9n[        U5       GH;  nXg   (       a  M  X'SS24   u  ppU/n[        US-   U5       H  nXm   (       a  M  X-SS24   u  pnn[        S	[        U
U5      [        X5      -
  5      n[        S	[        UU5      [        X5      -
  5      nUU-  nXG   XM   -   U-
  nUS:  d  Mw  UU-  U:  d  M  UR                  U5        S
Xm'   M     S
Xg'   X,   nUSS2SS24   nUR                  5       n[        R                  " US   5      nUS:  a!  USS2SS24   U-  R                  SS9U-  USS& UR                  U5        GM>     U(       a  [        R                  " USS9$ [        R                  " S[        R                  S9$ )uU   MP weighted NMS — kept boxes are score-weighted averages of overlapping detections.r   Nr   r   r   r	   ri  r
   r   Tr   rm  r  )r   rp  argsortr  r  boolr  r   r  rU  r  copyru  r  rs  )r	  r
  detsNareaskeptusedr   ax1ay1ax2ay2	merge_idxjbx1by1bx2by2iwihinterunionclusterwsws_summergeds                             r   _weighted_nmsr&    s5   abjj*QU"3!345D

1AGGDAJad+Q5QT
TRSUVRVZ@WYZ\`8aaED88AT"D1X7!QqS&\#C	q1uaAw!%1fCc3S#c3-#c-78BS#c3-#c-78BGEHux'%/EqyUU]Z7  # ! /Q2X$A:"1crc6?R/44!4<vEF3BKF/ 0 &*288Dq!Rrxxrzz/RRr   	detectionimage_wimage_hc                    U SS u  p4pVU S[         S-  -   S-      U-  nU S[         S-  -   S-      U-  nU S[        S-  -   S-      U-  n	U S[        S-  -   S-      U-  n
[        [        R                  " X-
  X-
  5      -
  n[        X5-   S-  U-  5      [        XF-   S-  U-  5      [        XS-
  U-  [        -  5      [        Xd-
  U-  [        -  5      [        U5      4$ )uN   Detection (normalized) → rotated 1.5xbbox ROI in image pixels (anisotropic).r   r
   r   r	   r   )_FACE_LEFT_EYE_KP_FACE_RIGHT_EYE_KP_FACE_ROI_TARGET_ANGLEmathatan2float_FACE_ROI_SCALE_X_FACE_ROI_SCALE_Y)r'  r(  r)  xminyminxmaxymaxlxlyrxryangles               r   _detection_to_face_rectr<    s
   &q^D	1(1,,q0	1G	;B	1(1,,q0	1G	;B	1)A--1	2W	<B	1)A--1	2W	<B"TZZ%AAE4;#%/04;#%/04;'),==>4;'),==>%L	 r   	image_chwsrc_xsrc_ypadding_modec                 H   [        U R                  S   5      [        U R                  S   5      pT[        R                  " SU-  S-   U-  S-
  SU-  S-   U-  S-
  /SS9R	                  S5      n[
        R                  " U R	                  S5      USSUS	9R                  S5      $ )
z;Bilinear-sample image_chw at corner-aligned (src_x, src_y).r   r   g       @r   r  r   rN  F)rP  rQ  r@  )r   r   r	  ru  	unsqueezer   grid_samplesqueeze)r=  r>  r?  r@  r   r   grids          r   _sample_warprF    s    yr"#S)<%=q;;us*a/#5us*a/#57<>@@I	! 	==,,Q/J',<IIPQRTr   ry  rz  widthheightr;  output_sizec                 T   X6-  XF-  p[         R                  " U5      [         R                  " U5      p[        R                  " X`R
                  U R                  S9US-  -
  n[        R                  " XSS9u  pXU-  U	-  -   X-  U
-  -
  nX-U-  U
-  -   X-  U	-  -   n[        XUS5      $ )uR   Rotated rect → output_size² with BORDER_REPLICATE. image_chw must be in [0, 1].r   r   r   rj  rk  border)	r.  cossinr	  rr  r   r   rq  rF  )r=  ry  rz  rG  rH  r;  rI  s_xs_ycos_asin_arr  v_gridu_gridr>  r?  s                   r   _warp_face_croprU    s     "F$888E?DHHUO5\\+__YEUEUVYdgjYjjF^^FTBNF#%%u(<<E#%%u(<<E	%::r   image_chw_rawtargetc                 r   [        U R                  S   5      [        U R                  S   5      p2[        [        X25      5      nUS-  US-  peXA-  n[        R
                  " XR                  U R                  S9US-  -
  n[        R                  " XSS9u  p[        XX-  -   XiU-  -   S5      nUS-  S	-
  XVU4$ )
u  Centered max(W,H) square → target² with BORDER_ZERO + [-1, 1] norm.

Sub-pixel grid_sample matters; integer-pad-then-resize drifts the bbox ~5%.
Returns (warped, sub_rect_cx, sub_rect_cy, sub_rect_size) — the triplet maps
tensor-normalized [0,1] detections back to image pixels.
r	   r   r   rK  rj  rk  r  g     _@r   )
r   r   r0  r   r	  rr  r   r   rq  rF  )rV  rW  r   r   sub_rect_sizesub_rect_cxsub_rect_cyr   rr  rS  rT  r  s               r   _blazeface_input_warpr\    s     }""1%&M,?,?,B(Cq#a)$M 3wCA\\&(;(;MDXDXY\beh\hhF^^FTBNF
}FJ&>WXj@XZa
bC%K3-GGr   c                      ^  \ rS rSrSrSS\4U 4S jjjr\S4S\\	R                     S\S\4S	 jjrS
\4S\\	R                     S\S\S\\\      4S jjrSrU =r$ )FaceLandmarkeri.  u7  BlazeFace → FaceMesh v2 → blendshapes. `detector_variant` selects 'short'
(128², ≤2m) or 'full' (192² FPN, ≤5m). State dict uses inner-module prefixes
`detector.*` / `mesh.*` / `blendshapes.*`; the outer FaceLandmarkerModel
wrapper rewrites `detector_{variant}.*` keys to `detector.*` before loading.
detector_variantc                 &  > [         TU ]  5         [        [        S.R	                  U5      nX@l        U" XUS9U l        [        XUS9U l        [        XUS9U l
        U R                  S[        R                  " [        [        R                  S9SS9  g )N)shortfullr   _bs_idxri  F)
persistent)r   r   r   r-  getr_  detectorr  meshr  blendshapesregister_bufferr	  tensorrW   long)r   r   r   r   r_  det_clsr   s         r   r   FaceLandmarker.__init__5  s}    %/ABFFGWX 0vzRFJO	*&R\]Y5Fejj(Yfklr   r   images_rgb_uint8r  r
  c                    U(       d  / / / / 4$ U R                   R                  R                  R                  U R                   R                  R                  R                  pTU R
                  S:X  a  [        [        4O[        [        4u  pgU Vs/ s H  n[        UR                  SS 5      PM     n	n[        [        U	5      5      S:X  a  [        R                  " [         R"                  " USS95      R%                  XE5      R'                  SS5      R)                  5       n
[+        U
R                  S   5       Vs/ s H  oU   PM	     nnOSU Vs/ s HF  n[        R                  " U5      R%                  XE5      R'                  SS5      R)                  5       PMH     nnU Vs/ s H  n[-        X5      PM     nnU Vs/ s H  oS   PM	     nnU Vs/ s H  oS   US   US	   4PM     nnU R                  [        R"                  " USS
95      u  nnUR/                  5       R1                  5       R3                  5       UR/                  5       R1                  5       R3                  5       nn/ n[+        [        U5      5       H?  nU" UU   UU   US9nUR5                  UR                  S   S:  a
  [7        UUS9OU5        MA     UUU	U4$ s  snf s  snf s  snf s  snf s  snf s  snf )zBatched detector pass. Returns (img_raws, sub_rects, sizes, per_frame_decoded)
where per_frame_decoded[b] is (N, 17) in tensor-normalized [0,1] coords.rb  Nr   r	   r   rm  r   r   r  r  )r
  )rf  r   weightr   r   r_  _BF_FR_INPUT_SIZEr  r  r  r  r   rX  rR  r	  
from_numpyrp  ru  tomovedimr'  r  r\  r0  cpunumpyrU  r&  )r   rn  r  r
  r   r   det_input_size	decode_fnimgsizes	batch_chwbiimg_rawsimg_rawwarpsr  	det_crops	sub_rectsregs_bcls_bregs_npcls_np	per_framebdecodeds                            r   run_detector_batch!FaceLandmarker.run_detector_batch?  s   
  r2r>!**1188$--:L:L:S:S:Y:Y(,(=(=(G '89U%V+9;L*M 	" 2BB1A#syy!}%1ABs5z?a((2B)KLOOPV^ffgikmnyy{I05iooa6H0IJ0I""0IHJHhxyhxad((-00?GGBOZZ\hxHyOWXxG&w?xX#()5aqT5	)167AdAaD!A$'	7ekk)&CD ,,.,,.4468I8I8K8Q8Q8S	s+,-A
F1ILQGgmm\]N^abNb]7zJhop . E944# C KyX)7s%   "K	;KAK#K>KK"r	   	num_facesr   c                    U R                  XS9u  pEpg[        U5       H  u  pU	R                  S   S:X  a  M  XX   u  pnXh   u  pXS-  -
  XS-  -
  nnXU	SS2SSS24   -  -   U-  U	SS2SSS24'   UXSS2SSS24   -  -   U-  U	SS2SSS24'   US:  d  My  U	S[        U5       Xx'   M     / n/ n[        U5       H  u  nnUR                  S   S:X  a  M  Xh   u  pXH   S-  nU HZ  n[	        UX5      u  pnnnUR                  [        UXUUU[        5      5        UR                  U[        US   5      XUUU45        M\     M     [        [        U5      5       Vs/ s H  n/ PM     nnU(       d  U$ U R                  [        R                  " USS	95      u  nnU R                  USS2U R                  SS24   5      n[        R                   " U VVV
VVVV s/ s H9  u  nnpnnn XUU["        R$                  " U 5      ["        R&                  " U 5      4PM;     sn nnnn
nnUR(                  UR*                  S
9n!U!R-                  SS	9u  n"n#n$n%n&n'S[        -  n(US   [        S-  -
  n)US   [        S-  -
  n*[        R                  " U"SS2S4   U)U$U(-  U&-  SS2S4   -  -   U*U%U(-  U'-  SS2S4   -  -
  U#SS2S4   U)U$U(-  U'-  SS2S4   -  -   U*U%U(-  U&-  SS2S4   -  -   /SS	9n+U+R                  5       R/                  5       R1                  5       n,UR                  5       R/                  5       R1                  5       n-UR                  5       R/                  5       R1                  5       n.UR                  5       R/                  5       R1                  5       n/[        U5       H  u  n0tnn1nU,U0   n2U2R3                  S5      U2R5                  S5      n4n3UU   R                  [6        R8                  " U3S   U3S   U4S   U4S   /[6        R:                  S9[=        [?        [@        U/U0   RC                  5       5      5      U2U-U0   [        U.U0   5      U1S.5        M     U$ s  snf s  sn nnnn
nnf )uF  Full pipeline batched across `images_rgb_uint8`. Returns one face-dict
list per image (empty if nothing detected). Face dict:
    bbox_xyxy (4,) image pixels, blendshapes {52} ∈ [0,1],
    landmarks_xy (478, 2) image pixels, landmarks_3d (478, 3) in
    192-canonical (pre-transformation) units, presence float (raw logit).
rq  r   r   Nr   r   r	   g     o@r  r   r   ).r   ).r	   r   ri  )	bbox_xyxyrh  landmarks_xylandmarks_3dr  score)"r  rT  r   r   r<  rU  rU  _FM_INPUT_SIZEr0  r  rX  rg  r	  ru  rh  rc  rj  r.  rM  rN  r   r   unbindrw  rx  r  r   rp  arrayrs  r   zipr   tolist)5r   rn  r  r  r  r  r|  per_frame_detsr  r  ry  rz  rO  r   r   sx0sy0face_params
mesh_cropsr  img_for_meshdetr  r  r;  r  resultslmks_canon_b
presence_bbs_out_b_b_sr   params_tr  r  r#  hsrQ  rR  invuv	lmks_xy_t
lmks_xy_nplmks_canon_nppresence_npbs_npr   r  lmks_xymnmxs5                                                        r   detect_batchFaceLandmarker.detect_batch`  s    6:5L5L 6M 6
2U $N3JA}}Q1$$<LBD8DA3JCZC"%wq!Bq&y/A(A"AQ!FGAqAvI"%q!Bq&y/A(A"AQ!FGAqAvI1}$+,<c)n$=! 4 SU#%
 0GAtzz!}!8DA#;.L&=c1&H#1e!!/,1eUc"de""AuSW~rq!U#KL  1 27s;K7L1M$N1MAR1M$NN#'99U[[-K#L j##LDLL"1"1D$EF <<WbccWb:S2r21aQRbaDHHQK!5Wbc&&l.@.@
 *2Q)?&S"b%N" >C#77 >C#77KK4L1S5 0!T':::Q"s(UBRTUW[T[A\=\\4L1S5 0!T':::Q"s(UBRTUW[T[A\=\\!
 	
 __&**,224
$**,00288: &&(,,.446 $$&,,.!*;!7A~51 mG[[^W[[^BAJXXr!ubeRUBqE&B"**U#C(8%(//:K$LM ' -a 0!+a.1  "8 K %O dcs   QA Q!)rh  rf  r_  rg  )NNNra  )r   r   r   r   r   strr   _BF_MIN_SCOREr   rp  ndarrayr0  r  r   r   r  r   r   r   s   @r   r^  r^  .  s    mSV m m 2?/254

3C 5).5',5B QR+8IT"**-= I# I#(I=A$t*=MI Ir   r^  )r   )Qr   r.  	functoolsr   typingr   r   rx  rp  r	  torch.nn.functionalr   
functionalr   scipy.specialr   r   rW   r   __annotations__r   r  r  r  r  r  r  r  r  r  r  r  r  rs  ro  rZ  r  r  r  r+  r,  r1  r2  r-  r   r   Moduler   r   r  r@  rS  rB  rE  r+  r-  r  r|  r0  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r&  r<  rF  rU  r\  r^  r6  r   r   <module>r     s  @         & 5c? % %S/ "        ;.         VF VC V V V DRYY D$ 		  JKbii K4  % 7  o&o& 06 0c 0# 0& 08  8 v 1Rrzz R R 8ERZZ  /4IK, ^BII ^*ryy @      
MBII M. 1bii  1F 1BJJ  . -:"** bjj $)>@jj(!Sbjj !Se !Sbjj !SHrzz C # RWX]_dfkmrtyXyRz  TF T6 T& TPS TX^ T 6D	;v 	;5 	;e 	;E 	;SX 	; 	;/2	;HN	; @N H H HRWX^`eglnsXsRt H"{RYY {r   