Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix(compose): preserve keypoint label mappings with instance binding#261

Merged
ternaus merged 2 commits into
mainfrom
codex-fix-keypoint-label-mapping-instance-binding
May 11, 2026
Merged

fix(compose): preserve keypoint label mappings with instance binding#261
ternaus merged 2 commits into
mainfrom
codex-fix-keypoint-label-mapping-instance-binding

Conversation

@ternaus
Copy link
Copy Markdown
Contributor

@ternaus ternaus commented May 11, 2026

Summary by Sourcery

Preserve public keypoint label field names and mappings when instance binding is enabled in Compose, ensuring serialization reflects user-facing labels.

Bug Fixes:

  • Fix loss or corruption of keypoint label mappings when instance binding rewrites keypoint label fields to internal names.

Enhancements:

  • Ensure keypoint label_mapping is transparently remapped between internal and public field names in Compose during binding and in to_dict outputs.

Tests:

  • Add regression tests to verify keypoint label mappings use public field names and that internal instance-binding fields are excluded from serialized configs.

Copilot AI review requested due to automatic review settings May 11, 2026 12:38
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 11, 2026

Reviewer's Guide

This PR fixes how Compose handles keypoint label mappings when instance binding is enabled by remapping internal label-field names back to public names in both runtime transformations and serialization, and adds tests to validate correct behavior.

Sequence diagram for label_mapping flow with keypoint instance binding

sequenceDiagram
    actor User
    participant Compose
    participant KeypointParams as KP
    participant Transform as T

    User->>Compose: create_with_instance_binding(label_fields, label_mapping)
    Compose->>KP: initialize(label_fields, label_mapping)

    Compose->>Compose: _apply_keypoints_instance_binding(targets)
    Compose->>Compose: build _kp_label_map(internal_field -> user_field)
    Compose->>Compose: user_to_internal = reverse(_kp_label_map)
    Compose->>KP: KP.label_mapping = _remap_label_mapping_fields(KP.label_mapping, user_to_internal)
    Compose->>KP: KP.label_fields = internal_fields + _KP_INSTANCE_ID
    Compose->>KP: KP.remove_invisible = False
    Compose->>KP: KP.check_each_transform = False

    loop for each image
        User->>Compose: __call__(image, keypoints, labels)
        Compose->>T: apply(image, keypoints, labels, label_mapping)
        T-->>Compose: transformed_image, transformed_keypoints, labels
    end

    User->>Compose: to_dict()
    Compose->>Compose: _get_init_params()
    Compose->>Compose: _remap_label_mapping_fields(KP.label_mapping, _kp_label_map)
    Compose-->>User: serialized_config_with_user_label_fields
Loading

Class diagram for Compose keypoint label_mapping handling with instance binding

classDiagram
    class Compose {
        - _kp_label_map: dict[str, str]
        + _apply_keypoints_instance_binding(targets: frozenset[str]) void
        + _set_processors_for_transforms(transforms: TransformsSeqType) void
        + _clean_params_dict(kp_params: KeypointParams, params_dict: dict[str, Any], label_map: dict[str, str]) dict[str, Any]
        + _get_init_params() dict[str, Any]
        + _remap_label_mapping_fields(label_mapping: dict[str, dict[str, dict[Any, Any]]], field_map: dict[str, str]) dict[str, dict[str, dict[Any, Any]]]
    }

    class KeypointParams {
        + label_fields: list[str]
        + label_mapping: dict[str, dict[str, dict[Any, Any]]]
        + remove_invisible: bool
        + check_each_transform: bool
        + angle_in_degrees: bool
    }

    Compose --> KeypointParams : configures

    class InstanceBindingInternalFields {
        + _ibl_kp_name: str
        + _KP_INSTANCE_ID: str
        + _INSTANCE_ID_FERRY_KEYS: set[str]
    }

    Compose ..> InstanceBindingInternalFields : uses

    %% Highlight key internal data flow
    Compose : _apply_keypoints_instance_binding()
    Compose :   - build _kp_label_map
    Compose :   - remap kp_params.label_mapping to internal fields
    Compose : _clean_params_dict()
    Compose :   - remap label_fields and label_mapping back to user fields
    Compose : _get_init_params()
    Compose :   - remap kp.label_mapping from internal to user fields for serialization
Loading

File-Level Changes

Change Details Files
Ensure keypoint label mappings use public label field names when instance binding rewrites label_fields to internal names.
  • Add a new unit test that constructs a HorizontalFlip transform with keypoint label_mapping using a public field ('name') and verifies that keypoint_labels retain correctly remapped names after transformation.
  • Update the to_dict_excludes_hidden_fields test to configure keypoint_params with label_fields and label_mapping, and assert that private/internal label fields and mappings are stripped while public ones are preserved.
tests/test_instance_binding.py
Remap keypoint label_mapping keys between user-facing and internal label field names throughout Compose’s instance binding and serialization lifecycle.
  • In _apply_keypoints_instance_binding, build a user-to-internal field map from _kp_label_map and rewrite kp_params.label_mapping to use internal field names before augmentations run.
  • Introduce _remap_label_mapping_fields helper that copies a label_mapping while renaming label-field keys via a provided field_map and preserving per-transform mappings.
  • Extend _clean_params_dict to remap label_mapping back from internal to public field names using label_map when serializing parameters.
  • Update _get_init_params to serialize keypoint label_mapping using public field names by applying _remap_label_mapping_fields with the stored _kp_label_map.
albumentations/core/composition.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes instance binding behavior in Compose so that keypoint label_mapping continues to work when keypoint label fields are temporarily rewritten to internal (hidden) field names for instance binding.

Changes:

  • Remap KeypointParams.label_mapping field keys from user label field names (e.g. "name") to internal instance-binding field names (e.g. "_ibl_kp_name") when instance binding is enabled for keypoints.
  • Ensure to_dict_private() and _get_init_params() convert internal keypoint label mapping field names back to the public/user field names.
  • Add/extend tests to verify correct label swapping behavior and serialization output when instance binding is active.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
albumentations/core/composition.py Adds label-mapping field-key remapping for bound keypoint label fields and restores public names during serialization/init-param export.
tests/test_instance_binding.py Adds a regression test for keypoint label swapping with instance binding and checks that serialization omits internal label-mapping keys.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 33424c6859

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

internal_fields = [f"_ibl_kp_{f}" for f in user_fields]
self._kp_label_map = dict(zip(internal_fields, user_fields, strict=True))
user_to_internal = {user_name: internal_name for internal_name, user_name in self._kp_label_map.items()}
kp_params.label_mapping = self._remap_label_mapping_fields(kp_params.label_mapping, user_to_internal)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep keypoint label swaps within each instance

When instance_binding is enabled, remapping the public label mapping to _ibl_kp_* makes the existing keypoint swap logic run on the flattened keypoint array. That swap uses global np.where matches over all rows and swaps entire rows, including _kp_instance_id, so inputs where different instances do not each contain both sides of a mapping (for example one instance has only left_eye and another only right_eye) will either swap keypoints between instances during repack or hit a shape mismatch. The mapping needs to be applied per _KP_INSTANCE_ID group, or otherwise avoid global row swaps for bound instances.

Useful? React with 👍 / 👎.

@ternaus ternaus merged commit eec2c46 into main May 11, 2026
22 checks passed
@ternaus ternaus deleted the codex-fix-keypoint-label-mapping-instance-binding branch May 11, 2026 12:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants