Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bounding boxes displaced in the image. #5923

Open
luforestal opened this issue May 27, 2024 · 2 comments
Open

Bounding boxes displaced in the image. #5923

luforestal opened this issue May 27, 2024 · 2 comments
Labels
community:needs-information Evaluated by community team, needs information community:reviewed Issue has been reviewed by the Label Studio Community Team.

Comments

@luforestal
Copy link

Hi, I have exported my annotations in JSON format. But when I try to view them in python, they appear offset almost 100 pixels. Here is an example of how they look in LabelStudio and how I see them in my code.

The code that I'm using:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from PIL import Image

def get_rotated_bounding_box_corners_and_extremes(x_center_pct, y_center_pct, width_pct, height_pct, rotation_deg, image_width, image_height):
    """
    Calculate the four corner coordinates of a rotated bounding box and its extreme values.

    Args:
    x_center_pct (float): x-coordinate of the center of the box in percentage.
    y_center_pct (float): y-coordinate of the center of the box in percentage.
    width_pct (float): Width of the box in percentage.
    height_pct (float): Height of the box in percentage.
    rotation_deg (float): Rotation of the box in degrees.
    image_width (int): Width of the image in pixels.
    image_height (int): Height of the image in pixels.

    Returns:
    corners (list of tuples): List with the (x, y) coordinates of the four corners of the rotated bounding box.
    extremes (tuple): Tuple with (xmin, xmax, ymin, ymax) of the rotated bounding box.
    """

    x_center = x_center_pct / 100 * image_width
    y_center = y_center_pct / 100 * image_height
    width = width_pct / 100 * image_width
    height = height_pct / 100 * image_height

    rotation_rad = np.deg2rad(rotation_deg)

    corners = np.array([
        [x_center - width / 2, y_center - height / 2],
        [x_center + width / 2, y_center - height / 2],
        [x_center + width / 2, y_center + height / 2],
        [x_center - width / 2, y_center + height / 2]
    ])


    rotation_matrix = np.array([
        [np.cos(rotation_rad), -np.sin(rotation_rad)],
        [np.sin(rotation_rad), np.cos(rotation_rad)]
    ])


    rotated_corners = np.dot(corners - np.array([x_center, y_center]), rotation_matrix.T) + np.array([x_center, y_center])


    rotated_corners = rotated_corners.astype(int)

    # Obtener extremos
    x_coords = rotated_corners[:, 0]
    y_coords = rotated_corners[:, 1]
    xmin = x_coords.min()
    xmax = x_coords.max()
    ymin = y_coords.min()
    ymax = y_coords.max()

    return rotated_corners.tolist(), (xmin, xmax, ymin, ymax)

def plot_rotated_bounding_box(image_path, corners):
    """
    Plot the rotated bounding box on the original image.

    Args:
    image_path (str): Path to the original image.
    corners (list of tuples): List with the (x, y) coordinates of the four corners of the rotated bounding box.
    """

    img = Image.open(image_path)
    img_width, img_height = img.size
    print('width', img_width, 'h', img_height)

    fig, ax = plt.subplots(1)
    ax.imshow(img)

    for i in range(len(corners)):
        next_i = (i + 1) % len(corners)
        x_values = [corners[i][0], corners[next_i][0]]
        y_values = [corners[i][1], corners[next_i][1]]
        ax.plot(x_values, y_values, 'r-')

    plt.gca().set_aspect('equal', adjustable='box')
    plt.show()

# Example
image_path = 'save_frame_test.jpg'  
image_width = 640
image_height = 352
x_center_pct =  72.26388590829315
y_center_pct = 87.85889758341253
width_pct = 14.273870065050815  
height_pct = 9.12891897312828
rotation_deg = -25.40638952513592

Screenshots
IMAGE AND LABELS IN LABELSTUDIO
image

IMAGE AND ONE LABEL IN PYTHON
My labels in python (at least one example)
image

Environment (please complete the following information):

  • OS: [e.g. iOS]
  • Label Studio Version [e.g. 0.8.0]
@sajarin
Copy link
Contributor

sajarin commented Jun 3, 2024

hey @luforestal thanks for the bug report. As a sane first step, can we try upgrading Label Studio to the latest? We just want to make sure that this bug is present on the latest version.

@sajarin sajarin added Community Community Feature Requests, Open Issues, Bugs Reported, or Comments community:reviewed Issue has been reviewed by the Label Studio Community Team. community:needs-information Evaluated by community team, needs information and removed Community Community Feature Requests, Open Issues, Bugs Reported, or Comments labels Jun 3, 2024
@mgcrea
Copy link

mgcrea commented Jun 16, 2024

Hey, chiming in to say that I am encountering a similar issue with rotated bounding boxes when trying to work from the JSON export.

I get inconsistencies with the rotation that are visible for angles > 5°.

My example:

LabelStudio
Screenshot 2024-06-16 at 23 02 33

Script output result (using nodejs/sharp to do the drawing and compositing with svg).

Screenshot 2024-06-16 at 23 02 46

It looks like the angle value used in labelstudio does not have the center of the rectangle (cx, cy) for origin (as expected) but the top-left point of the rectangle instead, which is quite strange as the UI actually rotates around the center!

So for me the fix looks like to patch all rects with:

const patchLabelStudioRect = <T extends Rect>(rect: T): T => {
  const { x, y } = rotatePoint({ x: rect.x, y: rect.y }, rect.rotation, getRectCenter(rect));
  rect.x = x;
  rect.y = y;
  return rect;
};

Interesting to dig this up a bit more, do you know where I can find the code responsible for drawing the boxes?

I'm using label-studio 1.2.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
community:needs-information Evaluated by community team, needs information community:reviewed Issue has been reviewed by the Label Studio Community Team.
Projects
None yet
Development

No branches or pull requests

3 participants