
    3jЉ                     Z   S SK r S SKrS SKrS SKrS SKrS SKrS SKJr  S SK	J
r
  S SKJrJr  S SKJr  S rS r " S S	5      r " S
 S\R&                  5      r " S S\R&                  5      rS r " S S\R&                  5      r " S S\R&                  5      r " S S\5      rS\4S jrg)    N)tqdm)override)ComfyExtensionio)LotusConditioningc                 2   [         R                  " U [         R                  S9n[         R                  " U[         R                  S9n[        U5      S:  a  US   US   -   S-  nUS   S:  a  US   S:  a  [	        US   US   5      OSn[         R
                  " USUSS9n[         R
                  " USU5      n[         R                  " / S	Q5      n[         R                  " / S
Q5      nUR                  5       UR                  5       pX&   X'   X6   X'   Xp2X#4$ )a  Insert neck keypoint and remap from MMPose to OpenPose ordering.

Returns (kp, sc) where kp has shape (134, 2) and sc has shape (134,).
Layout:
  0-17   body  (18 kp, OpenPose order)
  18-23  feet  (6 kp)
  24-91  face  (68 kp)
  92-112 right hand (21 kp)
  113-133 left hand (21 kp)
dtype            333333?r   axis)r   r      
      	                  r            )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )nparrayfloat32lenmininsertcopy)
kp_rawsc_rawkpscneck
neck_score
mmpose_idxopenpose_idxtmp_kptmp_scs
             9/home/wildlama/comfy/ComfyUI/comfy_extras/nodes_sdpose.py_preprocess_keypointsr0      s     
&

	+B	&

	+B
2w"}11"*,Q%#+"Q%#+SA1&1
YYr2t!,YYr2z*xx WX
xx [\BGGI!~!~B6M    c                    S n/ n[        [        U 5      5       H  n/ n[        X   X   5       H  u  p[        X5      u  p[        R
                  " U
SS U
SS/   /SS9n[        R
                  " USS USS/   /SS9nUR                  U" U
SS USS 5      U" U
SS USS 5      U" X5      U" U
SS	 USS	 5      U" U
S	S
 US	S
 5      S.5        M     UR                  X2US.5        M     U$ )a  Convert raw keypoint lists to a list of OpenPose-style frame dicts.

Each frame dict contains:
  canvas_width, canvas_height, people: list of person dicts with keys:
    pose_keypoints_2d       - 18 body kp  as flat [x,y,score,...] (absolute pixels)
    foot_keypoints_2d       -  6 foot kp  as flat [x,y,score,...] (absolute pixels)
    face_keypoints_2d       - 70 face kp  as flat [x,y,score,...] (absolute pixels)
                               indices 0-67: 68 face landmarks
                               index  68:    right eye (body[14])
                               index  69:    left  eye (body[15])
    hand_right_keypoints_2d - 21 right-hand kp (absolute pixels)
    hand_left_keypoints_2d  - 21 left-hand  kp (absolute pixels)
c                     [         R                  " U S S 2S4   U S S 2S4   U/SS9R                  5       R                  5       $ )Nr   r   r   )r   stackflattentolist)kp_slicesc_slices     r/   _flatten%_to_openpose_frames.<locals>._flatten6   s<    xx!Q$!Q$BKSSU\\^^r1      \   r   r   r   r      q      )pose_keypoints_2dfoot_keypoints_2dface_keypoints_2dhand_right_keypoints_2dhand_left_keypoints_2d)canvas_widthcanvas_heightpeople)ranger!   zipr0   r   concatenateappend)all_keypoints
all_scoresheightwidthr9   framesimg_idxrG   r%   r&   r'   r(   face_kpface_scs                 r/   _to_openpose_framesrT   (   s    _ F]+,!-"8*:MNNF*6:FBnnbBiRH%>QGGnnbBiRH%>QGGMM+3BqH1R+I+3Br"I2b	+J+3G+H+3Br#J2c
+K+3Bs3KC+M  O 	uQWXY - Mr1   c                   t    \ rS rSrSrS r\S 5       r\SS j5       r\S 5       r	\SS j5       r
  SS	 jrS
rg)KeypointDrawL   zH
Pose keypoint drawing class that supports both numpy and cv2 backends.
c                     SS K nXl        SS/SS/SS/SS/SS/SS/SS/SS	/SS
/S
S/SS/SS/SS/SS/SS/SS/SS/SS/SS/SS//U l        SS/SS/SS/SS/SS/SS	/SS
/S
S/SS/SS/SS/SS//U l        SS/SS/SS/SS/SS//U l        / SQ/ SQ/ SQ/ SQ/ SQ/ SQ/ SQ/ SQ/ SQ/ SQ/ S Q/ S!Q/ S"Q/ S#Q/ S$Q/ S%Q/ S&Q/ S'Q/U l        g ! [         a	    X l         Nf = f)(Nr   r   r   r   r   r   r   r   r   r   r      r   r   r   r   r   r   r=         )   r   r   )r\   U   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\   )r^   r   r\   )r\   r   r\   )r\   r   r^   )r\   r   r]   )cv2drawImportError
hand_edgesbody_limbSeq
head_edgescolors)selfr`   s     r/   __init__KeypointDraw.__init__P   s`   	I FQFQFQFFQFQFQFFQGb"XBxGb"XBx"bGb"XBx"b
 FQFQFQFQFQFQFQGHq"gBx"b
 FQGb"X2wR
 }m]+|]M<l=-	
1  	I	s   
C C! C!c                 l   Uu  pVU R                   SS u  px[        [        R                  " U5      5      n	[	        SXi-
  5      [        XvU	-   S-   5      p[	        SXY-
  5      [        XU	-   S-   5      pX::  d  X::  a  g[        R                  X2X24   u  pX-
  S-  X-
  S-  -   US-  :*  nX0X2X24   U'   g)z7Draw a filled circle using NumPy vectorized operations.Nr   r   r   )shapeintr   ceilmaxr"   ogrid)	canvas_npcenterradiuscolorkwargscxcyhw
radius_inty_miny_maxx_minx_maxyxmasks                    r/   circleKeypointDraw.circles   s     r")
1bo.AJ7J0Ku1bo.AJ7J0Ku>U^xxU[01{afq[(FAI549%+u{*+D1r1   c           	         / UQUQ7u  pgpU R                   SS u  p[        X-
  5      [        X-
  5      pXh:  a  SOSXy:  a  SOSpX-
  Xg/ 4u  nnnn UR                  UU45        UU:X  a  UU	:X  a  O(SU-  nUU* :  a
  UU-
  UU-   nnUU:  a
  UU-   UU-   nnMH  US:  a  US-  S-   [        [        R
                  " US-  S-   5      5      nnU H  u  nn[        SUU-
  5      [        U
UU-   S-   5      [        SUU-
  5      [        UUU-   S-   5      4u  nnnnUU:  d  MS  UU:  d  M[  [        R                  UU2UU24   u  nnX0UU2UU24   UU-
  S-  UU-
  S-  -   US-  :*  '   M     g[        R                  " U5      nUSS2S4   S:  USS2S4   U
:  -  USS2S4   S:  -  USS2S4   U:  -  nUU   =n R                  (       a  X0U SS2S4   U SS2S4   4'   gg)z<Draw line using Bresenham's algorithm with NumPy operations.Nr   r   g       @      ?r   )rk   absrK   rl   r   rm   rn   r"   ro   r   size)!rp   pt1pt2rs   	thicknessrt   x0y0x1y1rw   rx   dxdysxsyerrr   r~   line_pointse2rr   ry   pxpyrz   r{   r|   r}   yyxxvalidvalid_pointss!                                    r/   lineKeypointDraw.line   s    $#r"RWs27|Bw!Brw!BB!#""!4Q;1v&Bw17SBRCxr1r6QBwr1r6Q  q="+c/S!8#bggySVZ]F]>^:_JF%B-0BO-Dc!RR\__`M`Facfghjloyjycz|  AB  DF  IS  DS  VW  DW  }X  .X*ueU5=UU]XXeEk5;&>?FBdieEk5;67b1RRS|8SW]_`W`8`a	 & ((;/K A&!+AqD0AA0EF+VWYZVZJ[_`J`aepqrtuquevyzez{E +E 2288DI,q!t,l1a4.@@A 9r1   c           	      x   [        U5      S:  a  g[        R                  " U[        R                  S9nU R                  SS u  pE[        SUSS2S4   R                  5       5      [        XASS2S4   R                  5       S-   5      [        SUSS2S4   R                  5       5      [        XQSS2S4   R                  5       S-   5      4u  pgpXv::  d  X::  a  g[        R                  Xg2X24   u  p[        R                  " Xv-
  X-
  4[        S9n[        [        U5      5       H  nX   XS-   [        U5      -     pUS   US   nnUU:X  a  M+  UU:  a  XUS   US   4u  pnnU
U:  U
U:  -  =nR                  5       (       d  Mb  UUXS   U
U-
  US   US   -
  -  UU-
  -  -   :  -  -  nM     X Xg2X24   U'   g)z1Fill polygon using vectorized scanline algorithm.r   Nr	   r   r   r   )r!   r   r   int32rk   rn   r"   mgridzerosboolrH   any)rp   ptsrs   rt   rw   rx   rz   r{   r|   r}   r   r   r   ip1p2r   y2	edge_masks                      r/   fillConvexPolyKeypointDraw.fillConvexPoly   s     s8a<hhs"((+r"%(C1IMMO%<c!AY]]_WXEX>Y[^_`befgijfjbkbobobq[rtwxy  @A  CD  @D  |E  |I  |I  |K  NO  |O  uP  &P"e>U^%+u{23xx6dCs3xAVSa%3s8!34UBqEBRxBw!#A1!5B"$(rBw!77I<<>>I!uRBqEBqEM/JbSUg/V'V!VWWD ! 5:%+u{*+D1r1   c                    US   S-   US   S-   4nUS-  nX4:  a  XCpCUS:  a  US-   US-   pCUS:  a  M  US:  a  US-
  US-
  p4US:  a  M  XC-
  S:  a  Su  p4[         R                  " U5      n[         R                  " U5      [         R                  " U5      p/ n
[	        X4U-   U5       H  n[         R                  " [        X5      5      nUS   [         R                  " U5      -  US   [         R                  " U5      -  pU
R                  [        [        U S   X-  -   X-  -
  5      5      [        [        U S   X-  -   X-  -   5      5      /5        M     / [        S5      [        S5      4nnU
 H)  n[        U5      =nU:w  d  M  UR                  U5        UnM+     [        U5      S:  a  U$ U S   U S   /U S   U S   //$ )z*Python implementation of cv2.ellipse2Poly.r   r   r   h  )r   r   inf)mathradianscossinrH   r"   rK   rl   roundfloattupler!   )rq   axesangle	arc_startarc_enddeltart   	angle_radalphabetar   r   	theta_radr   r~   
unique_ptsprev_ptptpt_tuples                      r/   ellipse2PolyKeypointDraw.ellipse2Poly   s    Q#tAw}-!(w!m!*S'C-w !mm!(3	CY m$!'ILL'	hhy)488I+>tyE/59AS_5I7TXXi00$q'DHHY<O2OqJJE&)ai"7!("BCDc%PVWXPY\]\dPdghgpPpJqFrst :
 !5<u">G
B!"I%'1!!"%" 
 !_q0zfq	6!97MPVWXPY[abc[dOe6ffr1   Nc                    UR                   u  pnU(       d  U(       Ga  [        U5      S:  Ga  Sn/ nU(       a  UU R                  -  nOU[        U R                  5      -  nU(       a  UU R                  -  n[	        U5       GH|  u  nnUS   S-
  US   S-
  nnUS:  d  US:  a  M%  Ub  UU   U:  d	  UU   U:  a  M<  UU   S   UU   S   /nUU   S   UU   S   /nUS   US   -   S-  US   US   -   S-  nn[
        R                  " US   US   -
  S-  US   US   -
  S-  -   5      nUS:  a  M  [
        R                  " [
        R                  " US   US   -
  US   US   -
  5      5      nU R                  R                  [        U5      [        U5      4[        US-  5      U
4[        U5      SSS5      nU R                  R                  UUU R                  UU-   [        U R                  5      -     5        GM     U(       d  U(       a  [        U5      S:  a  1 SknSn[        S5       H  nU(       d  UU;   a  M  U(       d  UU;  a  UU:w  a  M'  Ub  UU   U:  a  M5  [        UU   S   5      [        UU   S   5      nnSUs=::  a  U:  d  Mf  O  Mj  SUs=::  a  U:  d  My  O  M}  U R                  R                  UUU4SU R                  U[        U R                  5      -     SS	9  M     U(       a  [        U5      S
:  a  [        SS
5       H  nUb  UU   U:  a  M  [        UU   S   5      [        UU   S   5      nnSUs=::  a  U:  d  MB  O  MF  SUs=::  a  U:  d  MU  O  MY  U R                  R                  UUU4SU R                  U[        U R                  5      -     SS	9  M     U	(       Ga'  [        U5      S:  Ga  Sn [	        U R                   5       GHc  u  n!n"SU"S   -   SU"S   -   nnUb  UU   U:  d	  UU   U:  a  M.  [        UU   S   5      [        UU   S   5      n$n#[        UU   S   5      [        UU   S   5      n&n%U#U :  d  Mz  U$U :  d  M  U%U :  d  M  U&U :  d  M  SU#s=::  a  U:  d  M  O  M  SU$s=::  a  U:  d  M  O  M  SU%s=::  a  U:  d  M  O  M  SU&s=::  a  U:  d  M  O  M  ["        R$                  " U!['        [        U R                   5      5      -  SS5      u  n'n(n)[        U'S-  5      [        U(S-  5      [        U)S-  5      4n*U R                  R)                  UU#U$4U%U&4U*SS	9  GMf     [        SS5       H  nUb  UU   U:  a  M  [        UU   S   5      [        UU   S   5      nnUU :  d  M;  UU :  d  MC  SUs=::  a  U:  d  MR  O  MV  SUs=::  a  U:  d  Me  O  Mi  U R                  R                  UUU4SSSS	9  M     U	(       Ga6  [        U5      S:  Ga&  Sn [	        U R                   5       GHc  u  n!n"SU"S   -   SU"S   -   nnUb  UU   U:  d	  UU   U:  a  M.  [        UU   S   5      [        UU   S   5      n$n#[        UU   S   5      [        UU   S   5      n&n%U#U :  d  Mz  U$U :  d  M  U%U :  d  M  U&U :  d  M  SU#s=::  a  U:  d  M  O  M  SU$s=::  a  U:  d  M  O  M  SU%s=::  a  U:  d  M  O  M  SU&s=::  a  U:  d  M  O  M  ["        R$                  " U!['        [        U R                   5      5      -  SS5      u  n'n(n)[        U'S-  5      [        U(S-  5      [        U)S-  5      4n*U R                  R)                  UU#U$4U%U&4U*SS	9  GMf     [        SS5       H  nUb  U[        U5      :  a  UU   U:  a  M   [        UU   S   5      [        UU   S   5      nnUU :  d  MJ  UU :  d  MR  SUs=::  a  U:  d  Ma  O  Me  SUs=::  a  U:  d  Mt  O  Mx  U R                  R                  UUU4SSSS	9  M     U(       a  [        U5      S:  a  Sn [        S
S5       H  nUb  UU   U:  a  M  [        UU   S   5      [        UU   S   5      nnUU :  d  M;  UU :  d  MC  SUs=::  a  U:  d  MR  O  MV  SUs=::  a  U:  d  Me  O  Mi  U R                  R                  UUU4USSS	9  M     U$ )ab  
Draw wholebody keypoints (134 keypoints after processing) in DWPose style.

Expected keypoint format (after neck insertion and remapping):
- Body: 0-17 (18 keypoints in OpenPose format, neck at index 1)
- Foot: 18-23 (6 keypoints)
- Face: 24-91 (68 landmarks)
- Right hand: 92-112 (21 keypoints)
- Left hand: 113-133 (21 keypoints)

Args:
    canvas: The canvas to draw on (numpy array)
    keypoints: Array of keypoint coordinates
    scores: Optional confidence scores for each keypoint
    threshold: Minimum confidence threshold for drawing keypoints

Returns:
    canvas: The canvas with keypoints drawn
r=   r   r   r   r   >   r   r   r   r   r   r   r   )r   r;   r>   {Gz?r<         ?r\   r_   r?   )r\   r\   r\   )rk   r!   rd   re   	enumerater   sqrtdegreesatan2ra   r   rl   r   rf   rH   r   rc   colorsys
hsv_to_rgbr   r   )+rg   canvas	keypointsscores	threshold	draw_body	draw_head	draw_feet	draw_face
draw_handsstick_widthface_point_sizeHWCcolorIndexOffsetedgesr   limbidx1idx2YXmXmYlengthr   polygonhead_keypoints
neck_pointr   r~   epsieedger   r   x2r   rgbrs   s+                                              r/   draw_wholebody_keypoints%KeypointDraw.draw_wholebody_keypoints   s@   * ,,a I"(< E*** C(9(9$:: ($U+4!!Wq[$q'A+d2:%d|i/6$<)3K t_Q'4);<t_Q'4);<A$1+*QqTAaD[A,=BAaD1Q4KA#51!8J#JKA:TZZ!qtQqTAaD[%IJ))00#b'3r71Cc&ST*oWbEcehineoqrtwyz{		(($++qK[G[_bcgcncn_oFo:pq/ ,4 I"(<0NJ2Y Q.%8 Qn%<j%&)i*?9Q<?+S1a-A1:A::!q*1**II$$VaVQADKKHXDX8Yeg$h  Y2-2r]%&)i*?9Q<?+S1a-A1:A::!q*1**II$$VaVQADKKHXDX8Yeg$h # #i.C/C%doo6D$q'\2Q<d%d|i/6$<)3K Yt_Q/0#ioa6H2IBYt_Q/0#ioa6H2IB8SR#X"s(B{{{qB{{{qB{{{qB{QR{{"*"5"5b5T__AU;V6VX[]`"a1a!$QWs1s7|SS\ J		vBx"b5TUV 7" 2s^%&)i*?9Q<?+S1a-A1s7q3w1:A::!q*1**II$$VaVQr$R $ #i.C/C%doo6D 47]C$q'Md%d|i/6$<)3K Yt_Q/0#ioa6H2IBYt_Q/0#ioa6H2IB8SR#X"s(B{{{qB{{{qB{{{qB{QR{{"*"5"5b5T__AU;V6VX[]`"a1a!$QWs1s7|SS\ J		vBx"b5TUV 7" 3_%!c&k/fQi)>S9Q<?+S1a-A1s7q3w1:A::!q*1**II$$VaVQr$R % Y2-C2r]%&)i*?9Q<?+S1a-A1s7q3w1:A::!q*1**II$$VaV_oac$d # r1   )rd   rf   ra   rc   re   )r   )	Nr   TTTTTr   r   )__name__
__module____qualname____firstlineno____doc__rh   staticmethodr   r   r   r   r   __static_attributes__ r1   r/   rV   rV   L   su    !
F : :" J J> : :2 g g: RU RSRr1   rV   c                   P    \ rS rSr\S 5       r\S\R                  4S j5       rSr	g)SDPoseDrawKeypointsiq  c                    [         R                  " SSS/ SQ[         R                  " S5      R                  S5      [         R                  R                  SSS	9[         R                  R                  S
SS	9[         R                  R                  SSS	9[         R                  R                  SSS	9[         R
                  R                  SSSSSS9[         R
                  R                  SSSSSS9[         R                  R                  SSSSSS9[         R                  R                  SSS	9/	[         R                  R                  5       /S9$ )Nr   zSDPose Draw Keypointsimage/detection)openposepose detectionpreprocessorr   posePOSE_KEYPOINTr   r   T)defaultr   r   r   Fr   r   r   r   r  r"   rn   stepr   r   score_thresholdr   g        r   r   r   node_iddisplay_namecategorysearch_aliasesinputsoutputs)	r   SchemaCustomInputBooleanIntFloatImageOutputclss    r/   define_schema!SDPoseDrawKeypoints.define_schemar  s   yy)0&^		/*00=

  d ;

  t <

  d ;

  e <]A1"1M.qbqQ0#3CVZ[

  d ;
 !!
 	
r1   returnc
                 L   U(       d7  [         R                  " [        R                  " S[        R                  S95      $ US   S   n
US   S   nS nS n/ n[        5       n[        USS	9 GH  n[        R                  " XS
4[        R                  S9nUS    H  nU" US   S5      u  nnUR                  S5      nU(       a	  U" US5      OU" S5      u  nnU" US   S5      u  nnUS S US S nnU" US   S5      u  nnU" US   S5      u  nn[        R                  " UUUUU/SS9n[        R                  " UUUUU/SS9nUR                  UUUUX)UXCXgS9nM     UR                  U5        GM     [        U5      S:  a  [        R                  " U5      O[        R                  " US   S5      n [        R                   " U 5      R#                  [$        R&                  R)                  5       [$        R&                  R+                  5       S9S-  n![         R                  " U!5      $ )N)r   @   r  r   r	   r   rF   rE   c                     [         R                  " U [         R                  S9R                  US5      nUS S 2S S24   US S 2S4   4$ )Nr	   r   r   )r   r   r    reshape)flatnarrs      r/   _parse+SDPoseDrawKeypoints.execute.<locals>._parse  sB    ((4rzz2::1a@Cq"1"u:s1a4y((r1   c                     [         R                  " U S4[         R                  S9[         R                  " U [         R                  S94$ )Nr   r	   )r   r   r    )r   s    r/   _zeros+SDPoseDrawKeypoints.execute.<locals>._zeros  s/    88QF"**5rxx7TTTr1   zDrawing keypoints on framesdescr   rG   r@   r=   rA   r   rB   F   D   rC      rD   r   )r   r   r   r   r   r   r   r   r   )devicer
   g     o@)r   
NodeOutputtorchr   r    rV   r   r   uint8getrJ   r   rK   r!   r4   expand_dims
from_numpytocomfymodel_managementintermediate_deviceintermediate_dtype)"r  r   r   r   r   r   r   r   r  r   rN   rO   r"  r%  pose_outputsdrawerframer   personbody_kpbody_scfoot_rawfoot_kpfoot_scrR   rS   rhand_kprhand_sclhand_kplhand_scr'   r(   pose_outputs_npfinal_pose_outputs"                                     r/   executeSDPoseDrawKeypoints.execute  s0   ==^5==!QRR1o.1n-	)	U )*GHEXXva0AF/%+F3F,Gr%R!'!::&9:<DVHa%8&QR)!'%+F3F,Gr%R!'%,Sb\73B<'%+F3L,Mr%R"(%+F3K,Lr%R"(^^Wgw($SZ[\^^Wgw($SZ[\88B-'	' + 9  *& '+ I. 584E4I"((<0r~~^jkl^mopOq!,,_=@@))==?((;;= A ?AFG }}.//r1   r   N
r   r   r   r   classmethodr  r   r-  rG  r   r   r1   r/   r   r   q  sB    
 
, +0  KM  KX  KX +0 +0r1   r   c                   T    \ rS rSr\S 5       r\SS\R                  4S jj5       rSr	g)SDPoseKeypointExtractori  c                    [         R                  " SSS/ SQS[         R                  R                  S5      [         R                  R                  S5      [         R
                  R                  S5      [         R                  R                  S	S
SSSS9[         R                  R                  SSSSS9/[         R                  " S5      R                  SSS9/S9$ )NrL  zSDPose Keypoint Extractorr   )r   r   r   r   sdposezxExtract pose keypoints from images using the SDPose model: https://huggingface.co/Comfy-Org/SDPose/tree/main/checkpointsmodelvaeimage
batch_sizer   r   i'  r  bboxesTzZOptional bounding boxes for more accurate detections. Required for multi-person detection.)optionalforce_inputtooltipr  r   zHKeypoints in OpenPose frame format (canvas_width, canvas_height, people)rV  r  r	  r
  r  descriptionr  r  )
r   r  Modelr  Vaer  r  BoundingBoxr  r  r  s    r/   r  %SDPoseKeypointExtractor.define_schema  s    yy-4&` Sw'U#w'\21%aP$$X$  Yu$  v 		/*11+  HR1  S
 	
r1   Nr  c           
        ^)^*^+^,^-^. UR                   S   UR                   S   pv[        5       R                  5       R                  S   m*U)4S jnUR	                  5       m,SSU/00T,R
                  S'   [        UR                  R                  S5      (       d  [        S	5      eUR                  R                  R                  m+UR                   S   n	S m)[        T+R                  S   5      S
-  m.[        T+R                  S   5      S
-  m-U-U.4S jn
SS jnU)U*U+U,4S jn/ n/ n[        R                  R                  U	5      nUGb  [!        U["        5      (       d  U//nO[%        U5      S:X  a  S /U	-  n['        [)        U	5      SS9 GH  nUUUS-    nU(       a  U[+        U[%        U5      S-
  5         OS n/ n/ nU(       a  U H  n[-        S[        US   5      5      n[-        S[        US   5      5      n[+        U[        US   US   -   5      5      n[+        U[        US   US   -   5      5      nUU::  d  UU::  a  M}  US S 2UU2UU2S S 24   nU
" U5      u  nnnUR/                  U5      nU" U5      u  nn U" US   UUUU5      n!UR1                  U!5        UR1                  U S   5        M     OXU
" U5      u  n"nnUR/                  U"5      n#U" U#5      u  nn UR1                  U" US   UU5      5        UR1                  U S   5        UR1                  U5        UR1                  U5        UR3                  S5        GM     O['        [)        SX5      SS9 H  n$U
" UU$U$U-    5      u  n%nnUR/                  U%5      n&U" U&5      u  nn [5        UU 5       H2  u  n!n'UR1                  U" U!UU5      /5        UR1                  U'/5        M4     UR3                  [%        U5      5        M     [7        XXg5      n([8        R:                  " U(5      $ )Nr   c                 P   > U R                   S   S:X  a  U R                  5       mX4$ )Nr   i  )rk   clone)rw   hsptransformer_optionscaptured_feats      r/   output_patch5SDPoseKeypointExtractor.execute.<locals>.output_patch  s%    wwqzS  !	6Mr1   patchesoutput_block_patchrd  heatmap_headzThe provided model does not have a heatmap_head. Please use SDPose model from here https://huggingface.co/Comfy-Org/SDPose/tree/main/checkpoints.r   r   c                   > U R                   S   U R                   S   p!TU::  a  TU::  a  SOSnU R                  SSSS5      R                  5       n[        R                  R                  UTTUS	S
9nUR                  SSSS5      TU-  TU-  4$ )zPStretch BHWC images to (model_h, model_w), model expects no aspect preservation.r_  r`  areabilinearr   r   r   r   disabledupscale_methodcrop)rk   permuter   r4  utilscommon_upscale)imgsrw   rx   methodchwscaledmodel_hmodel_ws         r/   _resize_to_model9SDPoseKeypointExtractor.execute.<locals>._resize_to_model  s    ::b>4::b>q '1AVJF,,q!Q*002C[[//WgV\cm/nF>>!Q1-w{GaKGGr1   c                     [        U [        R                  5      (       a  U R                  5       O"[        R                  " U [        R
                  S9n U S   S:  nU S   U-  U-   U S'   U S   U-  U-   U S'   SX'   U $ )z>Remap keypoints from model space back to original image space.r	   ).r   r   ).r   r   )
isinstancer   ndarrayr$   r   r    )r'   scale_xscale_yoffset_xoffset_yinvalids         r/   _remap_keypoints9SDPoseKeypointExtractor.execute.<locals>._remap_keypoints  sx    (RZZ88bhhrQSQ[Q[>\Bj1nGFg-8BvJFg-8BvJBKIr1   c                    > Sm[         R                  R                  T[        R                  " U 5      SSSSTTU SSS9nT" T5      $ )zLRun one forward pass and return (keypoints_list, scores_list) for the batch.Nr   r   eulersimpleT)
noisestepscfgsampler_name	schedulerpositivenegativelatent_imagedisable_noisedisable_pbar)r4  sampler.  
zeros_like)latent_batch_re  contextheadmodel_clones     r/   _run_on_latent7SDPoseKeypointExtractor.execute.<locals>._run_on_latent  sW     !M##&&|4S$ 7)D $ A &&r1   zExtracting keypoints from cropsr'  r   r~   rO   rN   zExtracting keypoints)r   r   )rk   r   rG  resultrb  model_optionshasattrrO  diffusion_model
ValueErrorrj  rl   heatmap_sizer4  rs  ProgressBarr~  listr!   r   rH   r"   rn   encoderK   updaterI   rT   r   r-  )/r  rO  rP  rQ  rR  rS  rN   rO   rf  total_imagesr{  r  r  rL   rM   pbarrQ   img
img_bboxesimg_keypoints
img_scoresbboxr   r   r   r   rq  crop_resizedr   r   latent_cropkp_batchsc_batchr'   img_resized
latent_imgbatch_startbatch_resizedr  r(   openpose_framesre  r  r  r  ry  rz  s/                                            @@@@@@r/   rG  SDPoseKeypointExtractor.execute  s    BR#%--/66q9	 kkm<EH\_k^lGm;n!!"78u{{22NCC  q  r  r{{**77{{1~d''*+a/d''*+a/	H		' 	'" 
{{&&|4fd++!(V!,.l 3:[\GGaK0FLVCVq$ABRV
 "
 * CS	N3 CS	N3 T#Yg-F)GH T#Yh-G)HI8rRx$"1beRUA#56/?/E,b"&)jj&>-;K-H*(-hqk2r2rJ%,,R0"))(1+6! !+$ +;3*?'KR!$K!8J)7
)C&Hh!(()9(1+r2)NO%%hqk2$$]3!!*-AG ]L  $E!\$FMcd(8{;YcKc9d(e%r2"zz-8%3L%A"(!(H5FB!((*:2r2*F)GH%%rd+ 6 CM*  e .mW}}_--r1   r   NrI  r   r1   r/   rL  rL    s6    
 
& w.BMM w. w.r1   rL  c                 .   Uu  p4U R                  5       SS  XC4-  n[        R                  " USS9u  pg[        R                  " USS9u  pX-
  n
X-
  nU
S::  d  US::  a  / SQ$ X-  nX-  n[        R                  " XU-  -  5      n[        R                  " XU
-  -  5      nX-
  S-  nX-
  S-  n[        UU-
  S5      n[        UU-   U5      n[        USU-  -
  S5      n[        U	U-   U5      n[        U5      [        U5      [        U5      [        U5      /$ )Nr   r   r   )r   r   r   r   r   r   r   )r$   r   r"   rn   r   rl   )kp2dsscaleimage_shaperw   rx   
kp2ds_facemin_xmin_ymax_xmax_yinitial_widthinitial_heightinitial_areaexpanded_area	new_width
new_heightdelta_widthdelta_heightexpanded_min_xexpanded_max_xexpanded_min_yexpanded_max_ys                         r/   get_face_bboxesr  G  s+   DAab!QF*J66*1-LE66*1-LEMM]N^q0 1L (M)GHII=*HIJJ,1K/14L,a0N,a0N\!1115N-q1N^!4c.6I3~K^__r1   c                   P    \ rS rSr\S 5       r\S\R                  4S j5       rSr	g)SDPoseFaceBBoxesie  c                 8   [         R                  " SSS/ SQ[         R                  " S5      R                  S5      [         R                  R                  SSS	S
SSS9[         R
                  R                  SSSS9/[         R                  R                  SSS9/S9$ )Nr  zSDPose Face Bounding Boxesr   )z	face bboxzface bounding boxr  r   r  r   r  g      ?r   g      $@皙?z?Multiplier for the bounding box area around each detected face.r  r"   rn   r  rV  force_squareTzAExpand the shorter bbox axis so the crop region is always square.)r  rV  rS  zTFace bounding boxes per frame, compatible with SDPoseKeypointExtractor bboxes input.rW  r  )r   r  r  r  r  r  r\  r  r  s    r/   r  SDPoseFaceBBoxes.define_schemag  s    yy&5&R		/*00=w$S  [\  ]

    HK   L %%h  9O%  P
 	
r1   r  c           	         / nU GH  nUS   nUS   n/ nUS    GH  n	U	R                  S/ 5      n
U
(       d  M  [        R                  " U
[        R                  S9R	                  SS5      nUS S 2S S24   nU[        R                  " Xv/[        R                  S9-  n[        R
                  " [        R                  " S	[        R                  S9U/5      n[        XXg45      u  nnnnUU:  d  M  UU:  d  M  U(       a  UU-
  UU-
  nnUU:w  az  [        UU5      nUU-   S-  UU-   S-  nnUS-  n[        S
UU-
  5      n[        S
UU-
  5      n[        XU-   5      n[        UUU-   5      n[        S
UU-
  5      n[        S
UU-
  5      nUR                  UUUU-
  UU-
  S.5        GM     UR                  U5        GM     [        R                  " U5      $ )NrF   rE   rG   rB   r	   r   r   r   )r   r   r   )r   r~   rO   rN   )r0  r   r   r    r  vstackr   r  rn   r"   rK   r   r-  )r  r   r  r  
all_bboxesr:  rw   rx   frame_bboxesr;  	face_flatface_arrface_xykp_norm	kp_paddedr   r   r   r   bwbhsideru   rv   halfs                            r/   rG  SDPoseFaceBBoxes.executex  s   
Eo&An%AL/"JJ':B?	 88IRZZ@HHQO#ArrE?!BHHaV2::$FFIIrxxbjj'I7&ST	!0A6!JBB7rBw#!#b"r'B8#&r2;D&(2g!^b2g!^B#'19D!$QT	!2B!$QT	!2B!$QT	!2B!$QT	!2B!$QT	!2B!$QT	!2B ''brBGWY\^W^(_`5 *8 l+A D }}Z((r1   r   NrI  r   r1   r/   r  r  e  s3    
 
  $) $) $)r1   r  c                   T    \ rS rSr\S 5       r\SS\R                  4S jj5       rSr	g)CropByBBoxesi  c                    [         R                  " SSS/ SQS[         R                  R                  S5      [         R                  R                  SSS	9[         R
                  R                  S
SSSSSS9[         R
                  R                  SSSSSSS9[         R
                  R                  SSSSSSS9[         R                  R                  SSS/SSS9/[         R                  R                  SS9/S9$ ) Nr  zCrop By Bounding Boxeszimage/transform)rq  z	face cropz	bbox cropr  zbounding boxzTCrop and resize regions from the input image batch based on provided bounding boxes.rQ  rS  T)rU  output_widthi   r  i   r   zWidth each crop is resized to.r  output_heightzHeight each crop is resized to.paddingr   i   r   zGExtra padding in pixels added on each side of the bbox before cropping.keep_aspectstretchpadzfWhether to stretch the crop to fit the output size, or pad with black pixels to preserve aspect ratio.)optionsr  rV  z,All crops stacked into a single image batch.rW  rX  )r   r  r  r  r\  r  Combor  r  s    r/   r  CropByBBoxes.define_schema  s    yy"1&Unw'$$X4$@^crtRS]}~_crtRS]~Yqd  U^  _}y%6HR[  fN  O (VW
 	
r1   r  c                 d   UR                   S   nUR                   S   nUR                   S   n	UR                   S   n
[        U[        5      (       d  U//nO%[        U5      S:X  a  [        R
                  " U5      $ / n[        U5       GH  nU[        U[        U5      S-
  5         nU(       d  M(  X   R                  SSS5      R                  S5      n[        S U 5       5      n[        S U 5       5      n[        S U 5       5      n[        S U 5       5      nUS:  a;  [        SX-
  5      n[        SUU-
  5      n[        U	UU-   5      n[        UUU-   5      n[        SU5      [        U	U5      nn[        SU5      [        UU5      nnUU::  d  UU::  a  [        [        X5      S	-  5      n[        SU	U-
  S-  5      n[        S[        US
-  5      5      n[        U	UU-   5      n[        UUU-   5      nUU::  d  UU::  a=  UR                  [        R                  " SXX1R                  UR                   S95        GM  UUUU4u  nnnnUS S 2S S 2UU2UU24   nUS:X  a  UU-
  UU-
  nn[        UU-  UU-  5      n[        [#        UU-  5      5      n[        [#        UU-  5      5      n[$        R&                  R)                  UUUSSS9nUU-
  S-  nUU-
  S-  n [        R                  " SXX1R                  UR                   S9n!UU!S S 2S S 2U U U-   2UUU-   24'   O [$        R&                  R)                  UX4SSS9n!UR                  U!5        GM     U(       d  [        R
                  " U5      $ [        R*                  " USS9R                  SSSS5      n"[        R
                  " U"5      $ )Nr   r   r   r   c              3   >   #    U  H  n[        US    5      v   M     g7f)r   Nrl   .0r   s     r/   	<genexpr>'CropByBBoxes.execute.<locals>.<genexpr>       7,QS3[[,   c              3   >   #    U  H  n[        US    5      v   M     g7f)r~   Nr  r  s     r/   r  r    r  r  c              3   J   #    U  H  n[        US    US   -   5      v   M     g7f)r   rO   Nr  r  s     r/   r  r    s%     E1S3!G*,--   !#c              3   J   #    U  H  n[        US    US   -   5      v   M     g7f)r~   rN   Nr  r  s     r/   r  r    s%     E1S3!H+-..r  r   r  )r
   r,  r  rl  rn  ro  )dim)rk   r~  r  r!   r   r-  rH   r"   rr  	unsqueezern   rl   rK   r.  r   r
   r,  r   r4  rs  rt  cat)#r  rQ  rS  r  r  r  r  total_framesimg_himg_wnum_chcrops	frame_idxr  	frame_chwr   r   r   r   fallback_sizefb_x1fb_y1fb_x2fb_y2crop_chwcrop_hcrop_wr  scaled_wscaled_hrx  pad_leftpad_topresized
out_imagess#                                      r/   rG  CropByBBoxes.execute  s   {{1~AAQ&$''hZF[A==''|,I!#iVq"ABL(00Aq9CCAFI 7,77B7,77BEEEBEEEB{BL)BL)W-W-BZUBBBZUBB Rx28 #C$5$; <A 5!;<As53;/0E5=#89E5=#89E>Ue^LLQ|[f[foto{o{!|}!&ue!;BB Ar"ube!34He#!#b"r'L61=63IJuVe^45uVe^4533Hhagnx3y(H4:)H4:++aT_T_hmhthtuZ`1gg&88(8hCV:VVW++44X|kq  yC4  DLL!a -d ==''YYu!,44Q1a@
}}Z((r1   r   N)r  rI  r   r1   r/   r  r    s9    
 
( C)dfdqdq C) C)r1   r  c                   L    \ rS rSr\S\\\R                        4S j5       r	Sr
g)SDPoseExtensioni  r  c                 6   #    [         [        [        [        /$ 7fr  )rL  r   r  r  )rg   s    r/   get_node_listSDPoseExtension.get_node_list  s      $	
 	
s   r   N)r   r   r   r   r   r  typer   	ComfyNoder  r   r   r1   r/   r  r    s)    
T$r||*<%= 
 
r1   r  r  c                     #    [        5       $ 7fr  )r  r   r1   r/   comfy_entrypointr    s     s   )r.  comfy.utilsr4  comfy.model_managementnumpyr   r   r   r   typing_extensionsr   comfy_api.latestr   r   comfy_extras.nodes_lotusr   r0   rT   rV   r  r   rL  r  r  r  r  r  r   r1   r/   <module>r%     s           & / 66!Hc cJ	D0",, D0LM.bll M.``<8)r|| 8)vZ)2<< Z)z
n 
 r1   