diff options
author | Theo De La Hogue | 2023-09-22 22:06:20 +0200 |
---|---|---|
committer | Theo De La Hogue | 2023-09-22 22:06:20 +0200 |
commit | b947573f7dbccb5b2b13b64677192145f2dbb864 (patch) | |
tree | 20cd0cb471b245445bd493c3e8e24fa7baf45d8b /src/argaze/AreaOfInterest | |
parent | 1f36c34242791145a1b33dd17cf351018456310f (diff) | |
download | argaze-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.py | 31 | ||||
-rw-r--r-- | src/argaze/AreaOfInterest/AOI3DScene.py | 9 | ||||
-rw-r--r-- | src/argaze/AreaOfInterest/AOIFeatures.py | 81 |
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.""" |