aboutsummaryrefslogtreecommitdiff
path: root/src/argaze/AreaOfInterest/AOIFeatures.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/argaze/AreaOfInterest/AOIFeatures.py')
-rw-r--r--src/argaze/AreaOfInterest/AOIFeatures.py67
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."""