@@ -67,6 +67,59 @@ def images_to_video(image_files, video_path, fps=30):
6767 video_writer .release ()
6868 print (f"Saved video { video_path } " )
6969
70+ def _parse_mask_filename (fname ):
71+ """
72+ Parse a mask filename to extract sam_id_token and core_prompt_slug.
73+ Returns (sam_id_token, core_prompt_slug) or (None, None) if not matched.
74+ """
75+ # Example: 000001_obj1_dog_mask.png
76+ match = re .match (r"^\d+_(obj\d+)_([a-zA-Z0-9_]+)_mask\.png$" , fname )
77+ if match :
78+ return match .group (1 ), match .group (2 )
79+ # Fallback: 000001_obj1_mask.png (no prompt)
80+ match_simple = re .match (r"^\d+_(obj\d+)_mask\.png$" , fname )
81+ if match_simple :
82+ return match_simple .group (1 ), None
83+ return None , None
84+
85+ def _collect_unique_tracked_objects (mask_files ):
86+ """
87+ Collect unique (sam_id_token, core_prompt_slug) pairs from mask filenames.
88+ Returns a dict with keys as (sam_id_token, core_prompt_slug).
89+ """
90+ unique_tracked_objects = {}
91+ for f_path in mask_files :
92+ fname = os .path .basename (f_path )
93+ sam_id_token , core_prompt_slug = _parse_mask_filename (fname )
94+ if sam_id_token is not None :
95+ key = (sam_id_token , core_prompt_slug )
96+ if key not in unique_tracked_objects :
97+ unique_tracked_objects [key ] = {
98+ "sam_id_token" : sam_id_token ,
99+ "core_prompt_slug" : core_prompt_slug
100+ }
101+ else :
102+ print (f"Warning: Filename { fname } did not match expected pattern." )
103+ return unique_tracked_objects
104+
105+ def _get_obj_files (output_dir , sam_id_token , core_prompt_slug ):
106+ """
107+ Get sorted mask and overlay files for a given object.
108+ """
109+ if core_prompt_slug :
110+ mask_pattern = os .path .join (
111+ output_dir , f"*_{ sam_id_token } _{ core_prompt_slug } _mask.png" )
112+ overlay_pattern = os .path .join (
113+ output_dir , f"*_{ sam_id_token } _{ core_prompt_slug } _overlay.png" )
114+ video_prefix = f"{ sam_id_token } _{ core_prompt_slug } "
115+ else :
116+ mask_pattern = os .path .join (output_dir , f"*_{ sam_id_token } _mask.png" )
117+ overlay_pattern = os .path .join (output_dir , f"*_{ sam_id_token } _overlay.png" )
118+ video_prefix = sam_id_token
119+ mask_files = sorted (glob (mask_pattern ))
120+ overlay_files = sorted (glob (overlay_pattern ))
121+ return mask_files , overlay_files , video_prefix
122+
70123def generate_per_object_videos (output_dir , fps = 30 ):
71124 """
72125 Generate per-object videos from mask and overlay images.
@@ -80,57 +133,22 @@ def generate_per_object_videos(output_dir, fps=30):
80133 print (f"No mask files found in { output_dir } matching pattern." )
81134 return
82135
83- # Store unique combinations of (sam_id_token, core_prompt_slug)
84- # sam_id_token is like "obj1", core_prompt_slug is like "dog" or "a_red_bicycle"
85- unique_tracked_objects = {}
86-
87- # Regex to parse filenames like "000001_obj1_dog_mask.png"
88- # or "000001_obj1_a_red_bicycle_mask.png"
89- # Group 1: (obj\d+) - e.g., "obj1"
90- # Group 2: ([^_]+(?:_[^_]+)*) - e.g., "dog" or "a_red_bicycle"
91- filename_parser = re .compile (r"^\d+_(obj\d+)_([^_]+(?:_[^_]+)*)_mask\.png$" )
92-
93- for f_path in all_mask_files :
94- fname = os .path .basename (f_path )
95- match = filename_parser .match (fname )
96- if match :
97- sam_id_token = match .group (1 ) # e.g., "obj1"
98- core_prompt_slug = match .group (2 ) # e.g., "dog" or "a_red_bicycle"
99-
100- # Use a tuple to uniquely identify the tracked object
101- object_key = (sam_id_token , core_prompt_slug )
102- if object_key not in unique_tracked_objects :
103- unique_tracked_objects [object_key ] = {
104- "sam_id_token" : sam_id_token ,
105- "core_prompt_slug" : core_prompt_slug
106- }
107- else :
108- print (f"Warning: Filename { fname } did not match expected pattern." )
109- continue
110-
136+ unique_tracked_objects = _collect_unique_tracked_objects (all_mask_files )
111137 if not unique_tracked_objects :
112138 print (f"No objects successfully parsed from filenames in { output_dir } ." )
113139 return
114140
115- for key in sorted (list ( unique_tracked_objects .keys ())): # Sort for deterministic order
141+ for key in sorted (unique_tracked_objects .keys ()):
116142 obj_info = unique_tracked_objects [key ]
117143 sam_id_token = obj_info ["sam_id_token" ]
118144 core_prompt_slug = obj_info ["core_prompt_slug" ]
119145
120- # Construct glob patterns that include both sam_id_token and core_prompt_slug
121- obj_mask_files_pattern = os .path .join (
122- output_dir , f"*_{ sam_id_token } _{ core_prompt_slug } _mask.png" )
123- obj_overlay_files_pattern = os .path .join (
124- output_dir , f"*_{ sam_id_token } _{ core_prompt_slug } _overlay.png" )
125-
126- obj_mask_files = sorted (glob (obj_mask_files_pattern ))
127- obj_overlay_files = sorted (glob (obj_overlay_files_pattern ))
128-
129- # Create a descriptive prefix for the video files
130- video_file_prefix = f"{ sam_id_token } _{ core_prompt_slug } "
146+ mask_files , overlay_files , video_file_prefix = _get_obj_files (
147+ output_dir , sam_id_token , core_prompt_slug
148+ )
131149
132150 mask_video_path = os .path .join (output_dir , f"{ video_file_prefix } _mask_video.mp4" )
133151 overlay_video_path = os .path .join (output_dir , f"{ video_file_prefix } _overlay_video.mp4" )
134152
135- images_to_video (obj_mask_files , mask_video_path , fps )
136- images_to_video (obj_overlay_files , overlay_video_path , fps )
153+ images_to_video (mask_files , mask_video_path , fps )
154+ images_to_video (overlay_files , overlay_video_path , fps )
0 commit comments