import abc
from typing import List, Iterable, Union, Callable
from gbvision.constants.types import Frame, Location, Shape, FilterFunction, Contour, Number
from gbvision.models.contours import find_contours
from gbvision.models.system import EMPTY_PIPELINE, EMPTY_GAME_OBJECT
from gbvision.utils.cameras.camera import Camera
from gbvision.utils.game_object import GameObject
from gbvision.utils.shapes.base_shape import BaseShapeType
from gbvision.utils.thresholds.threshold import Threshold
[docs]class ShapeFinder(abc.ABC):
"""
This is an abstract class that represents an object finder
An object finder is a type that outputs an object's 3d real location based on an of it image it's
GameObject real-life parameters
:param threshold_func: The threshold function used to find the shapes in the frame
:param game_object: The game object descriptor for the real-life parameters of the finder's target
:param contours_hook: Optional. A pipeline to run on the contours after finding them
:param shapes_hook: Optional. A pipeline to run on the shapes after parsing the contours to them
"""
def __init__(
self,
threshold_func: Union[FilterFunction, Threshold],
game_object: GameObject = EMPTY_GAME_OBJECT,
contours_hook: Callable[[List[Contour]], List[Contour]] = EMPTY_PIPELINE,
shapes_hook: Callable[[List[Shape]], List[Shape]] = EMPTY_PIPELINE,
):
self.game_object = game_object
self._find_shapes_pipeline = EMPTY_PIPELINE + \
threshold_func + \
find_contours + \
contours_hook + \
self._base_shape().from_contours + \
shapes_hook
def __call__(self, frame: Frame, camera: Camera) -> List[Location]:
"""
Finds all instances of the object in the frame
:param frame: The frame in which to find
:param camera: The camera used to read the frame
:return: All object of this type in the physical space
"""
return self.locations_from_shapes(self.find_shapes(frame), camera)
@staticmethod
@abc.abstractmethod
def _base_shape() -> BaseShapeType:
"""
Returns the base shape matching this finder
:return: The base shape (a class that inherits from BaseShape)
"""
[docs] def find_shapes_unsorted(self, frame: Frame) -> List[Shape]:
"""
Finds all the shapes and returns them in frame after full pipeline (not sorted)
:param: The current frame the finder searches in
:return: A list of shapes: see gbvision/constants/types
"""
return self._find_shapes_pipeline(frame)
[docs] def find_shapes(self, frame: Frame) -> List[Shape]:
"""
Finds all the shapes and returns them in frame after full pipeline (sorted)
:param: The current frame the finder searches in
:return: A list of shapes: see gbvision/constants/types
"""
return self._base_shape().sort(self.find_shapes_unsorted(frame))
[docs] def find_and_filter_shapes(self, frame: Frame) -> List[Shape]:
"""
Finds all the shapes and returns them in frame after full pipeline (sorted), removes all inner shapes
:param: The current frame the finder searches in
:return: A list of shapes: see gbvision/constants/types
"""
return self._base_shape().filter_inners(self.find_shapes(frame))
[docs] def locations_from_shapes(self, shapes: Iterable[Shape], camera: Camera) -> List[Location]:
"""
Finds the locations of the shapes based on the shape descriptor and camera constants
:param shapes: A list of the shapes
:param camera: The camera used to capture the frame that the shapes were found in
:return: A list of the locations of all the shapes
"""
return list(
map(lambda shape: self.game_object.location(camera,
self._base_shape().root_area(shape),
self._base_shape().center(shape)), shapes))