+
    Ujb                       R t ^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RI	t
^ RIt]P                  P                  RR4       ]! ]4      P                  P!                  4       t]P$                  P'                  ^ ]! ]4      4       ^ RIHt ^ RIHt ^ RIHt ]R	,          t]R
,          R,          t]! R4      tR R ltR8tR9t R]3R R llt!R t"R t#R R lt$R R lt%R:t&R;t']
PP                  ! ]&R,          ]'R,          R.4      t)R<R R llt*R<R R llt+R=R R llt,R>R  R! llt-R?R" R# llt.R$ R% lt/R& R' lt0R( R) lt1R* R+ lt2R@R, R- llt3R. R/ lt4RAR0 R1 llt5R<R2 R3 llt6R4 R5 lt7R6 t8]9R78X  d
   ]8! 4        R# R# )Bu  Render 4 overlays for a dataset frame using the saved poses (no PnP round-trip).

Given a state npz that already carries scene_cam_pose / wrist_cam_pose / umi_pose (all
local→world 4x4 in the calib-board GridBoard frame, OpenCV camera convention), we drive
the render_core.Layer camera directly instead of re-detecting boards. Produces:

  A. <task>/f<N>_scene_umi.png       — UMI gripper rendered from scene camera
  B. <task>/f<N>_scene_calib.png     — scene calib board rendered from scene camera
  C. <task>/f<N>_wrist_calib.png     — scene calib board rendered from wrist camera
  D. <task>/f<N>_wrist_umi.png       — UMI gripper rendered from wrist camera, chained
                                       through a pre-calibrated wrist_cam→UMI transform.

The wrist_cam→UMI transform (constant, since the wrist camera is rigidly attached to the
UMI gripper) is recovered once from a chosen "calibration frame" where all three boards
were detected, then cached to `wrist_umi_calibration.json`.

Usage:
    MUJOCO_GL=osmesa python render_dataset_frame.py         --dataset-root /data/cameron/puget_ar_datasets/testing_cube_in_bowl         --frame 28 --calib-frame 184         --out /data/cameron/ar_renders/testing_cube_in_bowl
)annotationsN)Path	MUJOCO_GLosmesa)Layer)UMI_V2)CALIB_BOARDzwrist_umi_calibration.jsoncalib_board_modelzcalib_board.xmlz7/data/cameron/cad_recovery/mj_umi_v2/umi_gripper_v2.xmlc               (    V ^8  d   QhRRRRRRRR/# )   K_save
np.ndarrayH_renderintH_savereturnfloat )formats   "G/data/cameron/claude_feetech_controller/ar_view/render_dataset_frame.py__annotate__r   ,   s(     > >j >C > > >    c                    \        V R,          4      pW8X  d   TpMW1V,          ,          pR\        P                  ! \        P                  ! VRV,          ,          4      4      ,          # )zK_save is the intrinsics matched to the saved (500-wide) JPEGs.
Since fovy is resolution-independent (fovy = 2 atan(H/(2 fy))), we can render at any
size using the same fy scaled to that render height.       @)   r   )r   npdegreesarctan)r   r   r   fy_savefys   &&&  r   	_fovy_degr    ,   sR    
 F4L!G 6)*BIIh#(&;<===r   ?c               (    V ^8  d   QhRRRRRRRR/# )r   real_bgrr   sim_bgrweightr   r   r   )r   s   "r   r   r   ?   s)      Z * e ",r   c                   VP                  ^R7      P                  \        P                  4      R,          pVR8  p\        P                  ! V4      pW&V&   VR,          pV P                  \        P                  4      ^V,
          ,          VP                  \        P                  4      V,          ,           p\        P
                  ! V^ ^4      P                  \        P                  4      pVP                  \        P                  4      ^,          p	\        P                  ! V	\        P                  \        P                  ! \        P                  R4      4      p
W8V
^ 8  &   V# )a)  Composite the model onto the real image. Where the sim has drawn ANY pixel we blend
heavily (default 90% sim) so the overlay is unmistakable; elsewhere the real image
is preserved. A cyan silhouette outline is drawn along the sim mask so the align
target is easy to see even when the sim is dark.
axisg     o@{Gz?).N   r+   )maxastyper   float32
zeros_likeclipuint8cv2morphologyExMORPH_GRADIENTgetStructuringElement
MORPH_RECT)r#   r$   r%   outline_colorlummaskalphaaoutmask_u8edgess   &&&&       r   _blendr?   ?   s     ++1+

$
$RZZ
05
8C$JDMM#E$KiA
//"**
%Q
/'..2Lq2P
PC
''#q#

%
%bhh
/C{{288$+GWc&8&8 66s~~vNPE"	NJr   c                $   ^ RI p\        V P                  P                  4       Fh  p\	        V P                  P
                  V,          4      \	        VP                  P                  4      8X  g   KM  . ROV P                  P                  V&   Kj  	  R# )u   Make every plane-type geom in the loaded model invisible (rgba alpha → 0) so the
ambient floor/checker plane doesn't leak into the render — only real model meshes
(like the calib board or the UMI gripper) survive on a black background.N)    rA   rA   rA   )	mujocorangemodelngeomr   	geom_typemjtGeommjGEOM_PLANE	geom_rgba)layerrB   gs   &  r   _hide_floorsrL   U   s_     5;;$$%u{{$$Q'(C0K0K,LL'3EKK!!!$ &r   c                   ^ RI p^ RIHp V! V P                  V P                  W4       VP                  V P                  V P                  4       V P                  P                  W434      pVf,   VP                  V P                  W44      pWpP                  W43&   VP                  V P                  V P                  R7       VP                  pVP                  P                  VP                  P                  VP                  P                  VP                  P                   VP                  P"                  3 F  p	^ VP$                  V	&   K  	  \&        P(                  ! VP+                  4       \&        P,                  4      # )zLayer.render() but with skybox + floor + reflections stripped so the sim background
is black and only the model's dynamic geoms (the mesh we care about) survive.N)set_cam)camera)rB   render_corerN   rD   extcam
mj_forwarddata	renderersgetRendererupdate_scenescene
mjtRndFlagmjRND_SKYBOX
mjRND_HAZEmjRND_REFLECTIONmjRND_SHADOW	mjRND_FOGflagsr2   cvtColorrenderCOLOR_RGB2BGR)
rJ   	T_camCV_wfovyHWrB   rN   rscnflgs
   &&&&&     r   _render_cleanrj   _   s    #EKKy7
ekk5::.QF#AyOOEKK."#NN5::ellN3
''C!!..!!,,!!22!!..!!++	-
 		#- <<
C$5$566r   c               $    V ^8  d   QhRRRRRR/# )r   imgr   textstrr   r   )r   s   "r   r   r   v   s!      
 # * r   c           
         \         P                  ! V RV P                  ^,          ^3RR4       \         P                  ! WR\         P                  RR^\         P
                  4       V # )rA   g      ?)rA   rA   rA   rA   rA   )      )   rt   rt   )r2   	rectangleshapeputTextFONT_HERSHEY_SIMPLEXLINE_AA)rl   rm   s   &&r   _labelrz   v   sN    MM#v		!b19bAKK7C$<$<c?TUWZWbWbcJr   c               (    V ^8  d   QhRRRRRRRR/# )r   P_worldr   T_cam_worldKr   ztuple[int, int, float]r   )r   s   "r   r   r   |   s)     	3 	3j 	3z 	3j 	3Mc 	3r   c                   \         P                  P                  V4      pV\         P                  ! V ^ ,          V ^,          V ^,          R.4      ,          p\	        V^,          4      pVR8:  d   RRV3# W$R,          V,          ,          p\        \        V^ ,          4      4      \        \        V^,          4      4      V3# )u   Project a world point into the image. T_cam_world is (camera→world), 4x4, OpenCV convention.
Returns (u, v, z_cam). z_cam < 0 means behind camera.      ?gư>Nr+   Nrq   )r   linalginvarrayr   r   round)r|   r}   r~   T_world_camP_camzuvs   &&&    r   _projectr   |   s     ))--,K"((GAJ
GAJ#LMMEeAhADy2qy	
Bi!m	BuRU|c%1,/22r   r   g        c               $    V ^8  d   QhRRRRRR/# )r   umi_poser   refrn   r   r   )r   s   "r   r   r      s!     " "j "s "* "r   c                    VR8X  d   V R,          P                  \        4      # \        P                  ! . \        ORN4      pW,          R,          # )u   Return the world-frame reference point for a UMI pose.
'corner' → cv2 GridBoard origin (buggy behaviour, kept for A/B comparison).
'center' → center of the physical UMI ArUco board (much closer to the gripper).cornerr   r   r   r+   )r-   r   r   r   UMI_BOARD_CENTER)r   r   locals   && r   _keypoint_worldr      sH     h%%e,,HH-'--.Eb!!r   c               4    V ^8  d   QhRRRRRRRRRRR	R
RR/# )r   base_bgrr   	umi_poseslist[np.ndarray]visible
list[bool]r}   r~   r   rn   r   r   )r   s   "r   r   r      sC        
  7G  R\  #- 2< CF V` r   c           	        V P                   R,          w  rgV P                  4       p. p	\        \        W4      4       Fg  w  p
w  r\	        \        W4      W44      w  rpV^ 8:  g   V^ 8  g   V^ 8  g   W8  g   W8  d   V	P                  R4       KT  V	P                  WV34       Ki  	  \        \        V	4      ^,
          4       F  p
W,          W^,           ,          ppVe   Vf   K$  V
\        ^\        V	4      ^,
          4      ,          p\        ^P^V,          ,           4      \        ^^<V,          ,
          4      ^3p\        P                  ! VVR,          VR,          V^\        P                  4       K  	  \        V	4       F  w  p
pVf   K  Vw  rpV
\        ^\        V	4      ^,
          4      ,          pV
^ 8X  d   ^M^pV
^ 8X  d   RM2\        ^P^V,          ,           4      \        ^^<V,          ,
          4      ^3p\        P                  ! WV3VVR\        P                  4       V'       d   K  \        P                  ! WV3V^,           R^\        P                  4       K  	  V# )uQ   Polyline of UMI origins across `umi_poses`. Fading yellow→red, alpha 0.9→0.3.Nr   NN)<      rt   rq   )r   r   r   )rv   copy	enumeratezipr   r   appendrC   lenr,   r   r2   linery   circle)r   r   r   r}   r~   r   re   rf   r<   ptsiTvisuvr   r;   btcolorprg   s   &&&&&&                r   _draw_future_trajr      s    >>"DA
--/C
C Y!898A?12KCa6QUa!eqvJJt

A#; : 3s8a< vsq5z19	As3x!|$$R#'\"Cb1f$5s;aeQrUE1ckk: ! #19	cAs3x!|$$aAQ"#q&s2a</@#cBQRFlBSUX.Y

3A5"ckk:sJJsFAE<CKKH  Jr   c               8    V ^8  d   Qh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~   
axis_len_mr   r   rn   r   r   )r   s   "r   r   r      sK      
 7G R\ #-2<JO.8r   c           
       a V P                   R,          w  rxV P                  4       p	\        V4      p
\        \	        W4      4       EF{  w  pw  r\        W4      pVR,          p\        WV4      w  pppV^ 8:  g   V^ 8  g   V^ 8  g   VV8  g   VV8  d   KR  V\        ^V
^,
          4      ,          pRRV,          ,
          oR F  w  ppWRV3,          V,          ,           p\        VW44      w  pppV^ 8:  g   V^ 8  g   V^ 8  g   VV8  g   VV8  d   KS  \        ;QJ d    . V3R lV 4       F  NK  	  5M! V3R lV 4       4      p\        P                  ! T	VV3VV3TV^ 8  d   ^M^\        P                  4       K  	  \        P                  ! T	VV3V^ 8  d   ^M^V'       d   RMR	R
\        P                  4       EK~  	  V	# )z3-axis triad (X=red, Y=green, Z=blue) drawn at every UMI pose. Line alpha fades over time
so the current frame is bright and the horizon fades out.r   r!   g?:NNNc              3  H   <"   T F  p\        VS,          4      x  K  	  R # 5iN)r   ).0cr:   s   & r   	<genexpr>$_draw_axes_triads.<locals>.<genexpr>   s     =*Q#a%i..*s   "r   r   ))rA   )r   r   rt   )r   )P   r   r   )r   )rt      r   )   r   r   )d   r   r   rq   )rv   r   r   r   r   r   r   r,   tupler2   r   ry   r   )r   r   r   r}   r~   r   r   re   rf   r<   Nr   r   r   originRu0v0z0r   r(   
color_full	end_worldu1v1z1r   r:   s   &&&&&&&                    @r   _draw_axes_triadsr      s   
 >>"DA
--/CIA Y!898A (fIf15
B7b1fQ"'R1WAq1udQh!7D* 1d7j!88I!)[<JBBQw"q&BFbAgqE=*=EE=*==EHHS2r(RHe!a%QQT!7 	

3Rq1u!!&)?CKK	Q% :( Jr   c               (    V ^8  d   QhRRRRRRRR/# 	r   cellsr   	target_hwztuple[int, int]gapr   r   r   r   )r   s   "r   r   r      s+      #  +5r   c                  aa
a Vw  o
oV
VV3R lpV  Uu. uF
  qT! V4      NK  	  pp\        V4      S,          \        V4      ^,           V,          ,           p\        P                  ! S
^V,          ,           V^3S\        P                  4      pTp	V F)  pWXW"S
,           1WS,           13&   V	SV,           ,          p	K+  	  V# u upi )zNStack `cells` in a single horizontal row, aspect-fit each cell to `target_hw`.c                  < V P                   R ,          w  r\        SV,          S	V,          4      p\        \        W,          4      4      \        \        W#,          4      4      rT\        P
                  ! WV34      p\        P                  ! SS	^3S
\        P                  4      pWgSV,
          ^,          SV,
          ^,          V,           1S	V,
          ^,          S	V,
          ^,          V,           13&   V# r   	rv   minr   r   r2   resizer   fullr1   rl   ihiwsnhnwrg   r   re   rf   bgs   &       r   fit_hstack.<locals>.fit       2BBU26]#Srv%7BJJsH%GGQ1Ir288,PQ1r6a-RA*
*QVM1r6a-":L,L
LMr   )r   r   r   r1   )r   r   r   r   r   r   fittedtotal_wcanvasxre   rf   s   &&&f      @@r   _hstackr      s     DAq $$ec!feF$&kAoVqC 77GWWa!c'k7A.BHH=FA'(s7{A!eG#$	QW  M %s   Cc               (    V ^8  d   QhRRRRRRRR/# r   r   )r   s   "r   r   r      s+      & ? .8r   c                  aaa Vw  ooVVV3R lpV  Uu. uF
  qT! V4      NK  	  pp\        V4      ^,           ^,          pVS,          V^,           V,          ,           p^S,          ^V,          ,           p	\        P                  ! W^3S\        P                  4      p
\	        V4       FX  w  rV^,          V^,          rW,SV,           ,          ,           pW-SV,           ,          ,           pWZWS,           1WS,           13&   KZ  	  V
# u upi )zYStack `cells` into a 2-column grid, aspect-fit each cell into `target_hw` with letterbox.c                  < V P                   R ,          w  r\        SV,          S	V,          4      p\        \        W,          4      4      \        \        W#,          4      4      rT\        P
                  ! WV34      p\        P                  ! SS	^3S
\        P                  4      pWgSV,
          ^,          SV,
          ^,          V,           1S	V,
          ^,          S	V,
          ^,          V,           13&   V# r   r   r   s   &       r   r   _grid_2col.<locals>.fit   r   r   )r   r   r   r1   r   )r   r   r   r   r   r   r   rowsgrid_hgrid_wr   r   rg   colyr   re   rf   s   &&&f            @@r   
_grid_2colr      s     DAq $$ec!feF$K!O!DAXS((FUQW_FWWfa("bhh7F&!aQ3q3w-S/!#$qQwa% 	 "
 M %s   Dc               $    V ^8  d   QhRRRRRR/# )r   	state_dirr   framer   r   dictr   )r   s   "r   r   r     s!     & &4 & & &r   c                    WR  R2,          pVP                  4       '       g   \        V4      h\        P                  ! V4      pVP                   Uu/ uF  qDW4,          bK  	  up# u upi )06dz.npz)existsFileNotFoundErrorr   loadfiles)r   r   r   r   ks   &&   r   _load_stater     sV    Sk&&A88::""

AWW%WqtGW%%%s   A&c               (    V ^8  d   QhRRRRRRRR/# )	r   rootr   subdirrn   r   r   r   r   r   )r   s   "r   r   r     s(      d C  
 r   c                    W,          VR  R2,          p\         P                  ! \        V4      4      pVf   \        V4      hV# )r   .jpg)r2   imreadrn   r   )r   r   r   r   rl   s   &&&  r   _load_framer    s>    5+T**A
**SV
C
{""Jr   c               $    V ^8  d   QhRRRRRR/# )r   metar   camrn   r   r   r   )r   s   "r   r   r     s!     8 8$ 8S 8Z 8r   c                T    \         P                  ! W,          R ,          \        R7      # )r   dtype)r   asarrayr   )r  r  s   &&r   _K_saver
    s    ::di)77r   c                    V ^8  d   QhRRRR/# )r   Mr   r   r   )r   s   "r   r   r   !  s     + +z +j +r   c                   \         P                  P                  V 4      w  rp\         P                  ! \         P                  P	                  W,          4      4      pV\         P
                  ! RRV.4      ,          V,          # )zYNearest rotation matrix in Frobenius norm (Markley's method): SVD, drop determinant flip.r   )r   r   svdsigndetdiag)r  U_Vtds   &    r   _project_to_SO3r  !  sT    yy}}QHA"
		af%&ArwwS!}%%**r   c               $    V ^8  d   QhRRRRRR/# )r   Tsr   r   r   r   	list[int]r   )r   s   "r   r   r   (  s"     : :, : : :r   c                   \         P                  ! V  Uu. uF  q"R,          NK  	  up4      p\         P                  ! V^ R7      p\         P                  P	                  W4,
          ^R7      p\         P                  ! V4      R,           p\        V4       UUu. uF  w  rxWV,          8:  g   K  VNK  	  upp# u upi u uppi )u   Return indices of poses whose translation is within k*MAD of the median translation.
Coarse outlier rejection — throws away frames where the underlying PnP obviously drifted.r'   g&.>r   )r   r   medianr   normr   )	r  r   r   tsmeddevmadr   r  s	   &&       r   _pose_median_filterr!  (  s     
R(RU88R(	)B
))BQ
C
))...
*C
))C.4
C#C.9.$!ASLAA.99	 ) :s   B7B<-B<c               (    V ^8  d   QhRRRRRRRR/# )	r   dataset_rootr   calib_framer   forceboolr   r   r   )r   s   "r   r   r   2  s/     P Pt P# Pd PWa Pr   c                
   \         P                  4       '       dT   V'       gL   \        P                  ! \         P	                  4       4      p\
        P                  ! VR,          \        R7      # V R,          p. p\        VP                  R4      4       F  p\
        P                  ! V4      p \        VR,          4      '       d   \        VR,          4      '       dw   \        VR,          4      '       d]   \
        P                  P                  VR,          4      VR	,          ,          pVP                  \        VP                   4      V34       K  K  K  K  	  V'       g   \%        R
V 2RR7       \'        WA4      p\
        P                  P                  VR,          4      VR	,          ,          p\         P)                  \        P*                  ! RVP-                  4       RR\/        V 4      R\        V4      R^//^R7      4       V# \1        V!  w  r\3        \5        V
4      4      pV Uu. uF  qV,          NK  	  ppV Uu. uF  qV,          NK  	  pp\
        P6                  ! R%4      p\
        P6                  ! ^4      pV F"  pWR&,          ,          pVVR',          ,          pK$  	  \9        V4      pV\;        V4      ,          p\
        P<                  ! ^4      pVVR&&   VVR'&   \
        P>                  ! V Uu. uF  qR',          NK  	  up4      p\        \
        P                  PA                  VV,
          ^R7      PC                  4       4      p. pV F  pVR&,          VPD                  ,          p\
        PF                  ! \
        PH                  ! V4      ^,
          ^,          R(R4      pVP                  \
        PJ                  ! \
        PL                  ! V4      4      4       K  	  \        \
        PB                  ! V4      4      p\%        R\;        V4       R\;        V4       R2RR7       \%        RVR,          R RVR R2RR7       \         P)                  \        P*                  ! RVP-                  4       RR\/        V 4      RRR\;        V4      R\;        V4      R VR!,          R"\O        VR,          ^4      R#\O        V^4      //^R7      4       \%        R$\          2RR7       V#   \"         d     EKd  i ; iu upi u upi u upi ))us  Return T_wrist_cam→umi (4x4).

Strategy:
  1. If cached and not forced, return the cached value.
  2. Otherwise sweep every state npz in the dataset, keep only frames where
     scene/wrist/umi are ALL visible (so both PnP solves are trustworthy), compute
     T_wc_umi(f) = inv(umi_pose(f)) @ wrist_cam_pose(f).
  3. MAD-filter outliers on translation, then chordal-average the rotations via SVD
     and take the mean translation. That reduces PnP noise from a single frame by ~√N
     and rejects bad PnP solves (small board area / grazing angle).
  4. If nothing usable is found, fall back to the single `calib_frame`.
T_wrist_cam_umir  statez*.npzscene_visiblewrist_visibleumi_visibler   wrist_cam_poseuK   [calibration] no frames with all three boards visible — falling back to fTflushrecovered_fromdatasetr   n_frames)indentr'   r   z[calibration] u    tri-visible frames → z after MAD filterz([calibration] residual std: translation=  z.2fz mm, rotation=   °methodz8multi-frame chordal average, MAD-filtered on translationn_frames_consideredn_frames_keptframes_kept:N   Ntranslation_std_mmrotation_std_degz[calibration] wrote r*   r   r   g      )(
CALIB_PATHr   jsonloads	read_textr   r	  r   sortedglobr   r&  r   r   r   r   stemKeyErrorprintr   
write_textdumpstolistrn   r   r!  listzerosr  r   eyer   r  stdr   r0   tracer   arccosr   )r#  r$  r%  r  r   	per_framer   str   framesr  keepr   Ts_keepframes_keepRsumtsumR_meant_meanT_meanr  t_stdang_devRdcosang_stds   &&&                       r   _load_or_calibrate_wrist_umir_  2  s    5JJz++-.zz!-.e<<w&I.0IINN7+,WWQZ	B'((T"_2E-F-F4PRS`PaKbKbIIMM"Z.1B7G4HH  #aff+q!12 Lc-F( - [\g[hiquv0IIMM"Z.)B/?,@@djjqxxzy#l*;Wc+FVXbdef*
  	 iJFtBx(D"#d!uudG#&*+d!99dK+88FD88A;D&	%  T"FCL FVVAYFF6NF5M 
W-WU88W-	.B"))..f1.599;<EGvY!ggrxx|a'1,dC8rzz"))C.12  BFF7O$G	N3y>**B3w<.Pa
bjno	4U4Z4DNSZ[^R__a
bjno$**6==?s<(P!3y>S\;s+ %a"8gq 1
&   
 
-T:Mo  		 $+ .s%   -B"S(*S;T 9T(S87S8c                    V ^8  d   QhRRRR/# )r   gripper_radr   
joint_namern   r   )r   s   "r   r   r     s     7 7% 7S 7r   c                   ^ RI p\        P                  ! V4      '       g   R# VP                  V P                  VP
                  P                  V4      pV^ 8  d   R# \        V P                  P                  V,          4      p\        V4      V P                  P                  V&   VP                  V P                  V P                  4       R# )zWrite the servo-derived jaw angle into the UMI model's jaw joint before rendering.
gripper_rad comes from state/*.npz and already carries the calibration jaw_sign, so
it can be written to qpos directly (MuJoCo will clip to the joint range on step).N)rB   r   isfinite
mj_name2idrD   mjtObjmjOBJ_JOINTr   jnt_qposadrr   rS   qposrR   )	layer_umira  rb  rB   jidadrs   &&&   r   _pose_umi_jawrm    s     ;;{##


IOOV]]-F-F

SC
Qw
ioo))#.
/C$[1INN
iooy~~6r   c               $    V ^8  d   QhRRRRRR/# )r   r   r   r   rn   r   r   r   )r   s   "r   r   r     s(     :a :as :a-0:a@J:ar   c                   \        VP                  RV 4      p\        VP                  RV 4      p\        VP                  R,          V 4      pVR,          pVR,          pVR,          p\        V\	        VP                  R\        P                  4      4      4       \        WP                  V,          WhV	4      p\        WP                  \        P                  P                  V4      ,          V,          WhV	4      p\        VV\        R7      p\        VV\        R7      p\        VR	V  R
\!        VR,          4       R\!        VR,          4       R\	        VP                  R\	        R4      4      4      R 24      p\        WP                  V,          WzV4      p\        WP                  V,          WzV4      p\        VV\        R7      p\        VV\        R7      p\        VRV  R\!        VR,          4       24      p\!        VP"                  4      p\!        VR,          4      p\%        \'        V \)        V V,           ^,           V4      4      4      p. p. pV Fs  p \        VP                  R,          V 4      p!VP+                  \        P,                  ! V!R,          \        R7      4       VP+                  \/        V!R,          4      4       Ku  	  \1        VVVVWNR7      p"\3        V"VVVWNR7      p"\        V"R\5        V4      ^,
           RV  RV R24      p"VV,          p#\1        VVVV#W^R7      p$\3        V$VVV#W^R7      p$\        V$R\5        V4      ^,
           RV  RV R24      p$\7        VVV"V$.RR7      # )ux   Render a single frame → horizontal-stack composite (scene | wrist | future).
Returns the BGR composite ready to write.rX   wristr)  scene_cam_poser-  r   ra  )r7   u   scene · calib+UMI  fz  sv=r*  z uv=r,  z grip=nanz+.2fu   wrist · calib+UMI (chained)  fz  wv=r+  
num_framesr  r   u   scene · next z keypoints+axes  fz  [ref=]u   wrist · next )r   i  i  )r  r#  r   rm  r   rU   r   rr  rj   	T_board_wr   r   r?   CYANMAGENTArz   r   horizonrI  rC   r   r   r	  r&  r   r   r   r   )%r   argsr  T_wc_umiK_sceneK_wrist
fovy_scene
fovy_wristHsWsHwWwlayer_scenerj  r   rX   rp  rP  rq  r-  r   sim_scene_calibsim_scene_umiscene_combosim_wrist_calibsim_wrist_umiwrist_comborz  total
fut_framesr   umi_visfstffuture_scenewrist_cam_derivedfuture_wrists%   &&&&&&&&&&&&&&&                      r   _render_oner    sE   
 ))7E:E))7E:E	T&&0%	8B()N()N
^H)U266-#@AB $K1F1F1WYciklO#I1D1Dryy}}U]G^1^ao1o$.B8MtDKm7KK0 8"2o#678SMAR=S<T U!!&rvvmU5\'J!KD QSTK $K1F1F1WYciklO#I1D1Dx1OQ[acdMtDKm7KK:5's2oK^G_F`acK $,,G\"#EeE3uw':E#BCDJIG$++g5q9C
O5ABtC./0  %UIwPWaL$\9g~W^hL,*3z?1+<*==OPUwV]^a]bbcdfL !8+$UIw@QSZdL$\9gGXZakL,*3z?1+<*==OPUwV]^a]bbcdfL KlLIU_``r   c               $    V ^8  d   QhRRRRRR/# )r   specrn   r  r   r   r  r   )r   s   "r   r   r     s!     : :C : :	 :r   c                V   V R 8X  d   \        \        V4      4      # RV 9   dC   V P                  R^4      w  r#\        \        \        V4      \        V4      ^,           4      4      # V P                  R4       Uu. uF%  qDP	                  4       '       g   K  \        V4      NK'  	  up# u upi )all-,)rI  rC   splitr   strip)r  r  r;   r   r   s   &&   r   _parse_frames_argr    s{    u}E%L!!
d{zz#q!E#a&#a&1*-.. JJsO9OqwwyFCFO999s   8B&B&c                 
   \         P                  ! 4       p V P                  R R\        RR7       V P                  R\        RRR7       V P                  R\
        RR	R7       V P                  R
\
        ^RR7       V P                  RR\        RR7       V P                  RRRR7       V P                  R\
        ^RR7       V P                  R\        RRR7       V P                  R\
        ^\R7       V P                  RRR.RRR7       V P                  4       pVP                  P                  RRR7       \        P                  ! VP                  R,          P                  4       4      p\        VR ,          4      pVP                  f    VP                  f   V P                  R!4       VP                  '       d   \!        VP                  V4      M\        VP                  4      .pV Uu. uF  p^ Tu;8:  d
   V8  g   K  M K  VNK  	  pp\#        R"\%        V4       R#\%        V4      ^8:  d   TM+\	        VR$,          4      R%,           \	        VR>R 4      ,            2RR&7       \'        VP                  VP(                  VP*                  4      p\-        VR'4      p\-        VR(4      p\/        VP                  R'V^ ,          4      p	V	P0                  R),          w  r\/        VP                  R(V^ ,          4      p	V	P0                  R),          w  r\3        WzV
4      p\3        WV4      p\#        R*RR&7       \5        R'\	        \6        4      \8        R+R, 4      p\;        V4       \#        R-VP<                   2RR&7       \#        R.RR&7       \5        R/\	        \>        4      \@        R0R1 4      p\;        V4       \#        R2VP<                   2RR&7       ^ RI!pVPC                  4       p\E        V4       EF^  w  pp\G        VWWgVWWWVVVPH                  R37      pVP                  VPJ                  PM                  VR47      ,          pVPN                  PQ                  4       R?9   dF   \R        PT                  ! \	        V4      V\        \R        PV                  4      VPX                  .4       M \R        PT                  ! \	        V4      V4       V^,           ^,          ^ 8X  g   V^,           \%        V4      8X  g   EK  VPC                  4       V,
          p\#        R5V^,            R6\%        V4       R7VR8 R9VV^,           ,          R:,          R; R<2	RR&7       EKa  	  \#        R=VP                   24       R# u upi )@z--dataset-rootTz4dataset root (has meta.json, scene/, wrist/, state/))requiredtypehelpz--framesNu>   which frames to render — "all" | "28" | "0-100" | "28,50,90")r  defaultr  z--framez"convenience alias for --frames <N>z--calib-frameu@   frame with all three boards visible for wrist_cam→umi recoveryz--outzoutput directoryz--force-calib
store_trueu+   ignore cached wrist_cam→umi and re-derive)actionr  z	--horizonz;how many future frames to draw in the trajectory + axes vizz
--name-fmtzf{frame:06d}.jpgzDoutput file naming template (jpg default so the scrubber loads fast)z--jpeg-quality)r  r  z--refr   centeru   which UMI point to project as the 'gripper keypoint': 'corner' = raw cv2 GridBoard origin (marker 150 corner — off the visible gripper), 'center' = board center (much closer to gripper body). default center.)choicesr  r  )parentsexist_okz	meta.jsonrs  zsupply --frames or --framez[batch] rendering z frame(s): :N   Nu    … r.  rX   rp  r   uN   [layer] loading scene calib_board.xml + measure_board_world (loop-closure) …calibc                    R # r   r   jns   &r   <lambda>main.<locals>.<lambda>
  s    TXr   z[layer] scene reproj=u<   [layer] loading umi_gripper_v2.xml + measure_board_world …umiar_backc                    R # r   r   r  s   &r   r  r    s    4r   z[layer] umi reproj=rt  )r   z[batch] /z done  (z.1fzs, r4  z.0fz
 ms/frame)z[done] output dir: )r   z.jpeg)-argparseArgumentParseradd_argumentr   rn   r   
parse_argsr<   mkdirr>  r?  r#  r@  rQ  r   errorr  rE  r   r_  r$  force_calibr
  r  rv   r    r   SCENE_MODELr   rL   reproj	UMI_MODELr   timer   r  r   name_fmtr   suffixlowerr2   imwriteIMWRITE_JPEG_QUALITYjpeg_quality)apr{  r  r  rQ  r  r|  r}  r~  prober  r  r  r  r  r  r  rj  r  t0r   r   rl   out_pathdts                            r   mainr    s   		 	 	"BOO$t$O  QOOJS$Y  [OOIC=  ?OOO#s[  ]OOGd<NOOOOOLF  HOOKc2V  XOOLs4F_  aOO$3O;OOGh%98b  c ==?DHHNN4$N/::t((;6AACDD\"#E{{tzz1
-.6:kkkt{{E2DJJGXF2A1>E>a>aF2	s6{m;6{a'VS_W-DSPRPSEU-UVX_ce ,D,=,=t?O?OQUQaQabHdG$GdG$G))7F1I>E[[_FB))7F1I>E[[_FB7+J7+J	
Zbfg[!1;YK	!+"4"4!5
6dC	
HPTUeS^VYPI		 0 01
2$?	Bf%5%X$""%ydhh@ 88dmm222????  "&77KKHsS1I1I-JDL]L],^_KKHs+ER<1AV 4r!BHQUG1S[M"SR1Xd]SVDWWabjnoo & 
z
*+Q 3s   +U(U(U(__main__)rA   rt   rt   )rt   rA   rt   gRQ?gQ?)r  )r)   r  )rv  r  rp   )rv  rr   rp   )g      @)jaw):__doc__
__future__r   r  r>  ossyspathlibr   numpyr   r2   environ
setdefault__file__parentresolveAR_VIEWpathinsertrn   rP   r   aruco_boardsr   calib_boardr   r=  r  r  r    rx  ry  r?   rL   rj   rz   r   UMI_BOARD_WUMI_BOARD_Hr   r   r   r   r   r   r   r   r  r
  r  r!  r_  rm  r  r  r  __name__r   r   r   <module>r     sX  , #     
 

  k8 ,
x.


'
'
) 3w<     # 33
++.??LM	> 
 GJ,47.	3" $#88[3.c0A3GH " F>,2&8+:Pf7:az:G,T zF r   