Source code for supervisely.geometry.point_location

# coding: utf-8

# docs
from __future__ import annotations

from copy import deepcopy
from math import floor
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple

from supervisely._utils import unwrap_if_numpy
from supervisely.geometry import validation
from supervisely.geometry.constants import EXTERIOR, INTERIOR, POINTS
from supervisely.io.json import JsonSerializable

if TYPE_CHECKING:
    from supervisely.geometry.image_rotator import ImageRotator


[docs] class PointLocation(JsonSerializable): """2D pixel coordinate (row, col); used for point positions and polygon vertices. Immutable.""" def __init__(self, row: int, col: int): """ PointLocation in (row, col) position. :class:`~supervisely.geometry.point_location.PointLocation` object is immutable. :param row: Position of PointLocation on height. :type row: int or float :param col: Position of PointLocation on width. :type col: int or float :Usage Example: .. code-block:: python import supervisely as sly row = 100 col = 200 loc = sly.PointLocation(row, col) """ self._row = floor(unwrap_if_numpy(row)) self._col = floor(unwrap_if_numpy(col)) @property def row(self) -> int: """ Position of PointLocation on height. :returns: Height of PointLocation. :rtype: int :Usage Example: .. code-block:: python print(loc.row) # Output: 100 """ return self._row @property def col(self) -> int: """ Position of PointLocation on width. :returns: Width of PointLocation. :rtype: int :Usage Example: .. code-block:: python print(loc.col) # Output: 200 """ return self._col
[docs] def to_json(self) -> Dict: """ Convert the PointLocation to a json dict. Read more about `Supervisely format <https://docs.supervisely.com/data-organization/00_ann_format_navi>`_. :returns: Json format as a dict :rtype: dict :Usage Example: .. code-block:: python loc_json = loc.to_json() print(loc_json) # Output: { # "points": { # "exterior": [ # [ # 200, # 100 # ] # ], # "interior": [] # } # } """ packed_obj = {POINTS: {EXTERIOR: [[self.col, self.row]], INTERIOR: []}} return packed_obj
[docs] @classmethod def from_json(cls, data: Dict) -> PointLocation: """ Convert a json dict to PointLocation. Read more about `Supervisely format <https://docs.supervisely.com/data-organization/00_ann_format_navi>`_. :param data: PointLocation in json format as a dict. :type data: dict :returns: PointLocation from json. :rtype: :class:`~supervisely.geometry.point_location.PointLocation` :Usage Example: .. code-block:: python import supervisely as sly loc_json = { "points": { "exterior": [ [ 200, 100 ] ], "interior": [] } } loc = sly.PointLocation.from_json(loc_json) """ validation.validate_geometry_points_fields(data) exterior = data[POINTS][EXTERIOR] if len(exterior) != 1: raise ValueError( '"exterior" field must contain exactly one point to create "PointLocation" object.' ) return cls(row=exterior[0][1], col=exterior[0][0])
[docs] def scale(self, factor: float) -> PointLocation: """ Scale current PointLocation. :param factor: Scale parameter. :type factor: float :returns: Scaled PointLocation. :rtype: :class:`~supervisely.geometry.point_location.PointLocation` :Usage Example: .. code-block:: python # Remember that PointLocation class object is immutable, and we need to assign new instance of PointLocation to a new variable scale_loc = loc.scale(0.75) """ return self.scale_frow_fcol(factor, factor)
[docs] def scale_frow_fcol(self, frow: float, fcol: float) -> PointLocation: """ Calculates new parameters of PointLocation after scaling in horizontal and vertical. :param frow: Scale parameter for height. :type frow: float :param fcol: Scale parameter for width. :type fcol: float :returns: Scaled PointLocation. :rtype: :class:`~supervisely.geometry.point_location.PointLocation` :Usage Example: .. code-block:: python # Remember that PointLocation class object is immutable, and we need to assign new instance of PointLocation to a new variable loc_scale_rc = loc.scale_frow_fcol(0.1, 2.7) """ return PointLocation(row=round(self.row * frow), col=round(self.col * fcol))
[docs] def translate(self, drow: int, dcol: int) -> PointLocation: """ Translate current PointLocation object. :param drow: Horizontal shift. :type drow: int :param dcol: Vertical shift. :type dcol: int :returns: Translated PointLocation. :rtype: :class:`~supervisely.geometry.point_location.PointLocation` :Usage Example: .. code-block:: python # Remember that PointLocation class object is immutable, and we need to assign new instance of PointLocation to a new variable translate_loc = loc.translate(150, 350) """ return PointLocation(row=(self.row + drow), col=(self.col + dcol))
[docs] def rotate(self, rotator: ImageRotator) -> PointLocation: """ Rotates current PointLocation object. :param rotator: Class for object rotation. :type rotator: :class:`~supervisely.geometry.image_rotator.ImageRotator` :returns: Rotated PointLocation. :rtype: :class:`~supervisely.geometry.point_location.PointLocation` :Usage Example: .. code-block:: python from supervisely.geometry.image_rotator import ImageRotator # Remember that PointLocation class object is immutable, and we need to assign new instance of PointLocation to a new variable height, width = 300, 400 rotator = ImageRotator((height, width), 25) rotate_loc = loc.rotate(rotator) """ return rotator.transform_point(self)
[docs] def resize(self, in_size: Tuple[int, int], out_size: Tuple[int, int]) -> PointLocation: """ Resize current PointLocation object. :param in_size: Input image size (height, width) to which belongs PointLocation. :type in_size: Tuple[int, int] :param out_size: Desired output image size (height, width) to which belongs PointLocation. :type out_size: Tuple[int, int] :returns: Resized PointLocation. :rtype: :class:`~supervisely.geometry.point_location.PointLocation` :Usage Example: .. code-block:: python # Remember that PointLocation class object is immutable, and we need to assign new instance of PointLocation to a new variable in_height, in_width = 300, 400 out_height, out_width = 600, 800 resize_loc = loc.resize((in_height, in_width), (out_height, out_width)) """ from supervisely.imaging import image as sly_image new_size = sly_image.restore_proportional_size(in_size=in_size, out_size=out_size) frow = new_size[0] / in_size[0] fcol = new_size[1] / in_size[1] return self.scale_frow_fcol(frow=frow, fcol=fcol)
[docs] def fliplr(self, img_size: Tuple[int, int]) -> PointLocation: """ Flips current PointLocation object in horizontal. :param img_size: Input image size (height, width) to which belongs PointLocation. :type img_size: Tuple[int, int] :returns: Flipped PointLocation. :rtype: :class:`~supervisely.geometry.point_location.PointLocation` :Usage Example: .. code-block:: python # Remember that PointLocation class object is immutable, and we need to assign new instance of PointLocation to a new variable height, width = 300, 400 fliplr_loc = loc.fliplr((height, width)) """ return PointLocation(row=self.row, col=(img_size[1] - self.col))
[docs] def flipud(self, img_size: Tuple[int, int]) -> PointLocation: """ Flips current PointLocation object in vertical. :param img_size: Input image size (height, width) to which belongs PointLocation. :type img_size: Tuple[int, int] :returns: Flipped PointLocation. :rtype: :class:`~supervisely.geometry.point_location.PointLocation` :Usage Example: .. code-block:: python # Remember that PointLocation class object is immutable, and we need to assign new instance of PointLocation to a new variable height, width = 300, 400 flipud_loc = loc.flipud((height, width)) """ return PointLocation(row=(img_size[0] - self.row), col=self.col)
[docs] def clone(self) -> PointLocation: """ Makes a copy of the PointLocation object. :returns: Copied PointLocation. :rtype: :class:`~supervisely.geometry.point_location.PointLocation` :Usage Example: .. code-block:: python # Remember that PointLocation class object is immutable, and we need to assign new instance of PointLocation to a new variable new_loc = loc.clone() """ return deepcopy(self)
def _flip_row_col_order(coords): """ """ if not all(len(x) == 2 for x in coords): raise ValueError( "Flipping row and column order values is only possible within tuples of 2 elements." ) return [[y, x] for x, y in coords] def _maybe_flip_row_col_order(coords, flip=False): """ """ return _flip_row_col_order(coords) if flip else coords def points_to_row_col_list( points: List[PointLocation], flip_row_col_order: Optional[bool] = False ) -> List[List[int]]: """ Convert list of PointLocation objects to list of coords. :param points: List of PointLocation objects. :type points: List[:class:`~supervisely.geometry.point_location.PointLocation`] :param flip_row_col_order: Flips row col coords if True. :type flip_row_col_order: bool, optional :returns: List of coords :rtype: list :Usage Example: .. code-block:: python import supervisely as sly loc_1 = sly.PointLocation(100, 200) loc_2 = sly.PointLocation(300, 400) points_row_col = points_to_row_col_list([loc_1, loc_2]) print(points_row_col) # Output: [[100, 200], [300, 400]] """ return _maybe_flip_row_col_order( coords=[[p.row, p.col] for p in points], flip=flip_row_col_order ) def row_col_list_to_points( data: List[List[int, int]], flip_row_col_order: Optional[bool] = False, do_round: Optional[bool] = False, ) -> List[PointLocation]: """ Convert list of coords to list of PointLocation objects. :param data: List of coords. :type data: List[List[int, int]] :param flip_row_col_order: Flip row col coords if True. :type flip_row_col_order: bool, optional :param do_round: Round PointLocation params if True. :type do_round: bool, optional :returns: List of PointLocation objects. :rtype: List[:class:`~supervisely.geometry.point_location.PointLocation`] :Usage Example: .. code-block:: python row_1, col_1 = 100, 200 row_2, col_2 = 300, 400 coords = [(row_1, col_1), (row_2, col_2)] locs = row_col_list_to_points(coords) """ def _maybe_round(v): return v if not do_round else round(v) return [ PointLocation(row=_maybe_round(r), col=_maybe_round(c)) for r, c in _maybe_flip_row_col_order(data, flip=flip_row_col_order) ]