Instructions to use nvidia/Flora-TempSeg with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use nvidia/Flora-TempSeg with PEFT:
from peft import PeftModel from transformers import AutoModelForCausalLM base_model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3.5-9B") model = PeftModel.from_pretrained(base_model, "nvidia/Flora-TempSeg") - Notebooks
- Google Colab
- Kaggle
Download batch_utils/media.py from nvidia/Flora-TempSeg: direct link, hf CLI and curl.
- Browser
- Download file 5.14 kB
-
https://huggingface.co/nvidia/Flora-TempSeg/resolve/refs%2Fpr%2F2/batch_utils/media.py
- Command line
-
hf download hf://nvidia/Flora-TempSeg@refs/pr/2/batch_utils/media.py
-
curl -L -o media.py https://huggingface.co/nvidia/Flora-TempSeg/resolve/refs%2Fpr%2F2/batch_utils/media.py
5.14 kB
| from dataclasses import dataclass | |
| from fractions import Fraction | |
| from pathlib import Path | |
| import hashlib | |
| import av | |
| from .config import MAX_DURATION_S, MAX_DIMENSION, MAX_FRAME_COUNT | |
| class InputError(ValueError): | |
| pass | |
| class Video: | |
| path: Path | |
| sha256: str | |
| rate: Fraction | |
| pts_us: tuple | |
| duration_us: int | |
| size: tuple | |
| cfr: bool | |
| def duration_s(self): | |
| return self.duration_us / 1000000 | |
| def probe(path): | |
| with av.open(str(path), options={'err_detect': 'explode'}) as container: | |
| if len(container.streams.video) != 1: | |
| raise InputError('Use a file containing one video stream.') | |
| stream = container.streams.video[0] | |
| stream.codec_context.thread_count = 1 | |
| rate = stream.average_rate | |
| if not rate or rate < 4: | |
| raise InputError('The input needs at least 4 source frames per second.') | |
| size = (stream.codec_context.width, stream.codec_context.height) | |
| if min(size) <= 0 or max(size) > MAX_DIMENSION: | |
| raise InputError('Video dimensions must be at most 4096 pixels per side.') | |
| times, zero, last_length = ([], None, None) | |
| for frame in container.decode(stream): | |
| if frame.pts is None: | |
| raise InputError('Every source frame needs a presentation timestamp.') | |
| zero = frame.pts if zero is None else zero | |
| t = Fraction(frame.pts - zero) * stream.time_base * 1000000 | |
| if times and t <= times[-1]: | |
| raise InputError('Source timestamps must be strictly increasing.') | |
| if t >= MAX_DURATION_S * 1000000 or len(times) >= MAX_FRAME_COUNT: | |
| raise InputError(f'Video exceeds {MAX_DURATION_S:g} seconds or {MAX_FRAME_COUNT} frames.') | |
| times.append(t) | |
| last_length = Fraction(frame.duration) * stream.time_base * 1000000 if frame.duration else None | |
| if len(times) < 2: | |
| raise InputError('The video contains too few source frames.') | |
| tail = last_length or Fraction(1000000, rate) | |
| duration = round(times[-1] + tail) | |
| if duration > MAX_DURATION_S * 1000000: | |
| raise InputError(f'Video exceeds {MAX_DURATION_S:g} seconds.') | |
| cfr = all((abs(t - Fraction(i * 1000000, rate)) <= 1 for i, t in enumerate(times))) | |
| with path.open('rb') as f: | |
| digest = hashlib.file_digest(f, 'sha256').hexdigest() | |
| return Video(path, digest, rate, tuple(times), duration, size, cfr) | |
| def check_synchronized(videos): | |
| main = videos['main'] | |
| if len(videos) == 3: | |
| for role, video in videos.items(): | |
| if video.rate != main.rate or video.pts_us != main.pts_us or video.duration_us != main.duration_us: | |
| raise InputError('Three camera files must have identical relative frame timestamps, frame counts and duration.') | |
| if not main.cfr: | |
| raise InputError('The three-view profile requires constant-rate synchronized source videos.') | |
| def decode_selected(video, wanted, canonical=False): | |
| wanted = set(wanted) | |
| result = {} | |
| if not wanted: | |
| return result | |
| if min(wanted) < 0 or max(wanted) >= len(video.pts_us): | |
| raise InputError('A requested source frame is outside the video.') | |
| with av.open(str(video.path), options={'err_detect': 'explode'}) as container: | |
| stream = container.streams.video[0] | |
| stream.codec_context.thread_count = 1 | |
| zero = None | |
| for i, frame in enumerate(container.decode(stream)): | |
| zero = frame.pts if zero is None else zero | |
| if i in wanted: | |
| if Fraction(frame.pts - zero) * stream.time_base * 1000000 != video.pts_us[i]: | |
| raise InputError('Source frame timestamps changed while decoding.') | |
| use_canonical = canonical and frame.format.name == 'yuv420p' and (frame.width % 16 == 0) and (frame.height % 2 == 0) and (int(frame.colorspace) in (2, 5, 6)) and (int(frame.color_range) in (0, 1)) | |
| if use_canonical: | |
| from canonical_rgb import canonical_rgb | |
| result[i] = canonical_rgb(frame) | |
| else: | |
| result[i] = frame.to_image().convert('RGB') | |
| if i >= max(wanted): | |
| break | |
| if set(result) != wanted: | |
| raise InputError('A requested source frame could not be decoded.') | |
| return result | |
| def frames_for(videos, wanted, mosaic='YAM'): | |
| frames = {role: decode_selected(video, wanted, canonical=len(videos) == 3) for role, video in videos.items()} | |
| if len(videos) == 1: | |
| return frames['main'] | |
| from composers import compose_top_dominant_mosaic, compose_frame | |
| if mosaic == 'YAM': | |
| return {i: compose_top_dominant_mosaic(frames['main'][i], frames['left_wrist'][i], frames['right_wrist'][i]) for i in wanted} | |
| if mosaic == 'Dex': | |
| return {i: compose_frame(dict(ego=frames['main'][i], left_wrist=frames['left_wrist'][i], right_wrist=frames['right_wrist'][i]), ('ego', 'left_wrist', 'right_wrist')) for i in wanted} | |
| raise InputError('Choose a supported camera layout.') | |