aboutsummaryrefslogtreecommitdiff
path: root/src/argaze/AreaOfInterest
diff options
context:
space:
mode:
authorTheo De La Hogue2023-09-22 22:06:20 +0200
committerTheo De La Hogue2023-09-22 22:06:20 +0200
commitb947573f7dbccb5b2b13b64677192145f2dbb864 (patch)
tree20cd0cb471b245445bd493c3e8e24fa7baf45d8b /src/argaze/AreaOfInterest
parent1f36c34242791145a1b33dd17cf351018456310f (diff)
downloadargaze-b947573f7dbccb5b2b13b64677192145f2dbb864.zip
argaze-b947573f7dbccb5b2b13b64677192145f2dbb864.tar.gz
argaze-b947573f7dbccb5b2b13b64677192145f2dbb864.tar.bz2
argaze-b947573f7dbccb5b2b13b64677192145f2dbb864.tar.xz
Working on AOI frame feature: now 2D AOI in scene frame are merged into 3D AOI in scene layer.
Diffstat (limited to 'src/argaze/AreaOfInterest')
-rw-r--r--src/argaze/AreaOfInterest/AOI2DScene.py31
-rw-r--r--src/argaze/AreaOfInterest/AOI3DScene.py9
-rw-r--r--src/argaze/AreaOfInterest/AOIFeatures.py81
3 files changed, 96 insertions, 25 deletions
diff --git a/src/argaze/AreaOfInterest/AOI2DScene.py b/src/argaze/AreaOfInterest/AOI2DScene.py
index 73c977f..f6b8dcb 100644
--- a/src/argaze/AreaOfInterest/AOI2DScene.py
+++ b/src/argaze/AreaOfInterest/AOI2DScene.py
@@ -10,7 +10,7 @@ __license__ = "BSD"
from typing import TypeVar, Tuple
from argaze import DataStructures
-from argaze.AreaOfInterest import AOIFeatures
+from argaze.AreaOfInterest import AOIFeatures, AOI3DScene
from argaze import GazeFeatures
import cv2
@@ -19,6 +19,9 @@ import numpy
AOI2DSceneType = TypeVar('AOI2DScene', bound="AOI2DScene")
# Type definition for type annotation convenience
+AOI3DSceneType = TypeVar('AOI3DScene', bound="AOI3DScene")
+# Type definition for type annotation convenience
+
class AOI2DScene(AOIFeatures.AOIScene):
"""Define AOI 2D scene."""
@@ -89,6 +92,7 @@ class AOI2DScene(AOIFeatures.AOIScene):
yield name, aoi, matched_region, aoi_ratio, circle_ratio
+ '''DEPRECATED: but maybe still usefull?
def reframe(self, aoi: AOIFeatures.AreaOfInterest, size: tuple) -> AOI2DSceneType:
"""
Reframe whole scene to a scene bounded by a 4 vertices 2D AOI.
@@ -120,3 +124,28 @@ class AOI2DScene(AOIFeatures.AOIScene):
aoi2D_scene[name] = numpy.matmul(aoi2D - Src_origin, M.T)
return aoi2D_scene
+ '''
+ def dimensionalize(self, frame_3d: AOIFeatures.AreaOfInterest, size: tuple) -> AOI3DSceneType:
+ """
+ Convert to 3D scene considering it is inside of 3D rectangular frame.
+
+ Parameters:
+ aoi_frame_3d: rectangle 3D AOI to use as referential plane
+ size: size of the frame in pixel
+
+ Returns:
+ AOI 3D scene
+ """
+
+ # Vectorize outter_axis function
+ vfunc = numpy.vectorize(frame_3d.outter_axis)
+
+ # Prepare new AOI 3D scene
+ aoi3D_scene = AOI3DScene.AOI3DScene()
+
+ for name, aoi2D in self.items():
+
+ X, Y = (aoi2D / size).T
+ aoi3D_scene[name] = numpy.array(vfunc(X, Y)).T.view(AOIFeatures.AreaOfInterest)
+
+ return aoi3D_scene
diff --git a/src/argaze/AreaOfInterest/AOI3DScene.py b/src/argaze/AreaOfInterest/AOI3DScene.py
index 8ea6048..bfe189a 100644
--- a/src/argaze/AreaOfInterest/AOI3DScene.py
+++ b/src/argaze/AreaOfInterest/AOI3DScene.py
@@ -108,9 +108,9 @@ class AOI3DScene(AOIFeatures.AOIScene):
file.close()
- # retreive all aoi3D vertices
+ # retreive all aoi3D vertices and sort them in clockwise order
for name, face in faces.items():
- aoi3D = AOIFeatures.AreaOfInterest([ vertices[i-1] for i in face ])
+ aoi3D = AOIFeatures.AreaOfInterest([ vertices[i-1] for i in reversed(face) ])
aois_3d[name] = aoi3D
except IOError:
@@ -149,8 +149,9 @@ class AOI3DScene(AOIFeatures.AOIScene):
file.write('s off\n')
file.write(vertices_ids + '\n')
+ '''DEPRECATED: but maybe still usefull?
@property
- def orthogonal_projection(self) -> AOI2DScene.AOI2DScene:
+ def orthogonal_projection(self) -> AOI2DSceneType:
"""
Orthogonal projection of whole scene.
@@ -169,7 +170,7 @@ class AOI3DScene(AOIFeatures.AOIScene):
K = numpy.array([[scene_size[1]/scene_size[0], 0.0, 0.5], [0.0, 1., 0.5], [0.0, 0.0, 1.0]])
return self.project(tvec, rvec, K)
-
+ '''
def vision_cone(self, cone_radius, cone_height, cone_tip=[0., 0., 0.], cone_direction=[0., 0., 1.]) -> Tuple[AOI3DSceneType, AOI3DSceneType]:
"""Get AOI which are inside and out a given cone field.
diff --git a/src/argaze/AreaOfInterest/AOIFeatures.py b/src/argaze/AreaOfInterest/AOIFeatures.py
index e5585c5..ffaf882 100644
--- a/src/argaze/AreaOfInterest/AOIFeatures.py
+++ b/src/argaze/AreaOfInterest/AOIFeatures.py
@@ -127,8 +127,8 @@ class AreaOfInterest(numpy.ndarray):
return mpath.Path(self).contains_points([point])[0]
- def inner_axis(self, point: tuple) -> tuple:
- """Transform the coordinates from the global axis to the AOI's axis.
+ def inner_axis(self, x: float, y: float) -> tuple:
+ """Transform a point coordinates from global axis to AOI axis.
!!! warning
Available for 2D AOI only.
!!! danger
@@ -143,35 +143,30 @@ class AreaOfInterest(numpy.ndarray):
Dst = numpy.array([[0., 0.], [1., 0.], [1., 1.], [0., 1.]]).astype(numpy.float32)
P = cv2.getPerspectiveTransform(Src, Dst)
- X = numpy.append(numpy.array(numpy.array(point) - Src_origin), [1.0]).astype(numpy.float32)
+ X = numpy.append(numpy.array(numpy.array([x, y]) - Src_origin), [1.0]).astype(numpy.float32)
Y = numpy.dot(P, X)
La = (Y/Y[2])[:-1]
return tuple(numpy.around(La, 4))
- def outter_axis(self, point: tuple) -> tuple:
- """Transform the coordinates from the AOI's axis to the global axis.
- !!! warning
- Available for 2D AOI only.
+ def outter_axis(self, x: float, y: float) -> tuple:
+ """Transform a point coordinates from AOI axis to global axis.
!!! danger
- The AOI points must be sorted in clockwise order."""
-
- assert(self.dimension == 2)
+ The AOI points must be sorted in clockwise order.
+ !!! danger
+ The AOI must be a rectangle."""
- Src = numpy.array([[0., 0.], [1., 0.], [1., 1.], [0., 1.]]).astype(numpy.float32)
+ # Origin point
+ O = self[0]
- Dst = self.astype(numpy.float32)
- Dst_origin = Dst[0]
- Dst = (Dst - Dst_origin).reshape((len(Dst)), 2)
+ # Horizontal axis vector
+ H = self[1] - self[0]
- P = cv2.getPerspectiveTransform(Src, Dst)
- X = numpy.array([point[0], point[1], 1.0]).astype(numpy.float32)
- Y = numpy.dot(P, X)
+ # Vertical axis vector
+ V = self[3] - self[0]
- Lp = Dst_origin + (Y/Y[2])[:-1]
-
- return tuple(numpy.rint(Lp).astype(int))
+ return tuple(O + x * H + y * V)
def circle_intersection(self, center: tuple, radius: float) -> Tuple[numpy.array, float, float]:
"""Get intersection shape with a circle, intersection area / AOI area ratio and intersection area / circle area ratio.
@@ -353,6 +348,42 @@ class AOIScene():
return output
+ def __add__(self, add_vector) -> AOISceneType:
+ """Add vector to scene."""
+
+ assert(len(add_vector) == self.__dimension)
+
+ for name, area in self.__areas.items():
+
+ self.__areas[name] = self.__areas[name] + add_vector
+
+ return self
+
+ # Allow n + scene operation
+ __radd__ = __add__
+
+ def __sub__(self, sub_vector) -> AOISceneType:
+ """Sub vector to scene."""
+
+ assert(len(sub_vector) == self.__dimension)
+
+ for name, area in self.__areas.items():
+
+ self.__areas[name] = self.__areas[name] - sub_vector
+
+ return self
+
+ def __rsub__(self, rsub_vector) -> AOISceneType:
+ """RSub vector to scene."""
+
+ assert(len(rsub_vector) == self.__dimension)
+
+ for name, area in self.__areas.items():
+
+ self.__areas[name] = rsub_vector - self.__areas[name]
+
+ return self
+
def __mul__(self, scale_vector) -> AOISceneType:
"""Scale scene by a vector."""
@@ -367,6 +398,16 @@ class AOIScene():
# Allow n * scene operation
__rmul__ = __mul__
+ def __truediv__(self, div_vector) -> AOISceneType:
+
+ assert(len(div_vector) == self.__dimension)
+
+ for name, area in self.__areas.items():
+
+ self.__areas[name] = self.__areas[name] / div_vector
+
+ return self
+
def items(self) -> Tuple[str, AreaOfInterest]:
"""Iterate over areas."""