Skip to content

Commit

Permalink
Merge branch 'develop' into mk/fix_type_annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
Marishka17 authored Feb 12, 2025
2 parents 5abe1c4 + df5678a commit 0667d47
Show file tree
Hide file tree
Showing 21 changed files with 677 additions and 1,132 deletions.
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

<!-- scriv-insert-here -->

<a id='changelog-2.29.0'></a>
## \[2.29.0\] - 2025-02-10

### Added

- Tasks created from cloud storage can be backed up now
(<https://github.com/cvat-ai/cvat/pull/8972>)

- \[CLI\] `function create-native` now sends the function's declared label types
to the server
(<https://github.com/cvat-ai/cvat/pull/9035>)

### Changed

- When invoking Nuclio functions, labels of type `any` can now be mapped to
labels of all types except `skeleton`
(<https://github.com/cvat-ai/cvat/pull/9050>)

### Fixed

- Fixed invalid server-side track interpolation in tasks with deleted frames
(<https://github.com/cvat-ai/cvat/pull/9059>)

<a id='changelog-2.28.0'></a>
## \[2.28.0\] - 2025-02-06

Expand Down
5 changes: 0 additions & 5 deletions changelog.d/20250204_183545_roman_unknown_any.md

This file was deleted.

5 changes: 5 additions & 0 deletions changelog.d/20250210_172119_roman_missing_kwargs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### Fixed

- \[SDK\] `skeleton_label_spec` now correctly forwards `kwargs` to
`PatchedLabelRequest`
(<https://github.com/cvat-ai/cvat/pull/9087>)
2 changes: 1 addition & 1 deletion cvat-cli/requirements/base.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cvat-sdk==2.28.1
cvat-sdk==2.29.1

attrs>=24.2.0
Pillow>=10.3.0
Expand Down
5 changes: 5 additions & 0 deletions cvat-cli/src/cvat_cli/_internal/commands_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ def execute(
"name": label_spec.name,
}
)

if getattr(label_spec, "type", "any") != "any":
# Add the type conditionally, to stay compatible with older
# CVAT versions when the function doesn't define label types.
remote_function["labels_v2"][-1]["type"] = label_spec.type
else:
raise cvataa.BadFunctionError(
f"Unsupported function spec type: {type(function.spec).__name__}"
Expand Down
2 changes: 1 addition & 1 deletion cvat-cli/src/cvat_cli/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
VERSION = "2.28.1"
VERSION = "2.29.1"
2 changes: 1 addition & 1 deletion cvat-sdk/cvat_sdk/auto_annotation/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ def skeleton_label_spec(
name: str, id: int, sublabels: Sequence[models.SublabelRequest], **kwargs
) -> models.PatchedLabelRequest:
"""Helper factory function for PatchedLabelRequest with type="skeleton"."""
return models.PatchedLabelRequest(name=name, id=id, type="skeleton", sublabels=sublabels)
return label_spec(name, id, type="skeleton", sublabels=sublabels, **kwargs)


# pylint: disable-next=redefined-builtin
Expand Down
2 changes: 1 addition & 1 deletion cvat-sdk/gen/generate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ set -e

GENERATOR_VERSION="v6.0.1"

VERSION="2.28.1"
VERSION="2.29.1"
LIB_NAME="cvat_sdk"
LAYER1_LIB_NAME="${LIB_NAME}/api_client"
DST_DIR="$(cd "$(dirname -- "$0")/.." && pwd)"
Expand Down
2 changes: 1 addition & 1 deletion cvat-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-ui",
"version": "2.28.1",
"version": "2.29.1",
"description": "CVAT single-page application",
"main": "src/index.tsx",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion cvat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

from cvat.utils.version import get_version

VERSION = (2, 28, 1, "alpha", 0)
VERSION = (2, 29, 1, "alpha", 0)

__version__ = get_version(VERSION)
54 changes: 42 additions & 12 deletions cvat/apps/dataset_manager/annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,19 +202,26 @@ def clear_frames(self, frames: Container[int]):
def to_shapes(self,
end_frame: int,
*,
included_frames: Optional[Sequence[int]] = None,
deleted_frames: Sequence[int] | None = None,
included_frames: Sequence[int] | None = None,
include_outside: bool = False,
use_server_track_ids: bool = False
use_server_track_ids: bool = False,
) -> list:
shapes = self.data.shapes
tracks = TrackManager(self.data.tracks, dimension=self.dimension)

if included_frames is not None:
shapes = [s for s in shapes if s["frame"] in included_frames]

return shapes + tracks.to_shapes(end_frame,
included_frames=included_frames, include_outside=include_outside,
use_server_track_ids=use_server_track_ids
if deleted_frames is not None:
shapes = [s for s in shapes if s["frame"] not in deleted_frames]

return shapes + tracks.to_shapes(
end_frame,
included_frames=included_frames,
deleted_frames=deleted_frames,
include_outside=include_outside,
use_server_track_ids=use_server_track_ids,
)

def to_tracks(self):
Expand Down Expand Up @@ -462,10 +469,14 @@ def _modify_unmatched_object(self, obj, end_frame):


class TrackManager(ObjectManager):
def to_shapes(self, end_frame: int, *,
included_frames: Optional[Sequence[int]] = None,
def to_shapes(
self,
end_frame: int,
*,
included_frames: Sequence[int] | None = None,
deleted_frames: Sequence[int] | None = None,
include_outside: bool = False,
use_server_track_ids: bool = False
use_server_track_ids: bool = False,
) -> list:
shapes = []
for idx, track in enumerate(self.objects):
Expand All @@ -479,6 +490,7 @@ def to_shapes(self, end_frame: int, *,
self.dimension,
include_outside=include_outside,
included_frames=included_frames,
deleted_frames=deleted_frames,
):
shape["label_id"] = track["label_id"]
shape["group"] = track["group"]
Expand All @@ -498,10 +510,12 @@ def to_shapes(self, end_frame: int, *,
element_included_frames = set(track_shapes.keys())
if included_frames is not None:
element_included_frames = element_included_frames.intersection(included_frames)
element_shapes = track_elements.to_shapes(end_frame,
element_shapes = track_elements.to_shapes(
end_frame,
included_frames=element_included_frames,
deleted_frames=deleted_frames,
include_outside=True, # elements are controlled by the parent shape
use_server_track_ids=use_server_track_ids
use_server_track_ids=use_server_track_ids,
)

for shape in element_shapes:
Expand Down Expand Up @@ -588,10 +602,24 @@ def _modify_unmatched_object(self, obj, end_frame):

@staticmethod
def get_interpolated_shapes(
track, start_frame, end_frame, dimension, *,
track: dict,
start_frame: int,
end_frame: int,
dimension: DimensionType | str,
*,
included_frames: Optional[Sequence[int]] = None,
deleted_frames: Optional[Sequence[int]] = None,
include_outside: bool = False,
):
# If a task or job contains deleted frames that contain track keyframes,
# these keyframes should be excluded from the interpolation.
# In jobs having specific frames included (e.g. GT jobs),
# deleted frames should not be confused with included frames during track interpolation.
# Deleted frames affect existing shapes in tracks.
# Included frames filter the resulting annotations after interpolation
# to produce the requested track frames.
deleted_frames = deleted_frames or []

def copy_shape(source, frame, points=None, rotation=None):
copied = source.copy()
copied["attributes"] = faster_deepcopy(source["attributes"])
Expand Down Expand Up @@ -930,7 +958,7 @@ def propagate(shape, end_frame, *, included_frames=None):
prev_shape = None
for shape in sorted(track["shapes"], key=lambda shape: shape["frame"]):
curr_frame = shape["frame"]
if included_frames is not None and curr_frame not in included_frames:
if curr_frame in deleted_frames:
continue
if prev_shape and end_frame <= curr_frame:
# If we exceed the end_frame and there was a previous shape,
Expand Down Expand Up @@ -982,6 +1010,8 @@ def propagate(shape, end_frame, *, included_frames=None):
shapes = [
shape for shape in shapes

if shape["frame"] not in deleted_frames

# After interpolation there can be a finishing frame
# outside of the task boundaries. Filter it out to avoid errors.
# https://github.com/openvinotoolkit/cvat/issues/2827
Expand Down
9 changes: 4 additions & 5 deletions cvat/apps/dataset_manager/bindings.py
Original file line number Diff line number Diff line change
Expand Up @@ -508,8 +508,9 @@ def get_frame(idx):
self.stop + 1,
# Skip outside, deleted and excluded frames
included_frames=included_frames,
deleted_frames=self.deleted_frames.keys(),
include_outside=False,
use_server_track_ids=self._use_server_track_ids
use_server_track_ids=self._use_server_track_ids,
),
key=lambda shape: shape.get("z_order", 0)
):
Expand Down Expand Up @@ -1307,14 +1308,12 @@ def get_frame(task_id: int, idx: int) -> ProjectData.Frame:
anno_manager.to_shapes(
task.data.size,
included_frames=task_included_frames,
deleted_frames=task_data.deleted_frames.keys(),
include_outside=False,
use_server_track_ids=self._use_server_track_ids
use_server_track_ids=self._use_server_track_ids,
),
key=lambda shape: shape.get("z_order", 0)
):
if shape['frame'] in task_data.deleted_frames:
continue

assert (task.id, shape['frame']) in self._frame_info

if 'track_id' in shape:
Expand Down
Loading

0 comments on commit 0667d47

Please sign in to comment.