o
    Gi,                     @   s   d Z ddlZddlZddlmZ ddlZddlZddlm	Z	 edZ
defddZd	ed
edB fddZd&d	ededB fddZdejdedefddZd'dejdedefddZ		d(dejdejdejded ef
d!d"Zd#d$ Zed%kr{e  dS dS ))aV  
Run CoTracker 3 on RTX GIFs: forward point tracking from the first frame.

Uses a grid of points on frame 0 and tracks them to the end. Grid density and
video FPS are parameters you can inspect.

Requires: pip install opencv-python (and PyTorch with CUDA for best speed).
CoTracker3 is loaded via torch.hub from facebookresearch/co-tracker.
    N)Path)Imagez/data/RTX/RTX_Videorootc                 C   sN   t |  } g }t|  D ]}| sqt|dD ]}|| qq|S )z#Return sorted list of root/*/*.gif.z*.gif)r   resolvesortediterdiris_dirglobappend)r   outZsubdirf r   D/data/cameron/vidgen/unified_video_action/scripts/point_track_rtx.py	find_gifs   s   r   pathreturnc                 C   s   t | /}t|dd}d}t|D ]}|| |jdd}||dur)t|nd7 }qW d   n1 s7w   Y  |dkrBdS ||d  S )zJReturn effective FPS from GIF duration metadata, or None if not available.n_frames   r   durationNg     @@)r   opengetattrrangeseekinfogetint)r   imr   Ztotal_msidr   r   r   get_gif_effective_fps#   s   
r   
max_framesc              	   C   s   g }t | .}t|dd}|durt||}t|D ]}|| |t|	d qW d   n1 s8w   Y  tj
|ddS )z5Load all frames of a GIF as numpy (T, H, W, 3) uint8.r   r   NZRGBr   axis)r   r   r   minr   r   r
   nparrayconvertstack)r   r    framesr   nr   r   r   r   load_gif_frames1   s   

r*   r(   
source_fps
target_fpsc                 C   s`   |dks|dks||kr| S || }t t dt| |t}t |dt| d }| | S )zFSubsample frames to target_fps. frames: (T,H,W,C). Returns (T',H,W,C).r   r   )r$   roundarangelenastyper   clip)r(   r+   r,   stepindicesr   r   r   subsample_to_fps>   s   r4   cudavideo	grid_sizedevicec                 C   sj   t jjdddd|}| |} t   || |d\}}W d   n1 s(w   Y  | | fS )z
    Run CoTracker3 offline on video. Forward tracking only (grid on first frame).

    video: (1, T, C, H, W) float in [0, 255]
    Returns: pred_tracks (1, T, N, 2), pred_visibility (1, T, N, 1)
    zfacebookresearch/co-trackerZcotracker3_offlineT)
trust_repo)r7   N)torchhubloadtono_gradcpu)r6   r7   r8   Z	cotrackerpred_trackspred_visibilityr   r   r   run_cotrackerH   s   

rB         r@   rA   point_radiusline_thicknessc              	   C   s  zddl }W n ty   tdw | j\}}}}	|  }
|j\}}}|d}|j|| kr8|dk||}n|d  dk}|jdkrK|||}|j||fksaJ d|j d	| d
| dt	|
tj}t|d d|d |d< t|d d|d |d< t|D ]}t|D ])}|||f sqt|||df t|||df }}||
| ||f|dd q|dkrt|D ]J}||d |f r|||f sqt||d |df t||d |df }}t|||df t|||df }}||
| ||f||fd| qq|
S )z
    Overlay tracks on frames. pred_tracks (T, N, 2), pred_visibility (T, N, 1).
    Uses rounded coordinates for stable drawing. Returns (T, H, W, 3) uint8.
    r   NzGopencv-python is required for drawing tracks. pip install opencv-pythong      ?).r   r   zvisibility shape z vs (T=z, N=)).r   )r      r   )r      r   )cv2ImportErrorshapecopyreshapesizesqueezendimr$   r-   r0   int32r1   r   r   circleline)r(   r@   rA   rE   rF   rK   THWCr   _NvZvisZ
tracks_inttr)   xyx0y0x1y1r   r   r   draw_tracksZ   sB   

,&
.& rd   c            #   
   C   s  t jdd} | jdtttdd | jdtd dd | jdtd	d
d | jdtddd | jdtddd | jdtddd | jdtddd | jdtddd |  }|jrht	|j}|
 sgtd| n*t	|j }| sztd| t|}|std| |d }td|  t|}|d u s|dkr|j}td | d! ntd"|d# |j}|d ur|dkr|j|k rt|| |j }td$| d%| d& t||d'}|j\}}	}
}td(| d)|	 d*|
  |dkr(|j|k r(t|||j}|jd urt||jkr|d |j }t|}td+|j d,| d- t|dd.d/d0 d}|jd/ |krP|jd. |	krP|jd1 |
ksRJ |d0 }|d/ | }|dk sf|dkrtd2|j d3 t ||j|j!d4\}}|" d }|" d }|}nt#t$||| d}|d d |f }t#t$||| d/ }|d d |f }td5| d6|j d7| d8| d9	 t ||j|j!d4\}}t ||j|j!d4\}}|" d }|" d }|" d }|" d }t%j&||d/d  gdd:}t%j&||d/d  gdd:}|j'd0kr|d d d d d f }||d/d   }|| }td;|j  td< t(|||}t	|j)j*rFt	|j)+d=nt	|j)}|j,|j-d>  }|j,j.d?d?d@ dA}zdd l/m0} |j1t||dBdC|jdD d?}W n
 t2y~   Y nw |sdd l3}|j4dE } |5t|| |j|
|	f}!|!6 s|j4dF } |5t|| |j|
|	f}!|D ]}"|!7|8|"|j9 q|!:  tdG| dH|j d& tdI d S )JNzBRun CoTracker 3 on one RTX GIF (forward tracking from first frame))descriptionz--data-rootz9Root with subdirs of .gif files (used if --video not set))typedefaulthelpz--videozBPath to a single GIF. If not set, use first GIF under --data-root.z--grid-size    zGGrid density: grid_size x grid_size points on first frame (default 32).z--fpsg       @z2Load GIF and output video at this FPS (default 2).z--source-fpsg      4@z[Fallback FPS when GIF has no duration metadata; used for subsampling to --fps (default 20).z--max-frames<   zqMax frames to process (after subsampling to --fps). When subsampling, loads more from GIF as needed (default 60).z--outzout/rtx_trackzEOutput path prefix: writes {out}_tracks.mp4 (default: out/rtx_track).z--devicer5   z%Device for CoTracker (default: cuda).zVideo not found: zData root not found: zNo *.gif under rG   zUsing first GIF: r   z  Using --source-fps z (no duration metadata in GIF)z  GIF effective FPS: z.1fzLoading GIF: z (max_frames=rH   )r    z	  Loaded z	 frames, r^   z  Subsampled to z fps: z framesrC   r   rD      zRunning CoTracker 3 (grid_size=z, forward only) ...)r8   z&Running CoTracker 3 from center frame z (grid_size=z): z back + z forward ...r!   z  Tracks shape: zDrawing tracks ... z_tracks.mp4T)parentsexist_okFpyavlibx264)plugincodecfpsavc1mp4vzSaved: z (fps=zDone.);argparseArgumentParseradd_argumentstrDEFAULT_DATA_ROOTr   float
parse_argsr6   r   is_fileFileNotFoundError	data_rootr   r   r   printr   r+   r    rs   mathceilr*   rM   r4   r/   r:   
from_numpypermute	unsqueezer7   rB   r8   numpylistr   r$   concatenaterR   rd   r   suffixwith_suffixparentnamemkdir
imageio.v3v3imwrite	ExceptionrK   VideoWriter_fourccVideoWriterisOpenedwritecvtColorCOLOR_RGB2BGRrelease)#pargsgif_pathr   gifsr+   
load_limitr(   rV   rW   rX   rY   r6   kmiddler@   rA   out_frames_arrindices_back	clip_backindices_fwdclip_fwdtracks_backvis_back
tracks_fwdvis_fwdout_indices
out_framesout_pathwritteniiorK   fourccwriterr   r   r   r   main   s  
 4$(


r   __main__)N)r5   )rC   rD   )__doc__rv   r   pathlibr   r   r$   r:   PILr   rz   r   r{   r   r   r*   ndarrayr4   Tensorry   rB   rd   r   __name__r   r   r   r   <module>   s>    


0 +
