diff options
Diffstat (limited to 'src/argaze/AreaOfInterest/AOIFeatures.py')
-rw-r--r-- | src/argaze/AreaOfInterest/AOIFeatures.py | 67 |
1 files changed, 56 insertions, 11 deletions
diff --git a/src/argaze/AreaOfInterest/AOIFeatures.py b/src/argaze/AreaOfInterest/AOIFeatures.py index b78a104..a33db26 100644 --- a/src/argaze/AreaOfInterest/AOIFeatures.py +++ b/src/argaze/AreaOfInterest/AOIFeatures.py @@ -4,32 +4,77 @@ from dataclasses import dataclass, field from argaze import DataStructures +import cv2 as cv +import matplotlib.path as mpath +import numpy + @dataclass -class AreaOfInterest(): +class AreaOfInterest(numpy.ndarray): """Define 2D/3D Area Of Interest.""" - dimension: int = field(init=False, default=None) - """number of the coordinates to code vertice or pointer positions.""" + def dimension(self): + """Number of coordinates coding area points positions.""" + return self.shape[1] + + def center(self): + """Center of mass""" + return self.mean(axis=0) + + def clockwise(self): + """Get area points in clocwise order.""" + + if self.dimension() != 2: + raise RuntimeError(f'Bad area dimension ({self.dimension()})') + + O = self.center() + OP = (self - O) / numpy.linalg.norm(self - O) + angles = numpy.arctan2(OP[:, 1], OP[:, 0]) + + return self[numpy.argsort(angles)] + + def looked(self, gaze_position): + """Is gaze position inside area ?""" + + if self.dimension() != 2: + raise RuntimeError(f'Bad area dimension ({self.dimension()})') + + return mpath.Path(self).contains_points([(gaze_position.x, gaze_position.y)])[0] + + def look_at(self, gaze_position): + """Get where the area is looked.""" + + if self.dimension() != 2: + raise RuntimeError(f'Bad area dimension ({self.dimension()})') + + P = numpy.array([gaze_position.x, gaze_position.y]) + + clockwise_area = self.clockwise() + + O = clockwise_area[0] + OX, OY = clockwise_area[1] - O, clockwise_area[-1] - O + OP = P - O - vertices: list(tuple()) - """for each vertices of the area.""" + return numpy.array([numpy.dot(OP, OX) / numpy.dot(OX, OX), numpy.dot(OP, OY) / numpy.dot(OY, OY)]) - pointer: tuple = None - """to set where the area is looked.""" + def draw(self, frame, color): - def __post_init__(self): + # Draw form + cv.line(frame, self[-1], self[0], color, 1) + for A, B in zip(self, self[1:]): + cv.line(frame, A, B, color, 1) - self.dimension = len(self.vertices[0]) + # Draw center + cv.circle(frame, self.center().astype(int), 1, color, -1) @dataclass class AOIScene(): """Define 2D/3D AOI scene.""" dimension: int = field(init=False, default=None) - """dimension of the AOIs in scene.""" + """Dimension of the AOIs in scene.""" areas: dict = field(init=False, default_factory=dict) - """all aois in the scene.""" + """All aois in the scene.""" def append(self, name, aoi: AreaOfInterest): """Add an aoi to the scene.""" |