From e9d820a40f135f3e520669115d512285735016a2 Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Wed, 17 Jul 2024 21:34:09 +0200 Subject: Adding new OpenCV.Camera context for demonstration purpose. --- docs/user_guide/utils/demonstrations_scripts.md | 10 +++ src/argaze/utils/contexts/OpenCV.py | 96 ++++++++++++++++++++++++- 2 files changed, 103 insertions(+), 3 deletions(-) diff --git a/docs/user_guide/utils/demonstrations_scripts.md b/docs/user_guide/utils/demonstrations_scripts.md index 68d3dff..22a6245 100644 --- a/docs/user_guide/utils/demonstrations_scripts.md +++ b/docs/user_guide/utils/demonstrations_scripts.md @@ -36,6 +36,16 @@ Load **opencv_movie_context.json** file to playback movie pictures and also capt python -m argaze load ./src/argaze/utils/demo/opencv_movie_context.json ``` +## OpenCV camera context + +Edit **aruco_markers_pipeline.json** file as to adapt the *size* to the camera resolution and to reduce the value of the *sides_mask*. + +Then, load **opencv_camera_context.json** file to capture camera pictures and also capture cursor pointer positions over OpenCV window: + +```shell +python -m argaze load ./src/argaze/utils/demo/opencv_camera_context.json +``` + ## Tobii Pro Glasses 2 ### Live stream context diff --git a/src/argaze/utils/contexts/OpenCV.py b/src/argaze/utils/contexts/OpenCV.py index ff3ed82..6859a0c 100644 --- a/src/argaze/utils/contexts/OpenCV.py +++ b/src/argaze/utils/contexts/OpenCV.py @@ -157,8 +157,6 @@ class Movie(Cursor): if success: - video_height, video_width, _ = image.shape - # Refresh once self.__refresh = False @@ -225,4 +223,96 @@ class Movie(Cursor): else: - return 0. \ No newline at end of file + return 0. + +class Camera(Cursor): + """Capture camera images and capture cursor position over OpenCV window. + + !!! warning + It is assumed that an OpenCV window with the same name than the context is used to display context's pipeline image. + """ + @DataFeatures.PipelineStepInit + def __init__(self, **kwargs): + + # Init Cursor class + super().__init__() + + # Init private attributes + self.__camera_id = None + self.__camera = None + self.__video_fps = None + self.__video_width = None + self.__video_height = None + + @property + def identifier(self) -> int: + """Camera device id.""" + return self.__camera_id + + @identifier.setter + def identifier(self, camera_id: int): + + self.__camera_id = camera_id + + # Load movie + self.__camera = cv2.VideoCapture(self.__camera_id) + self.__video_fps = self.__camera.get(cv2.CAP_PROP_FPS) + self.__video_width = int(self.__camera.get(cv2.CAP_PROP_FRAME_WIDTH)) + self.__video_height = int(self.__camera.get(cv2.CAP_PROP_FRAME_HEIGHT)) + + @DataFeatures.PipelineStepEnter + def __enter__(self): + + logging.info('OpenCV.Movie context starts...') + + # Enter in Cursor context + super().__enter__() + + # Open reading thread + self.__reading_thread = threading.Thread(target=self.__read) + + logging.debug('> starting reading thread...') + self.__reading_thread.start() + + return self + + def __read(self): + """Iterate on camera images.""" + + while self.is_running(): + + # Check pause event (and stop event) + while self.is_paused() and self.is_running(): + + logging.debug('> reading is paused at %i', current_image_time) + + time.sleep(1) + + # Select a new image + success, image = self.__camera.read() + image_time = self.__camera.get(cv2.CAP_PROP_POS_MSEC) + + if success: + + # Timestamp image + image = DataFeatures.TimestampedImage(image, timestamp=image_time) + + # Process movie image + self._process_camera_image(timestamp=image_time, image=image) + + # Wait + time.sleep(1 / self.__video_fps) + + @DataFeatures.PipelineStepExit + def __exit__(self, exception_type, exception_value, exception_traceback): + + logging.info('OpenCV.Movie context stops...') + + # Exit from Cursor context + super().__exit__(exception_type, exception_value, exception_traceback) + + # Close data capture + self.stop() + + # Stop reading thread + threading.Thread.join(self.__reading_thread) -- cgit v1.1