aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md7
-rw-r--r--src/argaze.test/ArFeatures.py67
-rw-r--r--src/argaze.test/ArScene.py59
-rw-r--r--src/argaze.test/OpenCVCuda.py10
-rw-r--r--src/argaze.test/utils/environment.json60
-rw-r--r--src/argaze.test/utils/scene.json56
-rw-r--r--src/argaze/ArFeatures.py32
7 files changed, 152 insertions, 139 deletions
diff --git a/README.md b/README.md
index 4b0be1b..d4972c5 100644
--- a/README.md
+++ b/README.md
@@ -2,17 +2,18 @@ An open-source python toolkit to deal with dynamic Areas Of Interest (AOI) and g
# Architecture
-The ArGaze toolkit provides some generics data structures and algorithms to build AR environement with dynamic AOI and so allow gaze tracking with mobil eye detecter devices. It is divided in submodules dedicated to various specifics features:
+The ArGaze toolkit provides some generics data structures and algorithms to build AR environement with dynamic AOI and so allow gaze tracking with mobil eye tracker devices. It is divided in submodules dedicated to various specifics features:
-* `argaze.ArUcoMarkers`: ArUco markers generator, traking, camera calibration, ...
+* `argaze.ArUcoMarkers`: ArUco markers generator, detector, camera calibration, ...
* `argaze.AreaOfInterest`: Area Of Interest (AOI) scene management for 2D and 3D environment.
* `argaze.GazeFeatures`: Generic gaze data structures definitions.
+* `argaze.GazeAnalysis`: Class interface to work with various gaze analysis algorithms.
* `argaze.TobiiGlassesPro2`: A gaze tracking device interface.
* `argaze.utils`: Collection of command-line high level features scripts based on ArGaze toolkit.
# Installation
-Consider that all inline commands below needs to be executed into ArGaze root folder.
+Consider that all inline commands below have to be executed into ArGaze root folder.
- Install build tool package:
diff --git a/src/argaze.test/ArFeatures.py b/src/argaze.test/ArFeatures.py
new file mode 100644
index 0000000..8e7ff49
--- /dev/null
+++ b/src/argaze.test/ArFeatures.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+
+import unittest
+import os
+
+from argaze import ArFeatures
+
+import numpy
+
+class TestArEnvironmentClass(unittest.TestCase):
+ """Test ArEnvironment class."""
+
+ def test_from_json(self):
+ """Test ArEnvironment creation from json file."""
+
+ # Edit test environment file path
+ current_directory = os.path.dirname(os.path.abspath(__file__))
+ json_filepath = os.path.join(current_directory, 'utils/environment.json')
+
+ # Load test environment
+ ar_environment = ArFeatures.ArEnvironment.from_json(json_filepath)
+
+ # Check environment meta data
+ self.assertEqual(ar_environment.name, "TestEnvironment")
+
+ # Check ArUco detector
+ self.assertEqual(ar_environment.aruco_detector.dictionary.name, "DICT_ARUCO_ORIGINAL")
+ self.assertEqual(ar_environment.aruco_detector.marker_size, 3.0)
+ self.assertEqual(ar_environment.aruco_detector.parameters.cornerRefinementMethod, 3)
+ self.assertEqual(ar_environment.aruco_detector.parameters.aprilTagQuadSigma, 2)
+ self.assertEqual(ar_environment.aruco_detector.parameters.aprilTagDeglitch, 1)
+
+ # Check ArUco detector camera
+ self.assertEqual(ar_environment.aruco_detector.camera.rms, 1.0)
+ self.assertIsNone(numpy.testing.assert_array_equal(ar_environment.aruco_detector.camera.dimensions, [1920, 1080]))
+ self.assertIsNone(numpy.testing.assert_array_equal(ar_environment.aruco_detector.camera.K, [[1.0, 0.0, 1.0], [0.0, 1.0, 1.0], [0.0, 0.0, 1.0]]))
+ self.assertIsNone(numpy.testing.assert_array_equal(ar_environment.aruco_detector.camera.D, [-1.0, -0.5, 0.0, 0.5, 1.0]))
+
+ # Check environment scenes
+ self.assertEqual(len(ar_environment.scenes), 1)
+ self.assertIsNone(numpy.testing.assert_array_equal(list(ar_environment.scenes.keys()), ["TestScene"]))
+
+ # Load test scene
+ ar_scene = ar_environment.scenes["TestScene"]
+
+ # Check Aruco scene
+ self.assertEqual(len(ar_scene.aruco_scene.places), 2)
+ self.assertIsNone(numpy.testing.assert_array_equal(ar_scene.aruco_scene.places['A'].translation, [1, 0, 0]))
+ self.assertIsNone(numpy.testing.assert_array_equal(ar_scene.aruco_scene.places['A'].rotation, [[1.,0.,0.],[0.,1.,0.],[0.,0.,1.]]))
+ self.assertEqual(ar_scene.aruco_scene.places['A'].marker.identifier, 0)
+
+ self.assertIsNone(numpy.testing.assert_array_equal(ar_scene.aruco_scene.places['B'].translation, [0, 1, 0]))
+ self.assertIsNone(numpy.testing.assert_array_almost_equal(ar_scene.aruco_scene.places['B'].rotation, [[0.,0.,1.],[0., 1.,0.],[-1.,0.,0.]]))
+ self.assertEqual(ar_scene.aruco_scene.places['B'].marker.identifier, 1)
+
+ # Check AOI scene
+ self.assertEqual(len(ar_scene.aoi_scene.items()), 1)
+ self.assertEqual(ar_scene.aoi_scene['Test'].size, 4)
+
+ # Check ArScene
+ self.assertEqual(ar_scene.angle_tolerance, 1.0)
+ self.assertEqual(ar_scene.distance_tolerance, 2.0)
+
+
+if __name__ == '__main__':
+
+ unittest.main() \ No newline at end of file
diff --git a/src/argaze.test/ArScene.py b/src/argaze.test/ArScene.py
deleted file mode 100644
index 5180c12..0000000
--- a/src/argaze.test/ArScene.py
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env python
-
-import unittest
-import os
-
-from argaze import ArScene
-
-import numpy
-
-class TestArSceneClass(unittest.TestCase):
- """Test ArScene class."""
-
- def test_from_json(self):
- """Test ArScene creation from json file."""
-
- # Edit scene file path
- current_directory = os.path.dirname(os.path.abspath(__file__))
- json_filepath = os.path.join(current_directory, 'utils/scene.json')
-
- # Load scene
- ar_scene = ArScene.ArScene.from_json(json_filepath)
-
- # Check scene meta data
- self.assertEqual(ar_scene.name, "TestScene")
- self.assertEqual(ar_scene.aruco_dictionary.name, "DICT_ARUCO_ORIGINAL")
- self.assertEqual(ar_scene.aruco_marker_size, 3.0)
-
- # Check ArUco camera
- self.assertEqual(ar_scene.aruco_camera.rms, 1.0)
- self.assertIsNone(numpy.testing.assert_array_equal(ar_scene.aruco_camera.dimensions, [1920, 1080]))
- self.assertIsNone(numpy.testing.assert_array_equal(ar_scene.aruco_camera.K, [[1.0, 0.0, 1.0], [0.0, 1.0, 1.0], [0.0, 0.0, 1.0]]))
- self.assertIsNone(numpy.testing.assert_array_equal(ar_scene.aruco_camera.D, [-1.0, -0.5, 0.0, 0.5, 1.0]))
-
- # Check ArUco detecter
- self.assertEqual(ar_scene.aruco_detector.detection_parameters.cornerRefinementMethod, 3)
- self.assertEqual(ar_scene.aruco_detector.detection_parameters.aprilTagQuadSigma, 2)
- self.assertEqual(ar_scene.aruco_detector.detection_parameters.aprilTagDeglitch, 1)
-
- # Check ArUco scene
- self.assertEqual(ar_scene.angle_tolerance, 1.0)
- self.assertEqual(ar_scene.distance_tolerance, 2.0)
- self.assertEqual(len(ar_scene.aruco_scene.places), 2)
-
- # Check ArUco scene places
- self.assertIsNone(numpy.testing.assert_array_equal(ar_scene.aruco_scene.places['A'].translation, [1, 0, 0]))
- self.assertIsNone(numpy.testing.assert_array_equal(ar_scene.aruco_scene.places['A'].rotation, [[1.,0.,0.],[0.,1.,0.],[0.,0.,1.]]))
- self.assertEqual(ar_scene.aruco_scene.places['A'].marker.identifier, 0)
-
- self.assertIsNone(numpy.testing.assert_array_equal(ar_scene.aruco_scene.places['B'].translation, [0, 1, 0]))
- self.assertIsNone(numpy.testing.assert_array_almost_equal(ar_scene.aruco_scene.places['B'].rotation, [[0.,0.,1.],[0., 1.,0.],[-1.,0.,0.]]))
- self.assertEqual(ar_scene.aruco_scene.places['B'].marker.identifier, 1)
-
- # Check AOI scene
- self.assertEqual(len(ar_scene.aoi_scene.items()), 1)
- self.assertEqual(ar_scene.aoi_scene['Test'].size, 4)
-
-if __name__ == '__main__':
-
- unittest.main() \ No newline at end of file
diff --git a/src/argaze.test/OpenCVCuda.py b/src/argaze.test/OpenCVCuda.py
index fd28abf..3b5b657 100644
--- a/src/argaze.test/OpenCVCuda.py
+++ b/src/argaze.test/OpenCVCuda.py
@@ -9,10 +9,7 @@ import os
class cuda_test(unittest.TestCase):
"""Test Cuda-accelerated OpenCV functions class."""
- def test_setup(self):
-
- self.assertGreater(cv.cuda.getCudaEnabledDeviceCount(), 0)
-
+ @unittest.skipIf(cv.cuda.getCudaEnabledDeviceCount() == 0, "No cuda device found")
def test_cuda_upload_download(self):
npMat = (np.random.random((128, 128, 3)) * 255).astype(np.uint8)
@@ -21,6 +18,7 @@ class cuda_test(unittest.TestCase):
self.assertTrue(np.allclose(cuMat.download(), npMat))
+ @unittest.skipIf(cv.cuda.getCudaEnabledDeviceCount() == 0, "No cuda device found")
def test_cuda_upload_download_stream(self):
stream = cv.cuda_Stream()
@@ -32,6 +30,7 @@ class cuda_test(unittest.TestCase):
self.assertTrue(np.allclose(npMat2, npMat))
+ @unittest.skipIf(cv.cuda.getCudaEnabledDeviceCount() == 0, "No cuda device found")
def test_cuda_interop(self):
npMat = (np.random.random((128, 128, 3)) * 255).astype(np.uint8)
@@ -46,6 +45,7 @@ class cuda_test(unittest.TestCase):
asyncstream = cv.cuda_Stream(1) # cudaStreamNonBlocking
self.assertTrue(asyncstream.cudaPtr() != 0)
+ @unittest.skipIf(cv.cuda.getCudaEnabledDeviceCount() == 0, "No cuda device found")
def test_cuda_buffer_pool(self):
cv.cuda.setBufferPoolUsage(True)
@@ -58,6 +58,7 @@ class cuda_test(unittest.TestCase):
self.assertEqual(cuMat.size(), (1024, 1024))
self.assertEqual(cuMat.type(), cv.CV_8UC3)
+ @unittest.skipIf(cv.cuda.getCudaEnabledDeviceCount() == 0, "No cuda device found")
def test_cuda_release(self):
npMat = (np.random.random((128, 128, 3)) * 255).astype(np.uint8)
@@ -69,6 +70,7 @@ class cuda_test(unittest.TestCase):
self.assertTrue(cuMat.step == 0)
self.assertTrue(cuMat.size() == (0, 0))
+ @unittest.skipIf(cv.cuda.getCudaEnabledDeviceCount() == 0, "No cuda device found")
def test_cuda_denoising(self):
self.assertEqual(True, hasattr(cv.cuda, 'fastNlMeansDenoising'))
diff --git a/src/argaze.test/utils/environment.json b/src/argaze.test/utils/environment.json
new file mode 100644
index 0000000..d5f8639
--- /dev/null
+++ b/src/argaze.test/utils/environment.json
@@ -0,0 +1,60 @@
+{
+ "name": "TestEnvironment",
+ "aruco_detector": {
+ "dictionary": "DICT_ARUCO_ORIGINAL",
+ "marker_size": 3.0,
+ "camera": {
+ "rms": 1.0,
+ "dimensions": [
+ 1920,
+ 1080
+ ],
+ "K": [
+ [
+ 1.0,
+ 0.0,
+ 1.0
+ ],
+ [
+ 0.0,
+ 1.0,
+ 1.0
+ ],
+ [
+ 0.0,
+ 0.0,
+ 1.0
+ ]
+ ],
+ "D": [
+ -1.0,
+ -0.5,
+ 0.0,
+ 0.5,
+ 1.0
+ ]
+ },
+ "parameters": {
+ "cornerRefinementMethod": 3,
+ "aprilTagQuadSigma": 2,
+ "aprilTagDeglitch": 1
+ }
+ },
+ "TestScene" : {
+ "aruco_scene": {
+ "A": {
+ "translation": [1, 0, 0],
+ "rotation": [0, 0, 0],
+ "marker": 0
+ },
+ "B": {
+ "translation": [0, 1, 0],
+ "rotation": [0, 90, 0],
+ "marker": 1
+ }
+ },
+ "aoi_scene": "aoi.obj",
+ "angle_tolerance": 1.0,
+ "distance_tolerance": 2.0
+ }
+} \ No newline at end of file
diff --git a/src/argaze.test/utils/scene.json b/src/argaze.test/utils/scene.json
deleted file mode 100644
index 25aacc8..0000000
--- a/src/argaze.test/utils/scene.json
+++ /dev/null
@@ -1,56 +0,0 @@
-{
- "name": "TestScene",
- "aruco_dictionary": "DICT_ARUCO_ORIGINAL",
- "aruco_marker_size": 3.0,
- "aruco_camera": {
- "rms": 1.0,
- "dimensions": [
- 1920,
- 1080
- ],
- "K": [
- [
- 1.0,
- 0.0,
- 1.0
- ],
- [
- 0.0,
- 1.0,
- 1.0
- ],
- [
- 0.0,
- 0.0,
- 1.0
- ]
- ],
- "D": [
- -1.0,
- -0.5,
- 0.0,
- 0.5,
- 1.0
- ]
- },
- "aruco_detector": {
- "cornerRefinementMethod": 3,
- "aprilTagQuadSigma": 2,
- "aprilTagDeglitch": 1
- },
- "aruco_scene": {
- "A": {
- "translation": [1, 0, 0],
- "rotation": [0, 0, 0],
- "marker": 0
- },
- "B": {
- "translation": [0, 1, 0],
- "rotation": [0, 90, 0],
- "marker": 1
- }
- },
- "aoi_scene": "aoi.obj",
- "angle_tolerance": 1.0,
- "distance_tolerance": 2.0
-} \ No newline at end of file
diff --git a/src/argaze/ArFeatures.py b/src/argaze/ArFeatures.py
index 25fd10d..e66b1ac 100644
--- a/src/argaze/ArFeatures.py
+++ b/src/argaze/ArFeatures.py
@@ -24,10 +24,10 @@ class ArEnvironment():
"""Define an Augmented Reality environment based ArUco marker detection."""
name: str
- """Environement name."""
+ """Environement name"""
aruco_detector: ArUcoDetector.ArUcoDetector = field(init=False, default_factory=ArUcoDetector.ArUcoDetector)
- """ArUco detecor."""
+ """ArUco detector"""
def __init__(self, **kwargs):
@@ -40,17 +40,14 @@ class ArEnvironment():
self.__scenes[name] = ArScene(self, **scene_kwargs)
- def __getitem__(self, name) -> ArSceneType:
- """Get an ArScene of the environment."""
-
- return self.__scenes[name]
-
@classmethod
def from_json(self, json_filepath: str) -> ArSceneType:
"""Load ArEnvironment from .json file."""
with open(json_filepath) as configuration_file:
+ self.__working_directory = os.path.dirname(json_filepath)
+
return ArEnvironment(**json.load(configuration_file))
def __str__(self) -> str:
@@ -63,15 +60,16 @@ class ArEnvironment():
return output
- def items(self) -> Tuple[str, ArSceneType]:
- """Iterate over scenes."""
-
- return self.__scenes.items()
-
- def keys(self) -> list[str]:
- """Get scenes name."""
+ @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.keys()
+ return self.__scenes
class PoseEstimationFailed(Exception):
"""Exception raised by ArScene project method when the pose can't be estimated due to unconsistencies."""
@@ -121,7 +119,7 @@ class ArScene():
# str: relative path to .obj file
if type(aruco_scene_value) == str:
- aruco_scene_value = os.path.join(os.getcwd(), aruco_scene_value)
+ aruco_scene_value = os.path.join(self.__ar_environment.working_directory, aruco_scene_value)
self.aruco_scene = ArUcoScene.ArUcoScene(self.__ar_environment.aruco_detector.dictionary, self.__ar_environment.aruco_detector.marker_size, aruco_scene_value)
@@ -131,7 +129,7 @@ class ArScene():
# str: relative path to .obj file
if type(aoi_scene_value) == str:
- obj_filepath = os.path.join(os.getcwd(), aoi_scene_value)
+ 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