Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions workflows/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ for contributor and maintainer responsibilities.

- Root-coordinate recovery (`sv_detections_to_root_coordinates`, applied to workflow outputs by default) re-encodes `rle_mask` from the re-anchored dense masks. A block that ran on a crop and returns RLE with dense masks, such as SAM 3 v3 with `output_format: rle`, used to serialize root-coordinate boxes next to an RLE still sized and placed in the crop. RLE-only predictions (`mask=None`) are unchanged, as in `scale_sv_detections`.

- Video-state blocks now accept an image from a step output as well as from a Workflow input, so they keep working inside an embedded `roboflow_core/inner_workflow@v1` whose `image` is bound to a parent step (for example a preprocessing block). Inlining replaces the child's `$inputs.image` with that step selector, and the merged definition used to fail with `Could not parse workflow definition` even though each Workflow compiled on its own. Affected blocks: `time_in_zone@v2`/`@v3`, `velocity@v1`, `line_counter@v2`, `path_deviation_analytics@v2`, `detection_event_log@v1`, `byte_tracker@v2`, `cache_get@v1`, `cache_set@v1`, `delta_filter@v1` and `rate_limiter@v1` (`video_reference_image`). The blocks read `video_metadata` from the image, which step outputs built with `WorkflowImageData.copy_and_replace` keep, so per-video state is unchanged.
- Absolute and relative static crops (`absolute_static_crop@v1`, `relative_statoic_crop@v1`) now give a crop the same `video_identifier` on every frame (`<video> | crop: <block>:<x_min>,<y_min>,<x_max>,<y_max>`). They used to append the per-frame crop ID, so a stateful block fed by a static crop (Cache Get/Set, trackers, analytics) saw each frame as a new video: the cache missed on every frame and state kept growing with one namespace per frame. Crop `parent_id` values are still unique per frame. `WorkflowImageData.create_crop` and `create_crop_from_tensor` take an optional `video_crop_identifier` for this; other callers are unchanged.
- Camera Calibration (`camera-calibration@v1`) keeps the input image's video metadata and root-ancestor metadata on its output. It used to drop them, so a rate limiter using the calibrated frame as `video_reference_image` saw every frame at time zero and suppressed its downstream steps after the first frame.

## `0.2.14`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
from roboflow_workflows.execution_engine.entities.types import (
DICTIONARY_KIND,
FLOAT_KIND,
IMAGE_KIND,
INSTANCE_SEGMENTATION_PREDICTION_KIND,
INTEGER_KIND,
OBJECT_DETECTION_PREDICTION_KIND,
Selector,
WorkflowImageSelector,
WorkflowParameterSelector,
)
from roboflow_workflows.execution_engine.entities.workload import (
Expand Down Expand Up @@ -94,7 +94,7 @@ class BlockManifest(WorkflowBlockManifest):
)
type: Literal["roboflow_core/detection_event_log@v1"]

image: WorkflowImageSelector = Field(
image: Selector(kind=[IMAGE_KIND]) = Field(
description="Reference to the image for video metadata (frame number, timestamp).",
examples=["$inputs.image"],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
from roboflow_workflows.execution_engine.entities.types import (
DICTIONARY_KIND,
FLOAT_KIND,
IMAGE_KIND,
INTEGER_KIND,
Selector,
WorkflowImageSelector,
WorkflowParameterSelector,
)
from roboflow_workflows.execution_engine.entities.workload import (
Expand Down Expand Up @@ -98,7 +98,7 @@ class BlockManifest(WorkflowBlockManifest):
)
type: Literal["roboflow_core/detection_event_log@v1"]

image: WorkflowImageSelector = Field(
image: Selector(kind=[IMAGE_KIND]) = Field(
description="Reference to the image for video metadata (frame number, timestamp).",
examples=["$inputs.image"],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
WorkflowImageData,
)
from roboflow_workflows.execution_engine.entities.types import (
IMAGE_KIND,
INSTANCE_SEGMENTATION_PREDICTION_KIND,
INTEGER_KIND,
LIST_OF_VALUES_KIND,
OBJECT_DETECTION_PREDICTION_KIND,
STRING_KIND,
Selector,
WorkflowImageSelector,
)
from roboflow_workflows.execution_engine.entities.workload import (
Discovery,
Expand Down Expand Up @@ -136,7 +136,7 @@ class LineCounterManifest(WorkflowBlockManifest):
}
)
type: Literal["roboflow_core/line_counter@v2"]
image: WorkflowImageSelector = Field(
image: Selector(kind=[IMAGE_KIND]) = Field(
description="Image with embedded video metadata. The video_metadata contains video_identifier to maintain separate counting state for different videos. Required for persistent counting across frames.",
)
detections: Selector(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
TENSOR_NATIVE_OBJECT_DETECTION_PREDICTION_KIND,
)
from roboflow_workflows.execution_engine.entities.types import (
IMAGE_KIND,
INTEGER_KIND,
LIST_OF_VALUES_KIND,
STRING_KIND,
Selector,
WorkflowImageSelector,
)
from roboflow_workflows.execution_engine.entities.workload import (
Discovery,
Expand Down Expand Up @@ -147,7 +147,7 @@ class LineCounterManifest(WorkflowBlockManifest):
}
)
type: Literal["roboflow_core/line_counter@v2"]
image: WorkflowImageSelector = Field(
image: Selector(kind=[IMAGE_KIND]) = Field(
description="Image with embedded video metadata. The video_metadata contains video_identifier to maintain separate counting state for different videos. Required for persistent counting across frames.",
)
detections: Selector(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
WorkflowImageData,
)
from roboflow_workflows.execution_engine.entities.types import (
IMAGE_KIND,
INSTANCE_SEGMENTATION_PREDICTION_KIND,
LIST_OF_VALUES_KIND,
OBJECT_DETECTION_PREDICTION_KIND,
STRING_KIND,
Selector,
WorkflowImageSelector,
)
from roboflow_workflows.execution_engine.entities.workload import (
Discovery,
Expand Down Expand Up @@ -134,7 +134,7 @@ class PathDeviationManifest(WorkflowBlockManifest):
}
)
type: Literal["roboflow_core/path_deviation_analytics@v2"]
image: WorkflowImageSelector = Field(
image: Selector(kind=[IMAGE_KIND]) = Field(
description="Image with embedded video metadata. The video_metadata contains video_identifier to maintain separate path tracking state for different videos. Required for persistent path accumulation across frames.",
)
detections: Selector(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
TENSOR_NATIVE_OBJECT_DETECTION_PREDICTION_KIND,
)
from roboflow_workflows.execution_engine.entities.types import (
IMAGE_KIND,
LIST_OF_VALUES_KIND,
STRING_KIND,
Selector,
WorkflowImageSelector,
)
from roboflow_workflows.execution_engine.entities.workload import (
Discovery,
Expand Down Expand Up @@ -140,7 +140,7 @@ class PathDeviationManifest(WorkflowBlockManifest):
}
)
type: Literal["roboflow_core/path_deviation_analytics@v2"]
image: WorkflowImageSelector = Field(
image: Selector(kind=[IMAGE_KIND]) = Field(
description="Image with embedded video metadata. The video_metadata contains video_identifier to maintain separate path tracking state for different videos. Required for persistent path accumulation across frames.",
)
detections: Selector(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
)
from roboflow_workflows.execution_engine.entities.types import (
BOOLEAN_KIND,
IMAGE_KIND,
INSTANCE_SEGMENTATION_PREDICTION_KIND,
LIST_OF_VALUES_KIND,
OBJECT_DETECTION_PREDICTION_KIND,
STRING_KIND,
Selector,
WorkflowImageSelector,
)
from roboflow_workflows.execution_engine.entities.workload import (
Discovery,
Expand Down Expand Up @@ -144,7 +144,7 @@ class TimeInZoneManifest(WorkflowBlockManifest):
}
)
type: Literal["roboflow_core/time_in_zone@v2"]
image: Union[WorkflowImageSelector] = Field(
image: Selector(kind=[IMAGE_KIND]) = Field(
title="Image",
description="Input image for the current video frame containing embedded video metadata (fps, frame_number, frame_timestamp, video_identifier, video source) required for time calculation and state management. The block extracts video_metadata from the WorkflowImageData object. The fps and frame_number are used for video files to calculate timestamps (timestamp = frame_number / fps). For streamed video, frame_timestamp is used directly. The video_identifier is used to maintain separate tracking state and zone configurations for different videos. Used for zone visualization and reference. The image dimensions are used to validate zone coordinates. This version simplifies input by embedding metadata in the image object rather than requiring a separate metadata field.",
examples=["$inputs.image", "$steps.cropping.crops"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@
)
from roboflow_workflows.execution_engine.entities.types import (
BOOLEAN_KIND,
IMAGE_KIND,
LIST_OF_VALUES_KIND,
STRING_KIND,
Selector,
WorkflowImageSelector,
)
from roboflow_workflows.execution_engine.entities.workload import (
Discovery,
Expand Down Expand Up @@ -154,7 +154,7 @@ class TimeInZoneManifest(WorkflowBlockManifest):
}
)
type: Literal["roboflow_core/time_in_zone@v2"]
image: Union[WorkflowImageSelector] = Field(
image: Selector(kind=[IMAGE_KIND]) = Field(
title="Image",
description="Input image for the current video frame containing embedded video metadata (fps, frame_number, frame_timestamp, video_identifier, video source) required for time calculation and state management. The block extracts video_metadata from the WorkflowImageData object. The fps and frame_number are used for video files to calculate timestamps (timestamp = frame_number / fps). For streamed video, frame_timestamp is used directly. The video_identifier is used to maintain separate tracking state and zone configurations for different videos. Used for zone visualization and reference. The image dimensions are used to validate zone coordinates. This version simplifies input by embedding metadata in the image object rather than requiring a separate metadata field.",
examples=["$inputs.image", "$steps.cropping.crops"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
)
from roboflow_workflows.execution_engine.entities.types import (
BOOLEAN_KIND,
IMAGE_KIND,
INSTANCE_SEGMENTATION_PREDICTION_KIND,
LIST_OF_VALUES_KIND,
OBJECT_DETECTION_PREDICTION_KIND,
STRING_KIND,
Selector,
WorkflowImageSelector,
)
from roboflow_workflows.execution_engine.entities.workload import (
Discovery,
Expand Down Expand Up @@ -167,7 +167,7 @@ class TimeInZoneManifest(WorkflowBlockManifest):
}
)
type: Literal["roboflow_core/time_in_zone@v3"]
image: Union[WorkflowImageSelector] = Field(
image: Selector(kind=[IMAGE_KIND]) = Field(
title="Image",
description="Input image for the current video frame containing embedded video metadata (fps, frame_number, frame_timestamp, video_identifier, video source) required for time calculation and state management. The block extracts video_metadata from the WorkflowImageData object. The fps and frame_number are used for video files to calculate timestamps (timestamp = frame_number / fps). For streamed video, frame_timestamp is used directly. The video_identifier is used to maintain separate tracking state and zone configurations for different videos. Used for zone visualization and reference. The image dimensions are used to validate zone coordinates. This version supports multiple zones per video with efficient zone cache management.",
examples=["$inputs.image", "$steps.cropping.crops"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
)
from roboflow_workflows.execution_engine.entities.types import (
BOOLEAN_KIND,
IMAGE_KIND,
LIST_OF_VALUES_KIND,
STRING_KIND,
Selector,
WorkflowImageSelector,
)
from roboflow_workflows.execution_engine.entities.workload import (
Discovery,
Expand Down Expand Up @@ -177,7 +177,7 @@ class TimeInZoneManifest(WorkflowBlockManifest):
}
)
type: Literal["roboflow_core/time_in_zone@v3"]
image: Union[WorkflowImageSelector] = Field(
image: Selector(kind=[IMAGE_KIND]) = Field(
title="Image",
description="Input image for the current video frame containing embedded video metadata (fps, frame_number, frame_timestamp, video_identifier, video source) required for time calculation and state management. The block extracts video_metadata from the WorkflowImageData object. The fps and frame_number are used for video files to calculate timestamps (timestamp = frame_number / fps). For streamed video, frame_timestamp is used directly. The video_identifier is used to maintain separate tracking state and zone configurations for different videos. Used for zone visualization and reference. The image dimensions are used to validate zone coordinates. This version supports multiple zones per video with efficient zone cache management.",
examples=["$inputs.image", "$steps.cropping.crops"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
)
from roboflow_workflows.execution_engine.entities.types import (
FLOAT_KIND,
IMAGE_KIND,
INSTANCE_SEGMENTATION_PREDICTION_KIND,
KEYPOINT_DETECTION_PREDICTION_KIND,
OBJECT_DETECTION_PREDICTION_KIND,
Selector,
StepOutputSelector,
WorkflowImageSelector,
)
from roboflow_workflows.execution_engine.entities.workload import (
Discovery,
Expand Down Expand Up @@ -134,7 +134,7 @@ class VelocityManifest(WorkflowBlockManifest):
}
)
type: Literal["roboflow_core/velocity@v1"]
image: WorkflowImageSelector = Field(
image: Selector(kind=[IMAGE_KIND]) = Field(
description="Image with embedded video metadata. The video_metadata contains fps, frame_number, frame_timestamp, and video_identifier. Required for calculating time deltas and maintaining separate velocity tracking state for different videos.",
)
detections: StepOutputSelector(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
)
from roboflow_workflows.execution_engine.entities.types import (
FLOAT_KIND,
IMAGE_KIND,
Selector,
StepOutputSelector,
WorkflowImageSelector,
)
from roboflow_workflows.execution_engine.entities.workload import (
Discovery,
Expand Down Expand Up @@ -143,7 +143,7 @@ class VelocityManifest(WorkflowBlockManifest):
}
)
type: Literal["roboflow_core/velocity@v1"]
image: WorkflowImageSelector = Field(
image: Selector(kind=[IMAGE_KIND]) = Field(
description="Image with embedded video metadata. The video_metadata contains fps, frame_number, frame_timestamp, and video_identifier. Required for calculating time deltas and maintaining separate velocity tracking state for different videos.",
)
detections: StepOutputSelector(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
STRING_KIND,
WILDCARD_KIND,
Selector,
WorkflowImageSelector,
)
from roboflow_workflows.execution_engine.entities.workload import (
Discovery,
Expand Down Expand Up @@ -99,7 +98,7 @@ class BlockManifest(WorkflowBlockManifest):
}
)
type: Literal["roboflow_core/cache_get@v1"]
image: WorkflowImageSelector = Field(
image: Selector(kind=[IMAGE_KIND]) = Field(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Keep a stable video identity when accepting cropped images

This now allows a static-crop output to feed Cache Get/Set, including through an embedded workflow. However, static cropping generates a new crop ID on every frame, and create_crop appends it to video_metadata.video_identifier. The cache uses that video identifier as its namespace, so successive frames from the same camera and the same crop region cannot read each other's cached values.

flowchart TD
    A["Camera A, frame 1"] --> B["Same static crop: new ID crop-1"]
    B --> C["Cache Set writes under camera-A + crop-1"]
    D["Camera A, frame 2"] --> E["Same static crop: new ID crop-2"]
    E --> F["Cache Get reads camera-A + crop-2"]
    F --> G["Cache miss: previous value is in a different namespace"]
    C -. "Value remains here" .-> G
Loading

I reproduced this by replacing grayscale with absolute_static_crop@v1 in the new embedded-cache test scenario. Three frames from one camera produced three cache misses and three retained namespaces. The grayscale control produced one namespace and hits after the first frame. On a long-running stream, the crop path also keeps adding namespaces until the cache blocks are closed.

The crop behavior predates this PR; the newly enabled connection is what exposes it. Previously this workflow failed selector validation rather than running with disconnected state. Please preserve a stable source-video identity, with a stable crop-region identity where separate crop state is needed, and add a multi-frame regression test. The root image's parent ID alone is not necessarily a camera identity.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 978e5c2. create_crop / create_crop_from_tensor take an optional video_crop_identifier. When it's set, it's used for the | crop: suffix in place of crop_identifier. The absolute and relative static crops pass their clamped pixel box (absolute_static_crop:<x_min>,<y_min>,<x_max>,<y_max>). The source video ID is unchanged, the crop region gets an ID that's the same on every frame, and parent_id is still a unique UUID per crop. Other callers (dynamic crop, slicer) don't change.

Regression test: test_embedded_cache_keeps_one_namespace_per_video_across_frames, parametrized over grayscale, absolute and relative static crop. It runs 3 frames from cam-a and 1 from cam-b, then asserts cache hits after the first frame and exactly one retained namespace per camera. Without the fix, both crop cases fail.

description="Input image used to determine the cache namespace. The block extracts the video identifier from the image's video metadata and uses it as the cache namespace. If no video identifier is present, the block uses 'default' as the namespace. The namespace isolates cache entries so different videos or streams have separate cache storage. Use the same image (with the same video identifier) for both Cache Set and Cache Get blocks to access the same cache namespace.",
examples=["$inputs.image", "$steps.input.output"],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
STRING_KIND,
WILDCARD_KIND,
Selector,
WorkflowImageSelector,
)
from roboflow_workflows.execution_engine.entities.workload import (
Discovery,
Expand Down Expand Up @@ -100,7 +99,7 @@ class BlockManifest(WorkflowBlockManifest):
}
)
type: Literal["roboflow_core/cache_set@v1"]
image: WorkflowImageSelector = Field(
image: Selector(kind=[IMAGE_KIND]) = Field(
description="Input image used to determine the cache namespace. The block extracts the video identifier from the image's video metadata and uses it as the cache namespace. If no video identifier is present, the block uses 'default' as the namespace. The namespace isolates cache entries so different videos or streams have separate cache storage. Use the same image (with the same video identifier) for both Cache Set and Cache Get blocks to access the same cache namespace.",
examples=["$inputs.image", "$steps.input.output"],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
WorkflowImageData,
)
from roboflow_workflows.execution_engine.entities.types import (
IMAGE_KIND,
WILDCARD_KIND,
Selector,
StepSelector,
WorkflowImageSelector,
)
from roboflow_workflows.execution_engine.entities.workload import (
Discovery,
Expand Down Expand Up @@ -92,7 +92,7 @@ class DeltaFilterManifest(WorkflowBlockManifest):
},
}
)
image: WorkflowImageSelector
image: Selector(kind=[IMAGE_KIND])
value: Selector(kind=[WILDCARD_KIND]) = Field(
title="Input Value",
description="Value to monitor for changes. Can be any data type (numbers, strings, detection counts, metrics, etc.) from workflow inputs or step outputs. The workflow branch continues to next_steps only when this value differs from the previously cached value for the current video stream. If the value remains the same, the branch terminates to avoid redundant processing. Example: Monitor a line counter count ($steps.line_counter.count_in) and trigger actions only when the count changes.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
IMAGE_KIND,
Selector,
StepSelector,
WorkflowImageSelector,
)
from roboflow_workflows.execution_engine.entities.workload import (
Discovery,
Expand Down Expand Up @@ -113,7 +112,7 @@ class RateLimiterManifest(WorkflowBlockManifest):
description="List of workflow steps to execute if the rate limit allows (i.e., sufficient time has passed since the last execution). These steps receive control flow only when the cooldown period has elapsed, enabling throttled downstream processing. If the cooldown period hasn't elapsed, these steps will not execute as the branch terminates. Each step selector references a block in the workflow that should execute when rate limiting permits.",
examples=[["$steps.upload"]],
)
video_reference_image: Optional[WorkflowImageSelector] = Field(
video_reference_image: Optional[Selector(kind=[IMAGE_KIND])] = Field(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Keep video time advancing for calibration outputs

This now allows Camera Calibration's output as video_reference_image, including through an embedded workflow. Calibration creates its output without the source video metadata. Reading image.video_metadata then supplies fallback values of frame number 0 and FPS 30. The rate limiter calculates time as frame_number / fps, so every frame appears to be at time zero.

flowchart TD
    A["Video frames with advancing frame numbers"] --> B["Camera Calibration drops video metadata"]
    B --> C["Fallback metadata: frame 0, FPS 30"]
    C --> D["Rate limiter sees time 0 on every frame"]
    D --> E["First frame: allow and save time 0"]
    E --> F["Later frames: elapsed time = 0 - 0"]
    F --> G["Positive cooldown never expires: suppress downstream steps"]
Loading

I reproduced this with frames 1, 3, and 5 at 1 FPS and a one-second cooldown. All three should pass. With calibration, only the first frame reached the downstream Cache Set; the grayscale control passed all three. The system-clock fallback does not help: reading the default metadata succeeds, so the limiter overwrites system time with zero without raising an exception.

The metadata loss predates this PR; previously this connection failed selector validation. It now compiles but silently stops downstream processing after the first frame. Please preserve the original video metadata through calibration, or explicitly handle missing metadata in the limiter, and cover this with a multi-frame regression test.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 978e5c2 by keeping the metadata at the source. Camera Calibration now builds its output with WorkflowImageData.copy_and_replace(origin_image_data=image, numpy_image=dst), so it keeps video_metadata. It also keeps workflow_root_ancestor_metadata, which it used to reset to the input's parent. That's the same pattern grayscale and the other single-image transforms use.

Regression test: test_embedded_rate_limiter_follows_video_time_of_step_output_image, parametrized over grayscale and calibration. It runs frames 1, 2, 3 and 5 at 1 FPS with a 1 s cooldown, and every frame reaches the downstream step. The calibration case fails without the fix.

Not changed here: the rate limiter's fallback still never fires when an image has no video metadata. The video_metadata property synthesizes frame 0 / 30 FPS instead of raising, so the except meant to fall back to wall-clock time never runs. Outputs that build a fresh WorkflowImageData, like stitch_images and grid visualization, still hit that path. I'd fix it in a separate PR, since it also changes how still images behave.

description="Optional reference to a video frame image to use for video-time-based timestamp generation. When provided, the rate limiter calculates timestamps based on video metadata (frame number and FPS) rather than system clock time. This is useful when processing video faster than real-time, ensuring rate limiting works correctly relative to video playback time rather than processing speed. If not provided (None), the block uses system clock time (datetime.now()). Only applicable for video processing workflows.",
examples=["$inputs.image"],
default=None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,4 +186,5 @@ def take_static_crop(
offset_x=x_min,
offset_y=y_min,
preserve_video_metadata=True,
video_crop_identifier=f"absolute_static_crop:{x_min},{y_min},{x_max},{y_max}",
)
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ def take_static_crop(
offset_x=x_min,
offset_y=y_min,
preserve_video_metadata=True,
video_crop_identifier=f"absolute_static_crop:{x_min},{y_min},{x_max},{y_max}",
)
# Only numpy is materialised — slice on the host and emit a numpy-backed
# crop; no full-image numpy->device conversion is forced.
Expand All @@ -202,4 +203,5 @@ def take_static_crop(
offset_x=x_min,
offset_y=y_min,
preserve_video_metadata=True,
video_crop_identifier=f"absolute_static_crop:{x_min},{y_min},{x_max},{y_max}",
)
Loading
Loading