From ecc0999ab94d0d80b663fee76ca04ac56fee7ea1 Mon Sep 17 00:00:00 2001 From: mprib Date: Tue, 5 Dec 2023 18:55:36 -0600 Subject: [PATCH 1/4] Improve functionality of intrinisc calibration widget during playback..functioning well. --- .../gui/camera_management/playback_widget.py | 23 ++++----- .../frame_emitters/playback_frame_emitter.py | 51 ++++++++++--------- pyxy3d/gui/workspace_widget.py | 1 - pyxy3d/intrinsic_stream_manager.py | 2 +- 4 files changed, 37 insertions(+), 40 deletions(-) diff --git a/pyxy3d/gui/camera_management/playback_widget.py b/pyxy3d/gui/camera_management/playback_widget.py index 5b59505cb..936c1cb4c 100644 --- a/pyxy3d/gui/camera_management/playback_widget.py +++ b/pyxy3d/gui/camera_management/playback_widget.py @@ -85,8 +85,10 @@ def __init__(self, controller: Controller, port: int, parent=None): self.frame_image = QLabel(self) self.frame_index_label = QLabel(self) self.play_button = QPushButton("", self) - play_icon = self.style().standardIcon(QStyle.SP_MediaPlay) - self.play_button.setIcon(play_icon) + self.play_icon = self.style().standardIcon(QStyle.SP_MediaPlay) + self.pause_icon = self.style().standardIcon(QStyle.SP_MediaPause) + + self.play_button.setIcon(self.play_icon) self.slider = CustomSlider() self.slider.setMaximum(self.total_frames - 1) @@ -177,13 +179,11 @@ def play_video(self): if self.is_playing: self.is_playing = False self.controller.pause_intrinsic_stream(self.port) - play_icon = self.style().standardIcon(QStyle.SP_MediaPlay) - self.play_button.setIcon(play_icon) + self.play_button.setIcon(self.play_icon) else: self.is_playing = True self.controller.unpause_intrinsic_stream(self.port) - pause_icon = self.style().standardIcon(QStyle.SP_MediaPause) - self.play_button.setIcon(pause_icon) + self.play_button.setIcon(self.pause_icon) def slider_moved(self, position): self.controller.stream_jump_to(self.port, position) @@ -191,7 +191,7 @@ def slider_moved(self, position): self.controller.pause_intrinsic_stream(self.port) self.is_playing = False self.play_button.setEnabled(False) - self.play_button.setText("Play") # now paused so only option is play + self.play_button.setIcon(self.play_icon) else: if not self.play_button.isEnabled(): self.play_button.setEnabled(True) @@ -213,9 +213,8 @@ def update_index(self, port, position): self.controller.pause_intrinsic_stream(self.port) self.is_playing = False self.play_button.setEnabled(False) - self.play_button.setText( - "Play" - ) # now paused so only option is play + # now paused so only option is play + self.play_button.setIcon(self.play_icon) def update_image(self, port, pixmap): logger.info(f"Running `update_image` in playback widget for port {self.port}") @@ -236,10 +235,8 @@ def on_scale_change(self, value): self.controller.stream_jump_to(self.port, self.index) def calibrate(self): + self.controller.calibrate_camera(self.port) - self.toggle_distortion_changed(2) - self.toggle_distortion.setChecked(True) - # self.controller.stream_jump_to(self.port, self.index) def clear_calibration_data(self): self.controller.clear_calibration_data(self.port) diff --git a/pyxy3d/gui/frame_emitters/playback_frame_emitter.py b/pyxy3d/gui/frame_emitters/playback_frame_emitter.py index 58fde9661..9703700a7 100644 --- a/pyxy3d/gui/frame_emitters/playback_frame_emitter.py +++ b/pyxy3d/gui/frame_emitters/playback_frame_emitter.py @@ -56,36 +56,37 @@ def run(self): if not self.keep_collecting.is_set(): break - self.frame = frame_packet.frame_with_points + if frame_packet.frame is not None: # stream end signal when None frame placed on out queue + self.frame = frame_packet.frame_with_points - logger.info(f"Frame size is {self.frame.shape}") - logger.info( - f"Grid Capture History size is {self.grid_capture_history.shape}" - ) - self.frame = cv2.addWeighted(self.frame, 1, self.grid_capture_history, 1, 0) + logger.info(f"Frame size is {self.frame.shape}") + logger.info( + f"Grid Capture History size is {self.grid_capture_history.shape}" + ) + self.frame = cv2.addWeighted(self.frame, 1, self.grid_capture_history, 1, 0) - self._apply_undistortion() + self._apply_undistortion() - # cv2.imshow("emitted frame", self.frame) - # key = cv2.waitKey(1) - # if key == ord('q'): - # break + # cv2.imshow("emitted frame", self.frame) + # key = cv2.waitKey(1) + # if key == ord('q'): + # break - logger.info(f"Frame size is {self.frame.shape} following undistortion") - self.frame = resize_to_square(self.frame) - self.frame = apply_rotation(self.frame, self.stream.rotation_count) - image = cv2_to_qlabel(self.frame) - pixmap = QPixmap.fromImage(image) - - if self.pixmap_edge_length: - pixmap = pixmap.scaled( - int(self.pixmap_edge_length), - int(self.pixmap_edge_length), - Qt.AspectRatioMode.KeepAspectRatio, - ) - self.ImageBroadcast.emit(self.port, pixmap) - self.FrameIndexBroadcast.emit(self.port, frame_packet.frame_index) + logger.info(f"Frame size is {self.frame.shape} following undistortion") + self.frame = resize_to_square(self.frame) + self.frame = apply_rotation(self.frame, self.stream.rotation_count) + image = cv2_to_qlabel(self.frame) + pixmap = QPixmap.fromImage(image) + + if self.pixmap_edge_length: + pixmap = pixmap.scaled( + int(self.pixmap_edge_length), + int(self.pixmap_edge_length), + Qt.AspectRatioMode.KeepAspectRatio, + ) + self.ImageBroadcast.emit(self.port, pixmap) + self.FrameIndexBroadcast.emit(self.port, frame_packet.frame_index) logger.info( f"Thread loop within frame emitter at port {self.stream.port} successfully ended" diff --git a/pyxy3d/gui/workspace_widget.py b/pyxy3d/gui/workspace_widget.py index 8ab75d230..901aeff9d 100644 --- a/pyxy3d/gui/workspace_widget.py +++ b/pyxy3d/gui/workspace_widget.py @@ -53,7 +53,6 @@ def connect_widgets(self): def on_calibrate_btn_clicked(self): logger.info("Calling controller to process extrinsic streams into 2D data") - self.controller.process_extrinsic_streams(fps_target=100) # Call the extrinsic calibration method in the controller self.controller.estimate_extrinsics() diff --git a/pyxy3d/intrinsic_stream_manager.py b/pyxy3d/intrinsic_stream_manager.py index 64cd88174..375a8524a 100644 --- a/pyxy3d/intrinsic_stream_manager.py +++ b/pyxy3d/intrinsic_stream_manager.py @@ -39,7 +39,7 @@ def load_stream_tools(self): port=camera.port, rotation_count=camera.rotation_count, tracker=self.tracker, - break_on_last=True, + break_on_last=False, ) self.streams[camera.port] = stream From 2c8128a4281b1527f2b1fdb8ee9af5de4e5b7e85 Mon Sep 17 00:00:00 2001 From: mprib Date: Tue, 5 Dec 2023 19:04:16 -0600 Subject: [PATCH 2/4] calibration runs though results look weird... --- pyxy3d/controller.py | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/pyxy3d/controller.py b/pyxy3d/controller.py index 37851d93f..0276ca617 100644 --- a/pyxy3d/controller.py +++ b/pyxy3d/controller.py @@ -129,20 +129,23 @@ def load_extrinsic_stream_manager(self): def process_extrinsic_streams(self, fps_target=None): def worker(): + output_path = Path(self.workspace_guide.extrinsic_dir, "CHARUCO", "xy_CHARUCO.csv") + output_path.unlink() # make sure this doesn't exist to begin with. + self.load_extrinsic_stream_manager() self.extrinsic_stream_manager.process_streams(fps_target=fps_target) - output_path = Path(self.extrinsic_dir, "CHARUCO", "xy_CHARUCO.csv") + logger.info(f"Processing of extrinsic calibration begun...waiting for output to populate: {output_path}") while not output_path.exists(): sleep(0.5) logger.info( f"Waiting for 2D tracked points to populate at {output_path}" ) - self.extrinsic_process_thread = QThread() - self.extrinsic_process_thread.run = worker - self.extrinsic_process_thread.finished.connect(self.extrinsic_2D_complete.emit) - self.extrinsic_process_thread.start() + # self.extrinsic_process_thread = QThread() + # self.extrinsic_process_thread.run = worker + # self.extrinsic_process_thread.finished.connect(self.extrinsic_2D_complete.emit) + # self.extrinsic_process_thread.start() def load_intrinsic_stream_manager(self): @@ -222,6 +225,7 @@ def scale_intrinsic_stream(self, port, new_scale): def calibrate_camera(self, port): def worker(): + # self.intrinsic_stream_manager.pause_stream(port) logger.info(f"Calibrating camera at port {port}") self.intrinsic_stream_manager.calibrate_camera(port) self.push_camera_data(port) @@ -288,6 +292,23 @@ def estimate_extrinsics(self): """ def worker(): + output_path = Path(self.workspace_guide.extrinsic_dir, "CHARUCO", "xy_CHARUCO.csv") + if output_path.exists(): + output_path.unlink() # make sure this doesn't exist to begin with. + + self.load_extrinsic_stream_manager() + self.extrinsic_stream_manager.process_streams(fps_target=100) + + logger.info(f"Processing of extrinsic calibration begun...waiting for output to populate: {output_path}") + + while not output_path.exists(): + sleep(0.5) + logger.info( f"Waiting for 2D tracked points to populate at {output_path}") + + # note that this processing will wait until it is complete + self.process_extrinsic_streams(fps_target=100) + logger.info("Processing if extrinsic caliberation streams complete...") + self.extrinsic_calibration_xy = Path( self.workspace, "calibration", "extrinsic", "CHARUCO", "xy_CHARUCO.csv" ) From dbeb16759a91f511767906fb14a3fad3213474e8 Mon Sep 17 00:00:00 2001 From: mprib Date: Wed, 6 Dec 2023 12:13:53 -0600 Subject: [PATCH 3/4] fix controller test now that extrinsic calibration has been revised --- tests/test_controller.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_controller.py b/tests/test_controller.py index cceb6ffc1..ba5dafe1a 100644 --- a/tests/test_controller.py +++ b/tests/test_controller.py @@ -60,16 +60,14 @@ def test_extrinsic_calibration(): # calibration requires a capture volume object which is composed of both a camera array, # and a set of point estimates controller.load_camera_array() - controller.load_extrinsic_stream_manager() # want to make sure that no previously stored data is leaking into this test - for cam in controller.camera_array.cameras.values(): cam.rotation = None cam.translation = None assert(not controller.camera_array.all_extrinsics_calibrated()) - controller.process_extrinsic_streams(fps_target=100) + controller.estimate_extrinsics() xy_path = Path(workspace,"calibration", "extrinsic", "CHARUCO", "xy_CHARUCO.csv") From 190897b896883cfd2b9f02896d7b516c124e4fc4 Mon Sep 17 00:00:00 2001 From: mprib Date: Wed, 6 Dec 2023 12:20:29 -0600 Subject: [PATCH 4/4] Tweak test to work wtih new controller process for estimating extrinsics --- tests/test_controller.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/test_controller.py b/tests/test_controller.py index ba5dafe1a..20e6d7fe5 100644 --- a/tests/test_controller.py +++ b/tests/test_controller.py @@ -67,14 +67,11 @@ def test_extrinsic_calibration(): cam.translation = None assert(not controller.camera_array.all_extrinsics_calibrated()) - controller.estimate_extrinsics() - - xy_path = Path(workspace,"calibration", "extrinsic", "CHARUCO", "xy_CHARUCO.csv") - - while not xy_path.exists(): - sleep(1) - logger.info(f"Waiting on data to populate in {xy_path}") + # xy_path = Path(workspace,"calibration", "extrinsic", "CHARUCO", "xy_CHARUCO.csv") + # while not xy_path.exists(): + # sleep(1) + # logger.info(f"Waiting on data to populate in {xy_path}") # with the charuco points tracked and saved out, the calibration can now proceed controller.estimate_extrinsics()