aboutsummaryrefslogtreecommitdiff
path: root/src/argaze/ArFeatures.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/argaze/ArFeatures.py')
-rw-r--r--src/argaze/ArFeatures.py145
1 files changed, 68 insertions, 77 deletions
diff --git a/src/argaze/ArFeatures.py b/src/argaze/ArFeatures.py
index 4e1f5cb..3706aac 100644
--- a/src/argaze/ArFeatures.py
+++ b/src/argaze/ArFeatures.py
@@ -24,31 +24,72 @@ class ArEnvironment():
"""Define an Augmented Reality environment based ArUco marker detection."""
name: str
- """Environement name"""
+ """Environment name"""
- aruco_detector: ArUcoDetector.ArUcoDetector = field(init=False, default_factory=ArUcoDetector.ArUcoDetector)
- """ArUco detector"""
-
- def __init__(self, **kwargs):
-
- self.name = kwargs.pop('name')
+ working_directory: str
+ """Environment working directory"""
- self.aruco_detector = ArUcoDetector.ArUcoDetector(**kwargs.pop('aruco_detector'))
-
- self.__scenes = {}
- for name, scene_kwargs in kwargs.items():
+ aruco_detector: ArUcoDetector.ArUcoDetector = field(default_factory=ArUcoDetector.ArUcoDetector)
+ """ArUco detector"""
- self.__scenes[name] = ArScene(self, **scene_kwargs)
+ scenes: dict = field(default_factory=dict)
+ """All environment scenes"""
@classmethod
def from_json(self, json_filepath: str) -> ArSceneType:
"""Load ArEnvironment from .json file."""
+ new_name = ''
+ new_working_directory = '.'
+ new_aruco_detector = None
+ new_scenes = {}
+
with open(json_filepath) as configuration_file:
- self.__working_directory = os.path.dirname(json_filepath)
+ data = json.load(configuration_file)
+
+ new_name = data.pop('name')
+
+ new_working_directory = os.path.dirname(json_filepath)
+
+ new_aruco_detector = ArUcoDetector.ArUcoDetector(**data.pop('aruco_detector'))
+
+ for scene_name, scene_data in data.items():
+
+ new_aruco_scene = None
+ new_aoi_scene = None
+
+ # Check aruco_scene value type
+ aruco_scene_value = scene_data.pop('aruco_scene')
- return ArEnvironment(**json.load(configuration_file))
+ # str: relative path to .obj file
+ if type(aruco_scene_value) == str:
+
+ aruco_scene_value = os.path.join(new_working_directory, aruco_scene_value)
+ new_aruco_scene = ArUcoScene.ArUcoScene.from_obj(aruco_scene_value)
+
+ # dict:
+ else:
+
+ new_aruco_scene = ArUcoScene.ArUcoScene(new_aruco_detector.marker_size, new_aruco_detector.dictionary, aruco_scene_value)
+
+ # Check aoi_scene value type
+ aoi_scene_value = scene_data.pop('aoi_scene')
+
+ # str: relative path to .obj file
+ if type(aoi_scene_value) == str:
+
+ obj_filepath = os.path.join(new_working_directory, aoi_scene_value)
+ new_aoi_scene = AOI3DScene.AOI3DScene.from_obj(obj_filepath)
+
+ # dict:
+ else:
+
+ new_aoi_scene = AOI3DScene.AOI3DScene(aoi_scene_value)
+
+ new_scenes[scene_name] = ArScene(self, new_aruco_scene, new_aoi_scene, **scene_data)
+
+ return ArEnvironment(new_name, new_working_directory, new_aruco_detector, new_scenes)
def __str__(self) -> str:
"""String display"""
@@ -60,17 +101,6 @@ class ArEnvironment():
return output
- @property
- def working_directory(self):
- """Working directory path."""
- return self.__working_directory
-
- @property
- def scenes(self) -> Tuple[str, ArSceneType]:
- """Access to scenes dictionary."""
-
- return self.__scenes
-
class PoseEstimationFailed(Exception):
"""Exception raised by ArScene project method when the pose can't be estimated due to unconsistencies."""
@@ -91,72 +121,33 @@ class SceneProjectionFailed(Exception):
class ArScene():
"""Define an Augmented Reality scene with ArUco markers and AOI scenes."""
- aruco_scene: ArUcoScene.ArUcoScene = field(init=False, default_factory=ArUcoScene.ArUcoScene)
+ ar_environment: ArEnvironment = field(default_factory=ArEnvironment)
+ """AR Environment to which the scene belongs."""
+
+ aruco_scene: ArUcoScene.ArUcoScene = field(default_factory=ArUcoScene.ArUcoScene)
"""ArUco markers 3D scene description used to estimate scene pose from detected markers: see `estimate_pose` function below."""
- aoi_scene: AOI3DScene.AOI3DScene = field(init=False, default_factory=AOI3DScene.AOI3DScene)
+ aoi_scene: AOI3DScene.AOI3DScene = field(default_factory=AOI3DScene.AOI3DScene)
"""AOI 3D scene description that will be projected onto estimated scene once its pose will be estimated : see `project` function below."""
- aruco_axis: dict
+ aruco_axis: dict = field(default_factory=dict)
"""Optional dictionary to define orthogonal axis where each axis is defined by list of 3 markers identifier (first is origin). \
This pose estimation strategy is used by `estimate_pose` function when at least 3 markers are detected."""
- aruco_aoi: dict
+ aruco_aoi: dict = field(default_factory=dict)
"""Optional dictionary of AOI defined by list of markers identifier and markers corners index tuples: see `build_aruco_aoi_scene` function below."""
- angle_tolerance: float
+ angle_tolerance: float = field(default=0.)
"""Optional angle error tolerance to validate marker pose in degree used into `estimate_pose` function."""
- distance_tolerance: float
+ distance_tolerance: float = field(default=0.)
"""Optional distance error tolerance to validate marker pose in centimeter used into `estimate_pose` function."""
- def __init__(self, ar_environment: ArEnvironment, **kwargs):
-
- self.__ar_environment = ar_environment
-
- # Check aruco_scene value type
- aruco_scene_value = kwargs.pop('aruco_scene')
-
- # str: relative path to .obj file
- if type(aruco_scene_value) == str:
-
- aruco_scene_value = os.path.join(self.__ar_environment.working_directory, aruco_scene_value)
-
- self.aruco_scene = ArUcoScene.ArUcoScene(aruco_scene_value, self.__ar_environment.aruco_detector.dictionary, self.__ar_environment.aruco_detector.marker_size)
-
- # Check aoi_scene value type
- aoi_scene_value = kwargs.pop('aoi_scene')
-
- # str: relative path to .obj file
- if type(aoi_scene_value) == str:
-
- obj_filepath = os.path.join(self.__ar_environment.working_directory, aoi_scene_value)
- self.aoi_scene = AOI3DScene.AOI3DScene.from_obj(obj_filepath)
-
- # dict: all AOI
- else:
- self.aoi_scene = AOI3DScene.AOI3DScene(aoi_scene_value)
-
- # Init aruco axis
- self.aruco_axis = {}
-
- # Init aruco aoi
- self.aruco_aoi = {}
-
- # Update all attributes from arguments
- self.__dict__.update(kwargs)
+ def __post_init__(self):
# Preprocess orthogonal projection to speed up further aruco aoi processings
self.__orthogonal_projection_cache = self.orthogonal_projection
- @classmethod
- def from_json(self, json_filepath: str) -> ArSceneType:
- """Load ArScene from .json file."""
-
- with open(json_filepath) as configuration_file:
-
- return ArScene(**json.load(configuration_file))
-
def __str__(self) -> str:
"""String display"""
@@ -270,7 +261,7 @@ class ArScene():
aoi_scene_copy = self.aoi_scene.copy()
- aoi_scene_projection = aoi_scene_copy.project(tvec, rvec, self.__ar_environment.aruco_detector.camera.K)
+ aoi_scene_projection = aoi_scene_copy.project(tvec, rvec, self.ar_environment.aruco_detector.camera.K)
# Warn user when the projected scene is empty
if len(aoi_scene_projection) == 0:
@@ -320,11 +311,11 @@ class ArScene():
def draw_axis(self, frame):
"""Draw scene axis into frame."""
- self.aruco_scene.draw_axis(frame, self.__ar_environment.aruco_detector.camera.K, self.__ar_environment.aruco_detector.camera.D)
+ self.aruco_scene.draw_axis(frame, self.ar_environment.aruco_detector.camera.K, self.ar_environment.aruco_detector.camera.D)
def draw_places(self, frame):
"""Draw scene places into frame."""
- self.aruco_scene.draw_places(frame, self.__ar_environment.aruco_detector.camera.K, self.__ar_environment.aruco_detector.camera.D)
+ self.aruco_scene.draw_places(frame, self.ar_environment.aruco_detector.camera.K, self.ar_environment.aruco_detector.camera.D)