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 Dict, List, Optional, Tuple

import supervisely as sly
from supervisely._utils import unwrap_if_numpy
from supervisely.geometry import validation
from supervisely.geometry.constants import EXTERIOR, INTERIOR, POINTS
from supervisely.imaging import image as sly_image
from supervisely.io.json import JsonSerializable


[docs]class PointLocation(JsonSerializable): """ PointLocation in (row, col) position. :class:`PointLocation<PointLocation>` object is immutable. :param row: Position of PointLocation object on height. :type row: int or float :param col: Position of PointLocation object 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) """ def __init__(self, row: int, col: int): self._row = floor(unwrap_if_numpy(row)) self._col = floor(unwrap_if_numpy(col)) @property def row(self) -> int: """ Position of PointLocation on height. :return: Height of PointLocation :rtype: :class:`int` :Usage example: .. code-block:: python print(loc.row) # Output: 100 """ return self._row @property def col(self) -> int: """ Position of PointLocation on width. :return: Width of PointLocation :rtype: :class:`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.supervise.ly/data-organization/00_ann_format_navi>`_. :return: Json format as a dict :rtype: :class:`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.supervise.ly/data-organization/00_ann_format_navi>`_. :param data: PointLocation in json format as a dict. :type data: dict :return: PointLocation object :rtype: :class:`PointLocation<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 :return: PointLocation object :rtype: :class:`PointLocation<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 :return: PointLocation object :rtype: :class:`PointLocation<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 :return: PointLocation object :rtype: :class:`PointLocation<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: sly.geometry.image_rotator.ImageRotator) -> PointLocation: """ Rotates current PointLocation object. :param rotator: ImageRotator object for rotation. :type rotator: ImageRotator :return: PointLocation object :rtype: :class:`PointLocation<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 :class:`PointLocation<PointLocation>` object. :type in_size: Tuple[int, int] :param out_size: Desired output image size (height, width) to which belongs :class:`PointLocation<PointLocation>` object. :type out_size: Tuple[int, int] :return: PointLocation object :rtype: :class:`PointLocation<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)) """ 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 :class:`PointLocation<PointLocation>` object. :type img_size: Tuple[int, int] :return: PointLocation object :rtype: :class:`PointLocation<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 :class:`PointLocation<PointLocation>` object. :type img_size: Tuple[int, int] :return: PointLocation object :rtype: :class:`PointLocation<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. :return: PointLocation object :rtype: :class:`PointLocation<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[PointLocation] :param flip_row_col_order: Flips row col coords if True. :type flip_row_col_order: bool, optional :return: List of coords :rtype: :class:`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 :return: List of PointLocation objects :rtype: :class:`List[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) ]