From 70aa8cbf4753b3a725e3359a0c4e90f19a46c1c6 Mon Sep 17 00:00:00 2001 From: hannalee2 Date: Thu, 9 May 2024 10:50:17 -0700 Subject: [PATCH] Implemented the function that getting a positive x axis from user --- parallax/axis_filter.py | 117 ++++++++++++++++++++++++----- parallax/model.py | 15 +++- parallax/no_filter.py | 70 +++++++++++++---- parallax/probe_detect_manager.py | 36 +++++++-- parallax/reticle_detect_manager.py | 28 +++++-- parallax/screen_widget.py | 11 ++- parallax/stage_widget.py | 108 +++++++++++++++++++------- 7 files changed, 310 insertions(+), 75 deletions(-) diff --git a/parallax/axis_filter.py b/parallax/axis_filter.py index 1c5a5141..9ae04537 100644 --- a/parallax/axis_filter.py +++ b/parallax/axis_filter.py @@ -8,6 +8,7 @@ import time import cv2 +import numpy as np from PyQt5.QtCore import QObject, QThread, pyqtSignal # Set logger name @@ -26,13 +27,16 @@ class Worker(QObject): finished = pyqtSignal() frame_processed = pyqtSignal(object) - def __init__(self, name): + def __init__(self, name, model): """Initialize the worker object.""" QObject.__init__(self) + self.model = model self.name = name self.running = False self.new = False self.frame = None + self.reticle_coords = self.model.get_coords_axis(self.name) + self.pos_x = None def update_frame(self, frame): """Update the frame to be processed. @@ -43,14 +47,69 @@ def update_frame(self, frame): self.frame = frame self.new = True - def process(self, frame): - """Process nothing (no filter) and emit the frame_processed signal. - - Args: - frame: The frame to be processed. - """ - cv2.circle(frame, (2000,1500), 10, (0, 255, 0), -1) # Test - self.frame_processed.emit(frame) + def process(self): + """Process the frame and emit the frame_processed signal.""" + if self.reticle_coords is not None: + for reticle_coords in self.reticle_coords: + for pt in reticle_coords: + cv2.circle(self.frame, tuple(pt), 4, (155, 155, 50), -1) + first_pt = reticle_coords[0] + last_pt = reticle_coords[-1] + cv2.circle(self.frame, tuple(first_pt), 12, (255, 255, 0), -1) + cv2.circle(self.frame, tuple(last_pt), 12, (255, 255, 0), -1) + + pos_x = self.model.get_pos_x(self.name) + if pos_x is not None: + cv2.circle(self.frame, pos_x, 15, (255, 0, 0), -1) + + self.frame_processed.emit(self.frame) + + def squared_distance(self, p1, p2): + return (p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2 + + def sort_reticle_points(self): + if self.pos_x is None or self.reticle_coords is None: + return + + if self.pos_x == tuple(self.reticle_coords[0][0]): + self.reticle_coords[0] = self.reticle_coords[0][::-1] + self.reticle_coords[1] = self.reticle_coords[1][::-1] + elif self.pos_x == tuple(self.reticle_coords[1][-1]): + tmp = self.reticle_coords[1] + self.reticle_coords[1] = self.reticle_coords[0][::-1] + self.reticle_coords[0] = tmp + elif self.pos_x == tuple(self.reticle_coords[1][0]): + tmp = self.reticle_coords[1][::-1] + self.reticle_coords[1] = self.reticle_coords[0] + self.reticle_coords[0] = tmp + else: + pass + + self.pos_x = tuple(self.reticle_coords[0][-1]) + return + + def clicked_position(self, input_pt): + """Get clicked position.""" + if self.reticle_coords is None: + return + + # Coordinates of points + pt1, pt2 = self.reticle_coords[0][0], self.reticle_coords[0][-1] + pt3, pt4 = self.reticle_coords[1][0], self.reticle_coords[1][-1] + pts = [pt1, pt2, pt3, pt4] + + # Finding the closest point to pt + self.pos_x = min(pts, key=lambda pt: self.squared_distance(pt, input_pt)) + self.pos_x = tuple(self.pos_x) + + # sort the reticle points and register to the model + self.sort_reticle_points() + self.model.add_coords_axis(self.name, self.reticle_coords) + self.model.add_pos_x(self.name, self.pos_x) + + def reset_pos_x(self): + self.pos_x = None + self.model.reset_pos_x() def stop_running(self): """Stop the worker from running.""" @@ -64,7 +123,7 @@ def run(self): """Run the worker thread.""" while self.running: if self.new: - self.process(self.frame) + self.process() self.new = False time.sleep(0.001) self.finished.emit() @@ -73,22 +132,24 @@ def run(self): def set_name(self, name): """Set name as camera serial number.""" self.name = name + self.reticle_coords = self.model.get_coords_axis(self.name) + self.pos_x = self.model.get_pos_x(self.name) - def __init__(self, camera_name): + def __init__(self, model, camera_name): """Initialize the filter object.""" logger.debug("Init axis filter manager") super().__init__() + self.model = model self.worker = None self.name = camera_name self.thread = None - self.thread = None def init_thread(self): """Initialize or reinitialize the worker and thread""" if self.thread is not None: self.clean() # Clean up existing thread and worker before reinitializing self.thread = QThread() - self.worker = self.Worker(self.name) + self.worker = self.Worker(self.name, self.model) self.worker.moveToThread(self.thread) self.thread.started.connect(self.worker.run) @@ -100,6 +161,7 @@ def init_thread(self): self.worker.frame_processed.connect(self.frame_processed.emit) self.worker.finished.connect(self.thread.quit) self.worker.finished.connect(self.thread.deleteLater) + self.worker.destroyed.connect(self.onWorkerDestroyed) logger.debug(f"init camera name: {self.name}") def process(self, frame): @@ -113,33 +175,52 @@ def process(self, frame): def start(self): """Start the filter by reinitializing and starting the worker and thread.""" + logger.debug(f" {self.name} Starting thread") self.init_thread() # Reinitialize and start the worker and thread self.worker.start_running() self.thread.start() - logger.debug(f"thread started {self.name}") def stop(self): """Stop the filter by stopping the worker.""" + logger.debug(f" {self.name} Stopping thread") if self.worker is not None: self.worker.stop_running() + self.worker.reset_pos_x() + + def onWorkerDestroyed(self): + """Cleanup after worker finishes.""" + logger.debug(f"{self.name} worker destroyed") + + def onThreadDestroyed(self): + """Flag if thread is deleted""" + logger.debug(f"{self.name} thread destroyed") + self.threadDeleted = True + self.thread = None def set_name(self, camera_name): """Set camera name.""" self.name = camera_name if self.worker is not None: self.worker.set_name(self.name) - logger.debug(f"camera name: {self.name}") + logger.debug(f"{self.name} set camera name") + + def clicked_position(self, pt): + """Get clicked position.""" + if self.worker is not None: + self.worker.clicked_position(pt) def clean(self): """Safely clean up the reticle detection manager.""" - logger.debug("Cleaning the thread") + logger.debug(f"{self.name} Cleaning the thread") if self.worker is not None: self.worker.stop_running() # Signal the worker to stop + if not self.threadDeleted and self.thread.isRunning(): self.thread.quit() # Ask the thread to quit self.thread.wait() # Wait for the thread to finish self.thread = None # Clear the reference to the thread self.worker = None # Clear the reference to the worker + logger.debug(f"{self.name} Cleaned the thread") def onThreadDestroyed(self): """Flag if thread is deleted""" @@ -147,4 +228,6 @@ def onThreadDestroyed(self): def __del__(self): """Destructor for the filter object.""" - self.clean() \ No newline at end of file + self.clean() + + diff --git a/parallax/model.py b/parallax/model.py index 182d041e..debd2ba4 100755 --- a/parallax/model.py +++ b/parallax/model.py @@ -36,6 +36,7 @@ def __init__(self, version="V1"): # coords axis self.coords_axis = {} + self.pos_x = {} self.camera_intrinsic = {} self.camera_extrinsic = {} self.calibration = None @@ -136,7 +137,19 @@ def reset_coords_intrinsic_extrinsic(self): self.coords_axis = {} self.camera_intrinsic = {} self.camera_extrinsic = {} - + + def add_pos_x(self, camera_name, pt): + """Add position x.""" + self.pos_x[camera_name] = pt + + def get_pos_x(self, camera_name): + """Add position x.""" + return self.pos_x.get(camera_name) + + def reset_pos_x(self): + """Reset position x.""" + self.pos_x = {} + def add_coords_axis(self, camera_name, coords): """Add coordinates axis.""" self.coords_axis[camera_name] = coords diff --git a/parallax/no_filter.py b/parallax/no_filter.py index ac65db75..6252da6b 100644 --- a/parallax/no_filter.py +++ b/parallax/no_filter.py @@ -4,10 +4,15 @@ facilitating integration and optional processing steps. """ +import logging import time +import cv2 from PyQt5.QtCore import QObject, QThread, pyqtSignal +# Set logger name +logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) class NoFilter(QObject): """Class representing no filter.""" @@ -27,6 +32,7 @@ def __init__(self, name): self.name = name self.running = True self.new = False + self.frame = None def update_frame(self, frame): """Update the frame to be processed. @@ -62,27 +68,37 @@ def run(self): time.sleep(0.001) self.finished.emit() - def __init__(self): + def set_name(self, name): + """Set name as camera serial number.""" + self.name = name + + def __init__(self, camera_name): """Initialize the filter object.""" + logger.debug(f"{self.name} Init no filter manager") super().__init__() self.worker = None + self.name = camera_name self.thread = None - self.init_thread() + self.start() def init_thread(self): """Initialize or reinitialize the worker and thread""" + if self.thread is not None: + self.clean() # Clean up existing thread and worker before reinitializing self.thread = QThread() self.worker = self.Worker(self.name) self.worker.moveToThread(self.thread) self.thread.started.connect(self.worker.run) + self.thread.finished.connect(self.thread.deleteLater) + self.thread.destroyed.connect(self.onThreadDestroyed) + self.threadDeleted = False + self.worker.frame_processed.connect(self.frame_processed.emit) self.worker.finished.connect(self.thread.quit) - self.worker.finished.connect(lambda: self.thread_deleted) self.worker.finished.connect(self.worker.deleteLater) - self.thread.finished.connect(self.thread.deleteLater) - - self.thread.start() + self.worker.destroyed.connect(self.onWorkerDestroyed) # Debug msg + logger.debug(f"{self.name} init camera name") def process(self, frame): """Process the frame using the worker. @@ -95,25 +111,47 @@ def process(self, frame): def start(self): """Start the filter by reinitializing and starting the worker and thread.""" + logger.debug(f" {self.name} Starting thread") self.init_thread() # Reinitialize and start the worker and thread + self.thread.start() + self.worker.start_running() def stop(self): """Stop the filter by stopping the worker.""" + logger.debug(f" {self.name} Stopping thread") if self.worker is not None: self.worker.stop_running() + def onWorkerDestroyed(self): + """Cleanup after worker finishes.""" + logger.debug(f"{self.name} worker destroyed") + + def onThreadDestroyed(self): + """Flag if thread is deleted""" + logger.debug(f"{self.name} thread destroyed") + self.threadDeleted = True + self.thread = None + + def set_name(self, camera_name): + """Set camera name.""" + self.name = camera_name + if self.worker is not None: + self.worker.set_name(self.name) + logger.debug(f"{self.name} set camera name") + def clean(self): - """Clean up the filter by stopping the worker and waiting for the thread to finish.""" + """Safely clean up the reticle detection manager.""" + logger.debug(f"{self.name} Cleaning the thread") if self.worker is not None: - self.worker.stop_running() - if self.thread is not None: - self.thread.quit() - self.thread.wait() + self.worker.stop_running() # Signal the worker to stop + + if not self.threadDeleted and self.thread.isRunning(): + self.thread.quit() # Ask the thread to quit + self.thread.wait() # Wait for the thread to finish + self.thread = None # Clear the reference to the thread + self.worker = None # Clear the reference to the worker + logger.debug(f"{self.name} Cleaned the thread") def __del__(self): """Destructor for the filter object.""" - self.clean() - - def thread_deleted(self): - """Placeholder method for when the thread is deleted.""" - pass \ No newline at end of file + self.clean() \ No newline at end of file diff --git a/parallax/probe_detect_manager.py b/parallax/probe_detect_manager.py index 72243e51..1e666908 100644 --- a/parallax/probe_detect_manager.py +++ b/parallax/probe_detect_manager.py @@ -243,19 +243,26 @@ def __init__(self, model, camera_name): self.worker = None self.name = camera_name self.thread = None - self.init_thread() def init_thread(self): """Initialize the worker thread.""" + if self.thread is not None: + self.clean() # Clean up existing thread and worker before reinitializing self.thread = QThread() self.worker = self.Worker(self.name, self.model) self.worker.moveToThread(self.thread) + self.thread.started.connect(self.worker.run) + self.thread.finished.connect(self.thread.deleteLater) + self.thread.destroyed.connect(self.onThreadDestroyed) + self.threadDeleted = False + self.worker.frame_processed.connect(self.frame_processed) self.worker.found_coords.connect(self.found_coords_print) self.worker.finished.connect(self.thread.quit) self.worker.finished.connect(self.worker.deleteLater) - self.thread.finished.connect(self.thread.deleteLater) + self.worker.destroyed.connect(self.onWorkerDestroyed) + logger.debug(f"{self.name} init camera name") def process(self, frame, timestamp): """Process the frame using the worker. @@ -287,15 +294,27 @@ def found_coords_print(self, timestamp, sn, pixel_coords): def start(self): """Start the probe detection manager.""" + logger.debug(f" {self.name} Starting thread") self.init_thread() # Reinitialize and start the worker and thread self.worker.start_running() self.thread.start() def stop(self): """Stop the probe detection manager.""" + logger.debug(f" {self.name} Stopping thread") if self.worker is not None: self.worker.stop_running() + def onWorkerDestroyed(self): + """Cleanup after worker finishes.""" + logger.debug(f"{self.name} worker destroyed") + + def onThreadDestroyed(self): + """Flag if thread is deleted""" + logger.debug(f"{self.name} thread destroyed") + self.threadDeleted = True + self.thread = None + def start_detection(self, sn): # Call from stage listener. """Start the probe detection for a specific serial number. @@ -320,15 +339,20 @@ def set_name(self, camera_name): self.name = camera_name if self.worker is not None: self.worker.set_name(self.name) - logger.debug(f"camera name: {self.name}") + logger.debug(f"{self.name} set camera name") def clean(self): """Clean up the probe detection manager.""" + logger.debug(f"{self.name} Cleaning the thread") if self.worker is not None: self.worker.stop_running() - if self.thread is not None: - self.thread.quit() - self.thread.wait() + + if not self.threadDeleted and self.thread.isRunning(): + self.thread.quit() # Ask the thread to quit + self.thread.wait() # Wait for the thread to finish + self.thread = None # Clear the reference to the thread + self.worker = None # Clear the reference to the worker + logger.debug(f"{self.name} Cleaned the thread") def __del__(self): """Destructor for the probe detection manager.""" diff --git a/parallax/reticle_detect_manager.py b/parallax/reticle_detect_manager.py index 62eaa2b2..117d3e41 100644 --- a/parallax/reticle_detect_manager.py +++ b/parallax/reticle_detect_manager.py @@ -202,6 +202,7 @@ def process(self, frame): return frame else: logger.debug(f"{ self.name} reticle detection success \n") + self.stop_running() # If found, stop processing return self.frame_success def stop_running(self): @@ -229,7 +230,6 @@ def run(self): self.new = False time.sleep(0.001) self.finished.emit() - logger.debug(f"thread finished {self.name}") def set_name(self, name): """Set name as camera serial number.""" @@ -237,7 +237,7 @@ def set_name(self, name): def __init__(self, camera_name): """Initialize the reticle detection manager.""" - logger.debug("Init reticle detect manager") + logger.debug(f"{self.name} Init reticle detect manager") super().__init__() self.worker = None self.name = camera_name @@ -253,14 +253,15 @@ def init_thread(self): self.thread.started.connect(self.worker.run) self.thread.finished.connect(self.thread.deleteLater) - self.thread.destroyed.connect(self.onThreadDestroyed) + self.thread.destroyed.connect(self.onThreadDestroyed) # Debug msg self.threadDeleted = False self.worker.frame_processed.connect(self.frame_processed) self.worker.found_coords.connect(self.found_coords) self.worker.finished.connect(self.thread.quit) self.worker.finished.connect(self.worker.deleteLater) - logger.debug(f"init camera name: {self.name}") + self.worker.destroyed.connect(self.onWorkerDestroyed) + logger.debug(f"{self.name} init camera") def process(self, frame): """Process the frame using the worker. @@ -273,33 +274,46 @@ def process(self, frame): def start(self): """Start the reticle detection manager.""" + logger.debug(f"{self.name} Starting thread in {self.__class__.__name__}") self.init_thread() # Reinitialize and start the worker and thread self.worker.start_running() self.thread.start() - logger.debug(f"thread started {self.name}") def stop(self): """Stop the reticle detection manager.""" if self.worker is not None: self.worker.stop_running() + + def onWorkerDestroyed(self): + """Cleanup after worker finishes.""" + logger.debug(f"{self.name} worker finished") + + def onThreadDestroyed(self): + """Flag if thread is deleted""" + logger.debug(f"{self.name} thread destroyed") + self.threadDeleted = True + self.thread = None def set_name(self, camera_name): """Set camera name.""" self.name = camera_name if self.worker is not None: self.worker.set_name(self.name) - logger.debug(f"camera name: {self.name}") + logger.debug(f"{self.name} set camera name") def clean(self): """Safely clean up the reticle detection manager.""" - logger.debug("Cleaning the thread") + logger.debug(f"{self.name} Cleaning the thread") if self.worker is not None: self.worker.stop_running() # Signal the worker to stop + if not self.threadDeleted and self.thread.isRunning(): + logger.debug(f"{self.name} Stopping thread in {self.__class__.__name__}") self.thread.quit() # Ask the thread to quit self.thread.wait() # Wait for the thread to finish self.thread = None # Clear the reference to the thread self.worker = None # Clear the reference to the worker + logger.debug(f"{self.name} Cleaned the thread") def onThreadDestroyed(self): """Flag if thread is deleted""" diff --git a/parallax/screen_widget.py b/parallax/screen_widget.py index 8d2de380..b777e066 100755 --- a/parallax/screen_widget.py +++ b/parallax/screen_widget.py @@ -75,11 +75,11 @@ def __init__(self, camera, filename=None, model=None, parent=None): self.focochan = None # No filter - self.filter = NoFilter() + self.filter = NoFilter(camera_name) self.filter.frame_processed.connect(self.set_image_item_from_data) # Axis Filter - self.axisFilter = AxisFilter(camera_name) + self.axisFilter = AxisFilter(self.model, camera_name) self.axisFilter.frame_processed.connect(self.set_image_item_from_data) # Reticle Detection @@ -255,6 +255,9 @@ def get_camera_color_type(self): if self.camera: return self.camera.device_color_type + def send_clicked_position(self, pos): + self.axisFilter.clicked_position(pos) + def image_clicked(self, event): """ Handle the image click event. @@ -264,6 +267,7 @@ def image_clicked(self, event): x, y = int(round(x)), int(round(y)) self.select((x,y)) print(f"Clicked position on {self.get_camera_name()}: ({x}, {y})") + self.send_clicked_position((x, y)) elif event.button() == QtCore.Qt.MouseButton.MiddleButton: self.zoom_out() @@ -293,17 +297,20 @@ def set_camera(self, camera): self.reticleDetector.set_name(camera_sn) self.probeDetector.set_name(camera_sn) self.axisFilter.set_name(camera_sn) + self.filter.set_name(camera_sn) def run_reticle_detection(self): """Run reticle detection by stopping the filter and starting the reticle detector.""" logger.debug("run_reticle_detection") self.filter.stop() + self.axisFilter.stop() self.reticleDetector.start() def run_probe_detection(self): """Run probe detection by stopping the filter and starting the probe detector.""" logger.debug("run_probe_detection") self.filter.stop() + self.axisFilter.stop() self.probeDetector.start() def run_no_filter(self): diff --git a/parallax/stage_widget.py b/parallax/stage_widget.py index d27949cc..758c3e92 100644 --- a/parallax/stage_widget.py +++ b/parallax/stage_widget.py @@ -9,7 +9,7 @@ import logging import os import math - +import time import numpy as np from PyQt5.QtCore import QTimer @@ -25,7 +25,6 @@ logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) - class StageWidget(QWidget): """Widget for stage control and calibration.""" @@ -87,7 +86,7 @@ def __init__(self, model, ui_dir, screen_widgets): # Reticle Widget self.reticle_detection_status = ( - None # options: default, process, detected, accepted, request_axis + "default" # options: default, process, detected, accepted, request_axis ) self.reticle_calibration_btn.clicked.connect( self.reticle_detection_button_handler @@ -105,6 +104,8 @@ def __init__(self, model, ui_dir, screen_widgets): self.reticle_calibration_timer.timeout.connect( self.reticle_detect_default_status ) + self.get_pos_x_from_user_timer = QTimer() + self.get_pos_x_from_user_timer.timeout.connect(self.check_positive_x_axis) # Stage widget self.stageUI = StageUI(self.model, self) @@ -133,6 +134,7 @@ def __init__(self, model, ui_dir, screen_widgets): self.probe_detection_status = None # options: default, process, x_y_z_detected, accepted self.filter = "no_filter" + logger.debug(f"filter: {self.filter}") def reticle_detection_button_handler(self): """ @@ -144,7 +146,7 @@ def reticle_detection_button_handler(self): self.reticle_detect_process_status() else: if self.reticle_detection_status == "accepted": - response = self.overwrite_popup_window() + response = self.reticle_overwrite_popup_window() if response: # Overwrite the result self.reticle_detect_default_status() @@ -166,13 +168,15 @@ def reticle_detect_default_status(self): # Stop reticle detectoin, and run no filter self.reticle_calibration_timer.stop() - if self.reticle_detection_status != "accepted": - for screen in self.screen_widgets: + for screen in self.screen_widgets: + if self.filter != "no_filter": + screen.run_no_filter() + if self.reticle_detection_status != "accepted": screen.reticle_coords_detected.disconnect( self.reticle_detect_two_screens - ) - screen.run_no_filter() - self.filter = "no_filter" + ) + self.filter = "no_filter" + logger.debug(f"filter: {self.filter}") # Hide Accept and Reject Button self.acceptButton.hide() @@ -194,7 +198,7 @@ def reticle_detect_default_status(self): # Disable probe calibration self.probe_detect_default_status() - def overwrite_popup_window(self): + def reticle_overwrite_popup_window(self): """ Displays a confirmation dialog to decide whether to overwrite the current reticle position. @@ -204,9 +208,10 @@ def overwrite_popup_window(self): message = ( f"Are you sure you want to overwrite the current reticle position?" ) + logger.debug(f"Are you sure you want to overwrite the current reticle position?") response = QMessageBox.warning( self, - "Reticle Detection Failed", + "Reticle Detection", message, QMessageBox.Yes | QMessageBox.No, QMessageBox.No, @@ -260,6 +265,7 @@ def reticle_detect_process_status(self): ) screen.run_reticle_detection() self.filter = "reticle_detection" + logger.debug(f"filter: {self.filter}") # Hide Accept and Reject Button self.acceptButton.hide() @@ -288,18 +294,58 @@ def reticle_detect_detected_status(self): "background-color: #bc9e44;" ) - def get_positive_x_axis_from_user(self): + def select_positive_x_popup_window(self): + message = ( + f"Click positive x-axis on each screen" + ) + QMessageBox.warning(self, "Calibration", message) + + def get_coords_detected_screens(self): + coords_detected_cam_name = [] + for screen in self.screen_widgets: + cam_name = screen.get_camera_name() + coords = self.model.get_coords_axis(cam_name) + if coords is not None: + coords_detected_cam_name.append(cam_name) + + return coords_detected_cam_name + + def is_positive_x_axis_detected(self): + pos_x_detected_screens = [] + for cam_name in self.coords_detected_screens: + pos_x = self.model.get_pos_x(cam_name) + if pos_x is not None: + pos_x_detected_screens.append(cam_name) + + return set(self.coords_detected_screens) == set(pos_x_detected_screens) + + def check_positive_x_axis(self): + if self.is_positive_x_axis_detected(): + self.get_pos_x_from_user_timer.stop() # Stop the timer if the positive x-axis has been detected + # Continue to calibrate stereo + self.start_calibrate_streo() + self.enable_reticle_probe_calibration_buttons() + logger.debug("Positive x-axis detected on all screens.") + else: + self.coords_detected_screens = self.get_coords_detected_screens() + logger.debug("Checking again for user input of positive x-axis...") + + def continue_if_positive_x_axis_from_user(self): """Get the positive x-axis coordinate of the reticle from the user.""" for screen in self.screen_widgets: screen.reticle_coords_detected.disconnect( self.reticle_detect_two_screens ) screen.run_axis_filter() - self.filter = "axis_filter" + + self.select_positive_x_popup_window() + self.coords_detected_screens = self.get_coords_detected_screens() + self.get_pos_x_from_user_timer.start(1000) def reticle_detect_accept_detected_status(self): """ - Finalizes the reticle detection process, accepting the detected reticle position and updating the UI accordingly. + Finalizes the reticle detection process, accepting the detected + reticle position and updating the UI accordingly. """ self.reticle_detection_status = "accepted" logger.debug(f"1 self.filter: {self.filter}") @@ -313,10 +359,23 @@ def reticle_detect_accept_detected_status(self): self.acceptButton.hide() self.rejectButton.hide() - # TODO Get user input of positive x coordiante of the reticle - self.get_positive_x_axis_from_user() + # TODO Get user input of positive x coor distance of the reticle + self.continue_if_positive_x_axis_from_user() logger.debug(f"2 self.filter: {self.filter}") + + """ + for screen in self.screen_widgets: + screen.reticle_coords_detected.disconnect( + self.reticle_detect_two_screens + ) + screen.run_no_filter() + self.filter = "no_filter" + logger.debug(f"filter: {self.filter}") + self.start_calibrate_streo() + self.enable_reticle_probe_calibration_buttons() + """ + def start_calibrate_streo(self): # Perform stereo calibration result = self.calibrate_stereo() if result: @@ -325,15 +384,7 @@ def reticle_detect_accept_detected_status(self): f"{result*1000:.1f} µm³" ) - """ - for screen in self.screen_widgets: - screen.reticle_coords_detected.disconnect( - self.reticle_detect_two_screens - ) - screen.run_no_filter() - self.filter = "no_filter" - logger.debug(f"3 self.filter: {self.filter}") - """ + def enable_reticle_probe_calibration_buttons(self): # Enable reticle_calibration_btn button if not self.reticle_calibration_btn.isEnabled(): self.reticle_calibration_btn.setEnabled(True) @@ -567,7 +618,7 @@ def probe_overwrite_popup_window(self): ) response = QMessageBox.warning( self, - "Reticle Detection Failed", + "Probe Detection", message, QMessageBox.Yes | QMessageBox.No, QMessageBox.No, @@ -628,6 +679,7 @@ def probe_detect_default_status(self): screen.run_no_filter() self.filter = "no_filter" + logger.debug(f"filter: {self.filter}") self.probeCalibration.clear() # update global coords @@ -653,7 +705,10 @@ def probe_detect_process_status(self): print(f"Connect probe_detection: {camera_name}") screen.probe_coords_detected.connect(self.probe_detect_two_screens) screen.run_probe_detection() + else: + screen.run_no_filter() self.filter = "probe_detection" + logger.debug(f"filter: {self.filter}") # message message = f"Move probe at least 2mm along X, Y, and Z axes" @@ -685,6 +740,7 @@ def probe_detect_accepted_status(self, stage_sn, transformation_matrix): screen.run_no_filter() self.filter = "no_filter" + logger.debug(f"filter: {self.filter}") # update global coords self.stageListener.requestUpdateGlobalDataTransformM(