
    +j                        U d Z ddlZddlmZ ddlmZmZ ddlZddl	Z	ddl
mc mZ ddlmZ ddl	mZmZ dZeedf         ed	<   d
Zeedf         ed<   dZdZdZdZdZdZdZdZdZdZdZ dZ!dZ"e"e"z  Z#dZ$dZ%dZ&dZ'dZ(dZ)dZ*dZ+dedededefdZ,g dZ- G d  d!ej.                  Z/ G d" d#ej.                  Z0 G d$ d%ej.                  Z1g d&Z2d'Z3d(Z4d)d)gd*d*gd+ggZ5d,ed-ed.edefd/Z6 G d0 d1ej.                  Z7 ed2          dej8        fd3            Z9e fd4ej8        d5ej8        d6e:dej8        fd7Z;g d8Z< G d9 d:ej.                  Z= G d; d<ej.                  Z>d=Z?d>Z@d?ZAd@ZBdAZCdBZDdCZEdDZF G dE dFej.                  ZG G dG dHej.                  ZH ed2          dej8        fdI            ZIe fd4ej8        d5ej8        d6e:dej8        fdJZJdcdKej8        dLe:dej8        fdMZKdNej8        dOedPedee:e:e:e:e:f         fdQZLdRedSedTedUedef
dVZMe&fdRedWe:dXe:dYe:dZe:d[e:d\edefd]ZNefd^ed_edeee:e:e:f         fd`ZO G da dbej.                  ZPdS )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  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           	      <   | j         d         | j         d         }}t          ||z   dz
  |z  dz
  |z  |z   |z
  d          }t          ||z   dz
  |z  dz
  |z  |z   |z
  d          }|dk    r|dk    r| S t          j        | |dz  ||dz  z
  |dz  ||dz  z
  f          S )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    72;qA!f*q.V+a/69FBQFJJE!f*q.V+a/69FBQFJJEzzeqjj5UaZ!!3UaZRSASTU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                   B     e Zd ZdZd
dededef fdZdedefd	Z xZS )BlazeFaceBlockzUDW 3x3 + PW + residual. Residual max-pools on stride>1, channel-pads on out_ch>in_ch.Nin_chout_chr   c                    t                                                       ||nt          }|||c| _        | _        | _        |                    ||d|d|d||	  	        | _        |                    ||ddd||          | _        d S )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   zBlazeFaceBlock.__init__f   s    &2jj/4ff,
DKE5!FAV[bfou  ~C  D  DE61adSYafggr   r   r   c           
         | j         dk    rt          j        |dd          n|}| j        | j        k    r(t          j        |ddddd| j        | j        z
  f          }| j         dk    rt          |d| j                   nt          j        |d          }t          j        |                     | 	                    |                    |z             S Nr	   r   r   r   r	   r	   r	   r	   )
r   r   
max_pool2dr   r   r   r   relur   r   r   r   residuals      r   forwardzBlazeFaceBlock.forwardm   s    ,0K!OO1<1a(((;##uX1aAt{TZ7O'PQQH/3{QLAt{+++AE!\DZDZvdnnT^^A%6%677(BCCCr   NNN	__name__
__module____qualname____doc__intr   r   r   __classcell__r   s   @r   r   r   c   s        __h hc h3 h h h h h h hD DF D D D D D D D Dr   r   c                   D     e Zd ZdZd fd	Zdedeeef         fdZ xZS )	BlazeFaceuH   Short-range BlazeFace: (B, 3, 128, 128) in [-1, 1] → 896 anchors x 17.Nc                    t                                                       nt          }t                    } |j        ddddd|| _        t          j        fdt          D                       | _         |j        dddd	|| _	         |j        d
ddd	|| _
         |j        dddd	|| _         |j        dddd	|| _        d S )Nr   r   )r   r   r   r   r   Tr   r   r   c           	   3   J   K   | ]\  }}}t          |||           V  dS r   r   r   N)r   .0iosr   r   r   s       r   	<genexpr>z%BlazeFace.__init__.<locals>.<genexpr>}   s\       $H $H(1Aq %31a6QVcm$n$n$n $H $H $H $H $H $Hr   )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   zBlazeFace.__init__x   s2   &2jju---CJN14NN2NN	m $H $H $H $H $H $H5F$H $H $H H H !cjF14FF2FFSZE!$EE"EE
 cjGADGGBGGSZF14FF2FF


r   image_chw_normalizedr   c           	      v   t          j        |                     t          |dd                              }t	          d          D ]} | j        |         |          }|}t	          dd          D ]} | j        |         |          }|}d }t          j         ||                     |          dd           || 	                    |          dd          gd          }t          j         || 
                    |          dd           ||                     |          dd          gd          }||fS )	Nr   r      r   c                     | j         \  }}}}|                     dddd                              |||z  |z  |          S )Nr   r   r   r	   )r   permutereshape)takB_r   r   s          r   flatzBlazeFace.forward.<locals>.flat   sC    JAq!Q99Q1a((00AEAIqA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   zBlazeFace.forward   sK   F499\*>1EEFFGGr 	" 	"AAq!!AAr2 	" 	"AAq!!AA	B 	B 	B idkk'22Aq9944

6@R@RTUWX;Y;YZ`abbbidkk'22Ar::DDFASASUVXZ<[<[\bcdddCxr   r   	r   r   r   r   r   r   tupler   r   r   s   @r   r   r   u   st        RRG G G G G GF uVV^7L        r   r   c            	       F     e Zd ZdZddedededef fdZded	efd
Z xZS )FRBlocku   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).
    Nr   mid_chr   r   c                 j   t                                                       ||nt          }t          ||          }	||k    o|dk    | _         |j        ||df|d|dd|	| _         |j        ||dfddd|	| _         |j        ||dfdd|dd|	| _         |j        ||dfddd|	| _	        d S )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   zFRBlock.__init__   s    &2jju---"f_<13:eUAgfaPU\`ggdfgg3:eVQKKKKK3:ffae1VZ^eebdee3:ffaLLLLLr   r   r   c           
         | j         r|nd }t          j        |                     |                     t          j        |d                                        }|                     |                     t          j        |d                              }|t          j        ||z             nt          j        |          S )Nr   )r  r   r   r  r  r   r  r  r   s      r   r   zFRBlock.forward   s    )311tF488DHHQU1l%;%;<<==>>HHTXXaeA|445566'/';qva(l###Jr   r   r   r   s   @r   r  r     s         M Mc M3 M MS M M M M M MK KF K K K K K K 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                     | j         \  }}}}|                     ||||||          } |                     dddddd                                          } |                     ||||z  ||z            S )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     su     GMB2r			"aE2r**A			!Q1a##..00A99RQQ///r   c                   D     e Zd ZdZd fd	Zdedeeef         fdZ xZS )BlazeFaceFullRangeuS   Full-range face detector: (B, 3, 192, 192) in [-1, 1] → 2304 anchors x 17 values.Nc           	         t                                                       nt          t                    fd j        ddddd| _        t          j        fdt          D                       | _        t          j        fd	t          D                       | _
         j        d
ddd| _        t          j        fdt          D                       | _        t          j         j        dddd j        ddddg          | _         j        dddd| _         j        dddddd| _         j        dddd| _         j        dddddd| _        d S )Nr   c           	      0    t          | |||          S )Nr   )r  )r   mr   r   r   r   r   s       r   <lambda>z-BlazeFaceFullRange.__init__.<locals>.<lambda>   s    gaAquak&l&l&l r   )r   r   r   r   r   Tr   c              3   >   K   | ]\  }}}} ||||          V  d S N r   r   r"  r   r   mk_blocks        r   r   z.BlazeFaceFullRange.__init__.<locals>.<genexpr>   s;      %c%c|1ahhq!Q&:&:%c%c%c%c%c%cr   c              3   D   K   | ]\  }} j         ||d fdddV  dS )r	   r   Tr   N)r   )r   r   r   r   r   s      r   r   z.BlazeFaceFullRange.__init__.<locals>.<genexpr>   sJ      *~*~_e`acd:3:aA+Zqt+Z+ZWY+Z+Z*~*~*~*~*~*~r   )rU   r   r	   r   c              3   X   K   | ]$}t          j        fd |D                       V  %dS )c              3   >   K   | ]\  }}}} ||||          V  d S r%  r&  r'  s        r   r   z8BlazeFaceFullRange.__init__.<locals>.<genexpr>.<genexpr>   s;      GG<Aq!Q((1aA..GGGGGGr   N)r   r   )r   lvlr(  s     r   r   z.BlazeFaceFullRange.__init__.<locals>.<genexpr>   sS       ,
 ,
LOBMGGGG3GGGGG,
 ,
 ,
 ,
 ,
 ,
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   _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   r(  r   r   s    ```@@@r   r   zBlazeFaceFullRange.__init__   s   &2jju---llllllCJN14NN2NN	%c%c%c%cOb%c%c%ccc]*~*~*~*~*~i}*~*~*~~~"
JqtJJrJJ m ,
 ,
 ,
 ,
Se,
 ,
 ,
 
 
 %'MCJ=!$=="==CJ=!$=="==3
 % %!
 #
HQTHHRHH cjYAadYYVXYY"
IadIIbII cj\1aQU\\Y[\\r   r   r   c                    t          j        |                     t          j        |d                              }t	          t
                    }g }t          | j                  D ])\  }} ||          }||v r|                    |           *t          j        | 	                    |                    }t          t          |                    }t          t          | j                            }	t          t          | j                            D ]}
||
         }t          j        ||j        dd          dd          }|t          j         |	|
         |                    z   }| j        |
         D ]} ||          }|
t          | j                  k     r(t          j         | j        |
         |                    }|                     t          j        |                     |          d                    }t+          |dd          }|                     t          j        |                     |          d                    }t+          |dd	          }|j        d
         }|                    d
ddd                              |t4          d          }|                    d
ddd                              |t4          d	          }||fS )Nr   r   bilinearF)sizemodealign_cornersr   r	   )r  r  r   r   r   )r   r   r   r   set_FR_LATERAL_TAP_INDICES	enumerater.  appendr1  listreversedr0  r   lenr3  interpolater   r4  r6  r5  r  r8  r7  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   zBlazeFaceFullRange.forward   s   F499QU#7FFGGHH-..!#.. 	# 	#FAsAAG||""" F4==##$$HX..// $*<!=!=>>3t23344 	@ 	@E"5)GagmBCC&8zY^___AAF3,U3G<<===A*51  CFFs445555F;44U;A>>??KKdmmA..==>>Qa000KKdmmA..==>>Qb111GAJ))Aq!Q''//3EqII))Aq!Q''//3ErJJr   r   r  r   s   @r   r  r     st        ]]] ] ] ] ] ]. F  uVV^7L                r   r  )maxsizec                  j   t           } t          j        t          j        | t          j                  t          j        | t          j                  d          \  }}|dz   | z  |dz   | z  t          j        |          }}}t          j        ||||gd                              t          d          S )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   rF  )featyyxxcxcyoness         r   _blazeface_full_range_anchorsrg  
  s     D[4rz:::BIdRTR\<]<]<]hlmmmFBH$rCx4&7b9I9IDB8RT4(r222::;MqQQQr   
regressorsclassificatorsscore_threshc                    t          t          j        |dddf         t           t                              }||k    }|                                s t          j        dt          j                  S | |         t          z  }t                      |         }|ddddf         |ddddf         |ddddf         |ddddf         f\  }}}	}
|ddddf         |	z  |z   |ddddf         |
z  |z   }}|ddddf         |	z  |ddddf         |
z  }}t          j        |j	        d         d	ft          j                  }||dz  z
  ||dz  z
  ||dz  z   ||dz  z   f\  |ddddf<   |ddddf<   |ddddf<   |ddddf<   |ddt          ddf         |	z  |z   |dddd
df<   |ddt          dz   ddf         |
z  |z   |dddd
df<   ||         |ddd
f<   |S )zCSame decode as short-range with 2304-anchor grid and box_scale=192.Nr   r   r   rT  r	   r   r   r
   r   r   r   )r   r[  clip_BF_FR_SCORE_CLIPanyemptyr^  _BF_FR_BOX_SCALErg  r   _BF_KP_OFFSETrh  ri  rj  scoreskeepr  r   cxscysawsahsxcycwhouts                   r   _decode_blazeface_full_ranger    st    27>!!!Q$/2C1CEVWWXXF\!D88:: 3xrz22224++A%''-A111ac6Aaaa1fIqAaCy!AAAqsF)CCc3qqq!A#vY_s"Aaaa1fIOc$9BQQQ!V9s?Aaaa1fIOqA
(AGAJ#2:
6
6
6C9;a!eR!a%ZQSVWZ[V[Q[]_bcfgbg]g9g6C1Q3KQQQ!Vc!!!QqS&k3qqq!A#v;qqq-***+c1C7C1R6	Nqqq-!+.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                   B     e Zd ZdZd
dededef fdZdedefd	Z xZS )FaceMeshBlockzFPReLU BlazeBlock: PReLU between DW and PW, and after the residual add.Nr   r   r   c                 p   t                                                       ||nt          }t          ||          }|||c| _        | _        | _         |j        ||df|d|dd|| _        t          j	        d	d|i|| _
         |j        ||dfddd|| _        t          j	        d	d|i|| _        d S )
Nr   r   r   Tr
  num_parametersr	   r   r&  )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   zFaceMeshBlock.__init__3  s    &2jju---/4ff,
DK#E5!mFAV[bfmmjlmm8??5?B??#E61QadQQbQQ>>>2>>r   r   r   c           
         | j         dk    rt          j        |dd          n|}| j        | j        k    r(t          j        |ddddd| j        | j        z
  f          }| j         dk    rt          |d| j                   nt          j        |d          }|                     |                     | 	                    | 
                    |                              |z             S r   )r   r   r   r   r   r   r   r  r   r  r   r   s      r   r   zFaceMeshBlock.forward=  s    ,0K!OO1<1a(((;##uX1aAt{TZ7O'PQQH/3{QLAt{+++AE!\DZDZ~~dnnT-=-=dnnQ>O>O-P-PQQT\\]]]r   r   r   r   s   @r   r  r  0  s        PP? ?c ?3 ? ? ? ? ? ? ?^ ^F ^ ^ ^ ^ ^ ^ ^ ^r   r  c                   D     e Zd ZdZd fd	Zdedeeef         fdZ xZS )FaceMeshi  Nc                 2   t                                                       nt          }t                    } |j        ddddd|| _        t          j        dddi|| _        t          j        fd	t          D                       | _
         |j        d
ddd|| _        t          j        dddi|| _        t          ddd          | _         |j        dddd|| _         |j        d| j        dz  dfddd|| _        d S )Nr   )r   r   r   r   r   Tr   r  r   c           	   3   J   K   | ]\  }}}t          |||           V  dS r   )r  r   s       r   r   z$FaceMesh.__init__.<locals>.<genexpr>N  s\       $G $G(1Aq %2!Q&PUbl$m$m$m $G $G $G $G $G $Gr   )r   r   r	   r   r   r	   r   )r   r	   r   r   r&  )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   zFaceMesh.__init__H  s{   &2jju---CJN14NN2NN	(;;";;;m $G $G $G $G $G $G5E$G $G $G G G%3:LLLLL!#!A!A!Ab!A!A'1aeXbccc'SZLLLLL(cjD,>,BAbqW[bb_abbr   face_chw_normalizedr   c           	         |                      |                     t          |dd                              }| j        D ]} ||          }|                     |                     |                    }|                     |          }|j        d         }|                     |          	                    |          }| 
                    |          	                    || j        d          }||fS )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   rI  r   presencelmkss          r   r   zFaceMesh.forwardV  s    OODIIl3F1&M&MNNOO; 	 	CAAA""4#3#3A#6#677OOAGAJ%%a((0033""1%%--a1CQGGX~r   r   )	r   r   r   r  r   r   r  r   r   r   s   @r   r  r  E  ss        Mc c c c c c
6 
eFFN6K 
 
 
 
 
 
 
 
r   r  r8   r   a   r   rU      r   gư>c            	       H     e Zd ZdZ	 ddedededef fdZded	efd
Z xZS )MlpMixerBlocku   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.N
num_tokens	token_dimtoken_hiddenchannel_hiddenc                    t                                                       ||nt          }t          ||          }	 |j        |ft
          dd|	| _         |j        |ft
          dd|	| _         |j        ||fddi|	| _	         |j        ||fddi|	| _
         |j        ||fddi|	| _         |j        ||fddi|	| _        d S )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   zMlpMixerBlock.__init__s  s   &2jju--- 3=M
MM"MM 3=M
MM"MM$#*ZOODOBOO$#*\:OODOBOO&CJy.RRtRrRR&CJ~yRRtRrRRr   r   r   c           
         |                      |                              dd          }||                     t          j        |                     |                                                  dd          z   }||                     t          j        |                     |                     |                                        z   S )Nr	   r   )	r  	transposer  r   r   r  r  r  r  )r   r   ys      r   r   zMlpMixerBlock.forward  s    HHQKK!!!Q''tq'9'9 : :;;EEaKKK4$$QVD,=,=dhhqkk,J,J%K%KLLLLr   r   r   r   s   @r   r  r  o  s        L L 6:S S3 S3 Sc S[^ S S S S S SM MF M M M M M M M Mr   r  c                   P     e Zd Zd fd	Zededefd            ZdedefdZ xZS )FaceBlendshapesNc                    t                                                       nt          }t                    } |j        t
          t          fddi|| _         |j        dt          fddi|| _	        t          j
        t          j        ddt          fi |          | _        t          j        fdt          d          D                       | _         |j        t          t"          fddi|| _        d S )Nr   r   Tr   r	   c           
   3   l   K   | ].}t          t          t          t          t                     V  /dS r   )r  _BS_NUM_TOKENS_BS_TOKEN_DIM_BS_TOKEN_MIX_HIDDEN_BS_CHANNEL_MIX_HIDDEN)r   r   r   r   r   s     r   r   z+FaceBlendshapes.__init__.<locals>.<genexpr>  sZ       $
 $
QR .-9MOe!'uM M M$
 $
 $
 $
 $
 $
r   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   zFaceBlendshapes.__init__  s#   &2jju---&CJ'>@Vhh]aheghh%3:aHHTHRHHek!Q&L&L&L&LMMm $
 $
 $
 $
 $
 $
V[\]V^V^$
 $
 $
 
 
 CJ}.ASSSPRSS			r   landmarks_2dr   c                     |                      dd          }| |z
  }t          j        ||z                      dd                    }|                     dd          }||                    d          z  dz  S )Nr	   T)r   keepdimr   g-q=)minr   )meanr   sqrtsumclamp)r  centroidr   magscales        r   _input_normalizez FaceBlendshapes._input_normalize  s|      $$D$998#j!a%T::;;Q--EKKEK***c11r   c                    |                      |          }|                     |                    dd                                        dd          }|                     |          }| j                            |j        d         dd          }t          j        ||gd          }| j	        D ]} ||          }t          j
        |                     |dddf                             S )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  rI  s        r   r   zFaceBlendshapes.forward  s    !!,//akk!Q//00::1a@@Qn##AGAJB77IsAhA&&&; 	 	CAAA}TYYqAw//000r   r   )	r   r   r   r   staticmethodr   r  r   r   r   s   @r   r  r    s        T T T T T T 2v 2& 2 2 2 \2	1F 	1v 	1 	1 	1 	1 	1 	1 	1 	1r   r  c                  j   t          t                    t          dk    rdndz   } g }d}|t          k     rNt          |         }|}|t          k     r2t          |         |k    r!|dz  }|t          k     rt          |         |k    !| ||z
  z  }t
          |z   dz
  |z  }t          j        t          j        |t          j	                  t          j        |t          j	                  d          \  }}|t          z   |z  |t          z   |z  t          j        |          }}
}	t          j        |	|
||gd                              dd          }|                    t          j        ||d                     |}|t          k     Nt          j        |d          }|j        d	k    sJ |j                    |S )
uQ   896 anchors per SsdAnchorsCalculator (fixed_anchor_size → anchor_w=anchor_h=1).r   r	   rT  rU  rV  r   rX  r
   )i  r
   )rD  _BF_ASPECT_RATIOS_BF_INTERP_SCALE_AR_BF_NUM_LAYERS_BF_STRIDES_BF_INPUT_SIZEr[  r\  r]  r^  _BF_ANCHOR_OFFSET_X_BF_ANCHOR_OFFSET_Yr_  r`  r   rA  repeatconcatenater   )per_arlayer_anchorslayerr   lastper_cellra  rb  rc  rd  re  rf  cellr~  s                 r   _blazeface_anchorsr    s    "##,?!,C,CqqKF&(ME
.
 
 U#^##D(9V(C(CAID ^##D(9V(C(CTE\*'!+6RYt2:>>>	$VXV`@a@a@alpqqqB00D82@S;SW[:[]_]ijl]m]mBxRt,2666>>r1EERYtXA>>>??? .
 
  .Q
/
/
/C9   #)   Jr   c                    t          t          j        |dddf         t           t                              }||k    }|                                s t          j        dt          j                  S | |         t          z  }t                      |         }|ddddf         |ddddf         |ddddf         |ddddf         f\  }}}	}
|ddddf         |	z  |z   |ddddf         |
z  |z   }}|ddddf         |	z  |ddddf         |
z  }}t          j        |j	        d         d	ft          j                  }||dz  z
  ||dz  z
  ||dz  z   ||dz  z   f\  |ddddf<   |ddddf<   |ddddf<   |ddddf<   |ddt          ddf         |	z  |z   |dddd
df<   |ddt          dz   ddf         |
z  |z   |dddd
df<   ||         |ddd
f<   |S )uV   Decode (regs (896,16), cls (896,1)) → (N, 17) = [xyxy, kp0x..kp5y, score] in [0, 1].Nr   rl  rT  r	   r   r   r
   r   r   r   )r   r[  rm  _BF_SCORE_CLIPro  rp  r^  _BF_BOX_SCALEr  r   rr  rs  s                   r   _decode_blazefacer    sp    27>!!!Q$/..QQRRF\!D88:: 3xrz22224=(AT"A111ac6Aaaa1fIqAaCy!AAAqsF)CCc3qqq!A#vY_s"Aaaa1fIOc$9BQQQ!V9s?Aaaa1fIOqA
(AGAJ#2:
6
6
6C9;a!eR!a%ZQSVWZ[V[Q[]_bcfgbg]g9g6C1Q3KQQQ!Vc!!!QqS&k3qqq!A#v;qqq-***+c1C7C1R6	Nqqq-!+.Q../#5;C1R6	NC2JJr   
detections
iou_threshc           
         | j         d         dk    r| S | t          j        | dddf                             }|j         d         }t          j        |dddf         |dddf         z
  dd          t          j        |dddf         |dddf         z
  dd          z  }g }t          j        |t
                    }t          |          D ]}||         r||ddf         \  }}	}
}|g}t          |dz   |          D ]}||         r||ddf         \  }}}}t          d	t          |
|          t          ||          z
            }t          d	t          ||          t          |	|          z
            }||z  }||         ||         z   |z
  }|dk    r#||z  |k    r|	                    |           d
||<   d
||<   ||         }|ddddf         }|
                                }t          j        |d                   }|dk    r-|ddddf         |z  
                    d          |z  |dd<   |	                    |           |rt          j        |d          nt          j        dt          j                  S )uU   MP weighted NMS — kept boxes are score-weighted averages of overlapping detections.r   Nr   r   r   r	   rT  r
   r   Tr   rX  rl  )r   r[  argsortrm  r  boolr   r   r  rA  r  copyr`  rp  r^  )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    s   abj*QQQU"3!3445D
1AGDAJaaad+Q55QQQT
TRSRSRSUVRVZ@WYZ\`8a8aaED8AT"""D1XX  7 	!!QqS&\S#sC	q1ua 
	 
	AAw !%a1fCc3S#c3--#c3--788BS#c3--#c3--788BGE!HuQx'%/EqyyUU]Z77  ###QQy/QQQ2X$$A::"111crc6?R/44!4<<vEF3B3KF%)R28Dq!!!!rxrz/R/R/RRr   	detectionimage_wimage_hc                    | dd         \  }}}}| dt           dz  z   dz            |z  }| dt           dz  z   dz            |z  }| dt          dz  z   dz            |z  }	| dt          dz  z   dz            |z  }
t          t          j        ||
z
  |	|z
            z
  }t          ||z   dz  |z            t          ||z   dz  |z            t          ||z
  |z  t          z            t          ||z
  |z  t          z            t          |          fS )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s^D$d	1(1,,q0	1G	;B	1(1,,q0	1G	;B	1)A--1	2W	<B	1)A--1	2W	<B"TZRb%A%AAE4$;#%/004$;#%/004$;'),==>>4$;'),==>>%LL	 r   	image_chwsrc_xsrc_ypadding_modec                 n   t          | j        d                   t          | j        d                   }}t          j        d|z  dz   |z  dz
  d|z  dz   |z  dz
  gd                              d          }t          j        |                     d          |dd|	                              d          S )
z;Bilinear-sample image_chw at corner-aligned (src_x, src_y).r   r   g       @r   r   r   r:  F)r<  r=  r   )r   r   r   r`  	unsqueezer   grid_samplesqueeze)r  r  r  r   r   r   grids          r   _sample_warpr&    s    yr"##S)<%=%=qA;us*a/#5us*a/#57<>@ @ @@I	! 	=,,Q//J',<I I IIPQRTr   rd  re  widthheightr  output_sizec                 \   ||z  ||z  }}t          j        |          t          j        |          }
}	t          j        || j        | j                  |dz  z
  }t          j        ||d          \  }}|||z  |	z  z   ||z  |
z  z
  }|||z  |
z  z   ||z  |	z  z   }t          | ||d          S )uR   Rotated rect → output_size² with BORDER_REPLICATE. image_chw must be in [0, 1].r   r   r   rU  rV  border)	r  cossinr   r]  r   r   r\  r&  )r  rd  re  r'  r(  r  r)  s_xs_ycos_asin_ar]  v_gridu_gridr  r  s                   r   _warp_face_cropr5    s     {"F[$8C8E??DHUOO5E\+Y_YEUVVVYdgjYjjF^FFTBBBNFF#%%u(<<E#%%u(<<E	5%:::r   image_chw_rawtargetc                    t          | j        d                   t          | j        d                   }}t          t          ||                    }|dz  |dz  }}||z  }t	          j        || j        | j                  |dz  z
  }t	          j        ||d          \  }	}
t          | ||
|z  z   ||	|z  z   d          }|dz  d	z
  |||fS )
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   r+  rU  rV  r  g     _@r   )
r   r   r  r   r   r]  r   r   r\  r&  )r6  r7  r   r   sub_rect_sizesub_rect_cxsub_rect_cyr   r]  r3  r4  r~  s               r   _blazeface_input_warpr<    s     }"1%&&M,?,B(C(CqA#a))$$M 3wCKA\&(;MDXYYY\beh\hhF^FFTBBBNFF
}kFQJ&>fWXj@XZa
b
bC%K3[-GGr   c                        e Zd ZdZddef fdZedfdeej	                 de
d	e
fd
Zdefdeej	                 dede
deee                  fdZ xZS )FaceLandmarkeruG  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.
    Nshortdetector_variantc                    t                                                       t          t          d                    |          }|| _         ||||          | _        t          |||          | _        t          |||          | _
        |                     dt          j        t          t          j                  d           d S )N)r?  fullr   _bs_idxrT  F)
persistent)r   r   r   r  getr@  detectorr  meshr  blendshapesregister_bufferr   tensorrV   long)r   r   r   r   r@  det_clsr   s         r   r   zFaceLandmarker.__init__5  s    %/ABBFFGWXX 0vUzRRRF%JOOO	*&R\]]]Y5Fej(Y(Y(Yfklllllr   r   images_rgb_uint8rj  r  c                    |sg g g g fS | j         j        j        j        | j         j        j        j        c| j        dk    rt          t          fnt          t          f\  }d |D             }t          t          |                    dk    rt          j        t          j        |d                                                                      dd                                          fdt'          j        d                   D             }nfd	|D             }fd
|D             }d |D             }d |D             }	|                      t          j        |d                    \  }
}|
                                                                                                |                                                                                                }}g }t'          t          |                    D ]S} |||         ||         |          }|                    |j        d         dk    rt3          ||          n|           T||	||fS )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  c                 F    g | ]}t          |j        d d                   S )Nr   )r  r   )r   imgs     r   
<listcomp>z5FaceLandmarker.run_detector_batch.<locals>.<listcomp>M  s*    BBB#sy!}%%BBBr   r	   r   rX  r   c                      g | ]
}|         S r&  r&  )r   bi	batch_chws     r   rQ  z5FaceLandmarker.run_detector_batch.<locals>.<listcomp>P  s    JJJ"	"JJJr   c                     g | ]P}t          j        |                                                            d d                                          QS )r   rR  )r   
from_numpytomovedimr  )r   rP  r   r   s     r   rQ  z5FaceLandmarker.run_detector_batch.<locals>.<listcomp>R  sQ    yyyad(--00??GGBOOZZ\\yyyr   c                 0    g | ]}t          |          S r&  )r<  )r   img_rawdet_input_sizes     r   rQ  z5FaceLandmarker.run_detector_batch.<locals>.<listcomp>T  s$    XXXG&w??XXXr   c                     g | ]
}|d          S )r   r&  r   r|  s     r   rQ  z5FaceLandmarker.run_detector_batch.<locals>.<listcomp>U  s    )))aQqT)))r   c                 <    g | ]}|d          |d         |d         fS )r	   r   r   r&  r^  s     r   rQ  z5FaceLandmarker.run_detector_batch.<locals>.<listcomp>V  s+    777AadAaD!A$'777r   r   rj  )r  )rF  r   weightr   r   r@  _BF_FR_INPUT_SIZEr  r  r  rD  r>  r   rW  r[  r`  rX  rY  r  r   r   r  cpunumpyrA  r  )r   rM  rj  r  	decode_fnsizesimg_rawswarps	det_crops	sub_rectsregs_bcls_bregs_npcls_np	per_framebdecodedrU  r\  r   r   s                    @@@@r   run_detector_batchz!FaceLandmarker.run_detector_batch?  so   
   	"r2r>!*18$-:L:S:Y(,(=(G(G '89U%V%V+9;L*M 	"	 CB1ABBBs5zz??a(2B)K)K)KLLOOPVX]^^ffgikmnnyy{{IJJJJioa6H0I0IJJJHHyyyyyhxyyyHXXXXxXXX))5)))	77777	ek)&C&C&CDD ,,..,,..44668I8I8K8K8Q8Q8S8S	s+,,-- 	q 	qAi
F1ILQQQGgm\]N^abNbNb]7zJJJJhoppppE944r   r	   	num_facesr   c                 	   |                      ||          \  }}}}t          |          D ]\  }}	|	j        d         dk    r||         \  }
}}||         \  }}|
|dz  z
  ||dz  z
  }}|||	dddddf         z  z   |z  |	dddddf<   |||	dddddf         z  z   |z  |	dddddf<   |dk    r|	dt          |                   ||<   g }g }t          |          D ]\  }}|j        d         dk    r||         \  }}||         dz  }|D ]u}t	          |||          \  }
}}}}|                    t          ||
||||t                               |                    |t          |d                   |
||||f           vd	 t          t          |                    D             }|s|S |                     t          j        |d
                    \  }}|                     |dd| j        ddf                   }t          j        d |D             |j        |j                  }|                    d
          \  }}} }!}"}#dt          z  }$|d         t          dz  z
  }%|d         t          dz  z
  }&t          j        |dddf         |%| |$z  |"z  dddf         z  z   |&|!|$z  |#z  dddf         z  z
  |dddf         |%| |$z  |#z  dddf         z  z   |&|!|$z  |"z  dddf         z  z   gd
          }'|'                                                                                                }(|                                                                                                })|                                                                                                }*|                                                                                                }+t          |          D ]\  },^}}-}.|(|,         }/|/                    d          |/                    d          }1}0||                             t1          j        |0d         |0d         |1d         |1d         gt0          j                  t7          t9          t:          |+|,                                                             |/|)|,         t          |*|,                   |-d           |S )un  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).
        r`  r   r   Nr   r   r	   g     o@c                     g | ]}g S r&  r&  )r   r   s     r   rQ  z/FaceLandmarker.detect_batch.<locals>.<listcomp>  s    $N$N$NAR$N$N$Nr   r   c           
      v    g | ]6\  }}}}}}}||||t          j        |          t          j        |          f7S r&  )r  r-  r.  )r   _b_srd  re  r|  r}  r   s           r   rQ  z/FaceLandmarker.detect_batch.<locals>.<listcomp>  sE    ccc:S2r2r1aQRb"aDHQKK!5cccr   r   r   ).r   ).r	   r   rT  )	bbox_xyxyrH  landmarks_xylandmarks_3dr  score)rr  r@  r   r   r  rA  r5  _FM_INPUT_SIZEr  r   rD  rG  r   r`  rH  rC  rJ  r   r   unbindrc  rd  r  r   r[  arrayr^  r   zipr   tolist)2r   rM  rs  rj  rg  rj  rf  per_frame_detsrp  rq  rd  re  r;  r   r   sx0sy0face_params
mesh_cropsr  img_for_meshdetr|  r}  r  resultslmks_canon_b
presence_bbs_out_bparams_trv  rw  r  hsr1  r2  invuv	lmks_xy_t
lmks_xy_nplmks_canon_nppresence_npbs_npr   r|  r   lmks_xymnmxs2                                                     r   detect_batchzFaceLandmarker.detect_batch`  sp    6:5L5L< 6M 6
 6
2)UN $N33 		> 		>JAw}Q1$$$Q<LBD8DAqD3JTCZC"%wqqq!Bq&y/A(A"AQ!FGAAAqAvI"%wqqq!Bq&y/A(A"AQ!FGAAAqAvI1}}$+,<c)nn,<$=q! SU#%
 00 	M 	MGAtz!}!!8DAq#A;.L M M&=c1a&H&H#B1e!!/,B1eUc"d"deee""AuSW~~r2q!U#KLLLLM
 %O$Ns;K7L7L1M1M$N$N$N 	N#'99U[-K-K-K#L#L j##LDL"1"1D$EFF <ccWbccc&l.@
 
 
 *2Q)?)?&S"b%N" >C#77 >C#77K4L1S5 0!!!T':::Q"s(UBRTUTUTUW[T[A\=\\4L1S5 0!!!T':::Q"s(UBRTUTUTUW[T[A\=\\!
   	
 __&&**,,2244
$**,,002288:: &&((,,..4466  $$&&,,..!*;!7!7 
	 
	A~51 mG[[^^W[[^^BAJXr!ubeRUBqE&B"*UUU#C(8%(//:K:K$L$LMM ' -a 0!+a.11      r   )NNNr?  )r   r   r   r   strr   _BF_MIN_SCOREr   r[  ndarrayr  rr  r   r   r  r   r   s   @r   r>  r>  .  s         m mSV m m m m m m 2?/25 54
3C 5).5',5 5 5 5B QR+8I IT"*-= I# I#(I=A$t*=MI I I I I I I Ir   r>  )r   )Qr   r  	functoolsr   typingr   r   rd  r[  r   torch.nn.functionalr   
functionalr   scipy.specialr   r   rV   r   __annotations__r   r  r  r  r  r  r  r  r  r  rr  r  r  rb  rZ  rF  rq  rn  r}  r  r  r  r  r  r   r   Moduler   r   r  r-  r?  r/  r2  r  r  r  rg  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r&  r5  r<  r>  r&  r   r   <module>r     s  @ @ @                                           & 5c?   % %S/   "        ;.         VF VC V V V V V V   D D D D DRY D D D$         	      JK K K K Kbi K K K4    % 7  o&o& 06 0c 0# 0& 0 0 0 08  8  8  8  8  8  8  8 v 1Rrz R R R R 8E RZ  /4IK   ,   ^ ^ ^ ^ ^BI ^ ^ ^*    ry   @      
M M M M MBI M M M. 1  1  1  1  1bi  1  1  1F 1BJ    . -: "* bj $)>@j   (!S !Sbj !Se !Sbj !S !S !S !SHrz C # RWX]_dfkmrtyXyRz     TF T6 T& TPS TX^ T T T T 6D	; 	;v 	;5 	;e 	;E 	;SX 	; 	;/2	;HN	; 	; 	; 	; @N H H H HRWX^`eglnsXsRt H H H H"{ { { { {RY { { { { {r   