albumentations icon indicating copy to clipboard operation
albumentations copied to clipboard

Keypoint flips are wrong

Open suyashkumar2409 opened this issue 1 year ago • 2 comments

🐛 Bug

To Reproduce

Steps to reproduce the behavior:

  1. Take an image, say of 25 x 25 size, and assume that one of the keypoints is (24.5, 24.5)
  2. The logic in function keypoint_flip would do a calculation like (rows - 1) - x == -0.5
  3. later, this keypoint will get filtered out because it has a negative value

Expected behavior

I would have expected the value to be 0.5 and included in the keypoints list.

Environment

  • Albumentations version (e.g., 0.1.8): 1.3.1
  • Python version (e.g., 3.7):
  • OS (e.g., Linux):
  • How you installed albumentations (conda, pip, source):
  • Any other relevant information:

Additional context

suyashkumar2409 avatar Nov 18 '23 02:11 suyashkumar2409

I had the same concern as well ~~and I feel like a similar issue occurs with ShiftScaleRotate as the center of the image is set as (cols - 1) * 0.5, (rows - 1) * 0.5 instead of just cols * 0.5, rows * 0.5~~ (it seems that the shift has to happen for ShiftScaleRotate so that the rotation matrix that is retrieved from cv2 is accurate)

LozaKiN avatar Nov 20 '23 17:11 LozaKiN

I've tried this method and it was totally correct:

def read_keypoints(keypoints_path):
    df = pd.read_csv(keypoints_path, delimiter=',', names=["labels", "x", "y"])
    # Convert 'x' and 'y' to integer if they are not NaN
    df['x'] = pd.to_numeric(df['x'], errors='coerce').fillna(0).astype(int)
    df['y'] = pd.to_numeric(df['y'], errors='coerce').fillna(0).astype(int)
    return list(zip(df["x"], df["y"]))
def get_augmentation_pipeline():
    return A.Compose([
        A.HorizontalFlip(always_apply=True),
    ], keypoint_params=A.KeypointParams(format='xy', remove_invisible=True))

augmentation_pipeline = get_augmentation_pipeline()
transformed = augmentation_pipeline(image=image, keypoints=keypoints)
print(f"transformed keypoints: {transformed['keypoints']}")

AphroDatalyst avatar Dec 07 '23 12:12 AphroDatalyst

@angle_2pi_range
def keypoint_hflip(keypoint: KeypointInternalType, rows: int, cols: int) -> KeypointInternalType:
    """Flip a keypoint horizontally around the y-axis.

    Args:
        keypoint: A keypoint `(x, y, angle, scale)`.
        rows: Image height.
        cols: Image width.

    Returns:
        A keypoint `(x, y, angle, scale)`.

    """
    x, y, angle, scale = keypoint[:4]
    angle = math.pi - angle
    return (cols - 1) - x, y, angle, scale

for (24.5, 24.5) and image (25, 25) it will return (0.5, 24.5) as expected

ternaus avatar Jun 19 '24 03:06 ternaus