Source code for lablib.operators.repositions
from dataclasses import dataclass, field
from typing import List
from lablib.lib.utils import (
identity_matrix,
transpose_matrix,
matrix_to_csv,
calculate_matrix,
mult_matrix,
)
[docs]
@dataclass
class Transform:
"""Transform operator for repositioning images.
Note:
The transformations are applied in the following order:
``translate, rotate, scale, center, invert, skewX, skewY``.
The :obj:`Transform.skew_order` parameter determines the order in which the skewX and skewY transformations are applied.
Attributes:
translate (List[float]): The translation vector.
rotate (float): The rotation angle in degrees.
scale (List[float]): The scaling vector.
center (List[float]): The center of the transformation.
invert (bool): Invert the transformation.
skewX (float): The skew in the X direction.
skewY (float): The skew in the Y direction.
skew_order (str): The order in which the skewX and skewY
transformations are applied.
"""
translate: List[float] = field(default_factory=lambda: [0.0, 0.0])
rotate: float = 0.0
# needs to be treated as a list of floats but can be single float
scale: List[float] = field(default_factory=lambda: [1.0, 1.0])
center: List[float] = field(default_factory=lambda: [0.0, 0.0])
invert: bool = False
skewX: float = 0.0
skewY: float = 0.0
skew_order: str = "XY"
[docs]
def to_oiio_args(self) -> List[str]:
"""Gets the arguments for ``oiiotool``.
Uses :obj:`lablib.lib` to work with transformation matrices.
Returns:
List[str]: Arguments for OIIO.
"""
matrix = calculate_matrix(
t=self.translate, r=self.rotate, s=self.scale, c=self.center
)
identity = identity_matrix()
matrix_xfm = mult_matrix(identity, matrix)
matrix_tr = transpose_matrix(matrix_xfm)
warp_cmd = matrix_to_csv(matrix_tr)
warp_flag = "--warp:filter=cubic:recompute_roi=1" # TODO: expose filter
return [warp_flag, warp_cmd]
[docs]
@classmethod
def from_node_data(cls, data) -> "Transform":
"""Create a :obj:`Transform` object from node data.
Attributes:
data (dict): The node data.
Returns:
Transform: The transform object.
"""
scale = data.get("scale", [0.0, 0.0])
if isinstance(scale, (int, float)):
scale = [scale, scale]
return cls(
translate=data.get("translate", [0.0, 0.0]),
rotate=data.get("rotate", 0.0),
scale=scale,
center=data.get("center", [0.0, 0.0]),
invert=data.get("invert", False),
skewX=data.get("skewX", 0.0),
skewY=data.get("skewY", 0.0),
skew_order=data.get("skew_order", "XY"),
)
[docs]
@dataclass
class Crop:
"""Operator for cropping images.
Attributes:
box (List[int]): The crop box.
"""
box: List[int] = field(default_factory=lambda: [0, 0, 1920, 1080])
# NOTE: could also be called with width, height, x, y
[docs]
def to_oiio_args(self) -> List[str]:
"""Gets the arguments for ``oiiotool``.
Returns:
List[int]: Arguments for OIIO.
"""
return [
"--crop",
# using xmin,ymin,xmax,ymax
f"{self.box[0]},{self.box[1]},{self.box[2]},{self.box[3]}",
]
[docs]
@classmethod
def from_node_data(cls, data) -> "Crop":
"""Create a :obj:`Crop` object from node data.
Attributes:
data (dict): The node data.
Returns:
Crop: The crop object.
"""
return cls(box=data.get("box", [0, 0, 1920, 1080]))
[docs]
@dataclass
class Mirror2:
"""Operator for mirroring images.
TODO:
This should be ``Mirror2 -> Mirror2D`` looking at :obj:`CornerPin2D`.
Attributes:
flop (bool): Mirror vertically.
flip (bool): Mirror horizontally.
"""
flop: bool = False
flip: bool = False
[docs]
def to_oiio_args(self):
"""Gets the arguments for ``oiiotool``.
Returns:
List[str]: Arguments for OIIO.
"""
args = []
if self.flop:
args.append("--flop")
if self.flip:
args.append("--flip")
return args
[docs]
@classmethod
def from_node_data(cls, data) -> "Mirror2":
"""Create :obj:`Mirror2` from node data.
Attributes:
data (dict): The node data.
Returns:
Mirror2: The mirror object.
"""
return cls(flop=data.get("flop", False), flip=data.get("flip", False))
[docs]
@dataclass
class CornerPin2D:
"""Operator for corner pinning images.
Danger:
This operator is not yet tested or used in the codebase.
Attributes:
from1 (List[float]): The first corner of the source image.
from2 (List[float]): The second corner of the source image.
from3 (List[float]): The third corner of the source image.
from4 (List[float]): The fourth corner of the source image.
to1 (List[float]): The first corner of the destination image.
to2 (List[float]): The second corner of the destination image.
to3 (List[float]): The third corner of the destination image.
to4 (List[float]): The fourth corner of the destination image.
"""
from1: List[float] = field(default_factory=lambda: [0.0, 0.0])
from2: List[float] = field(default_factory=lambda: [0.0, 0.0])
from3: List[float] = field(default_factory=lambda: [0.0, 0.0])
from4: List[float] = field(default_factory=lambda: [0.0, 0.0])
to1: List[float] = field(default_factory=lambda: [0.0, 0.0])
to2: List[float] = field(default_factory=lambda: [0.0, 0.0])
to3: List[float] = field(default_factory=lambda: [0.0, 0.0])
to4: List[float] = field(default_factory=lambda: [0.0, 0.0])
[docs]
def to_oiio_args(self):
"""Gets the arguments for ``oiiotool``.
Returns:
List[str]: Arguments for OIIO.
"""
# TODO: use matrix operation from utils.py
return []
[docs]
@classmethod
def from_node_data(cls, data) -> "CornerPin2D":
"""Create :obj:`CornerPin2D` from node data.
Attributes:
data (dict): The node data.
Returns:
CornerPin2D: The corner pin object.
"""
return cls(
from1=data.get("from1", [0.0, 0.0]),
from2=data.get("from2", [0.0, 0.0]),
from3=data.get("from3", [0.0, 0.0]),
from4=data.get("from4", [0.0, 0.0]),
to1=data.get("to1", [0.0, 0.0]),
to2=data.get("to2", [0.0, 0.0]),
to3=data.get("to3", [0.0, 0.0]),
to4=data.get("to4", [0.0, 0.0]),
)