GUI: added face_detection_panel.py
This commit is contained in:
@@ -22,6 +22,7 @@ from aaregui.panels.manual_sample_panel import ManualSamplePanel
|
||||
from aaregui.panels.reference_tools_panel import ReferenceToolsPanel
|
||||
from aaregui.panels.sample_queue_panel import SampleQueuePanel
|
||||
from aaregui.panels.tell_sample_panel import TellSamplePanel
|
||||
from aaregui.panels.face_detection_panel import FaceDetectionPanel
|
||||
from aaregui.scan_logic.raster_grid_manager import RasterGridManager
|
||||
from aaregui.scan_logic.rotation_scan_manager import RotationScanManager
|
||||
from aaregui.scan_logic.sample_mount_logic import SampleMountLogic
|
||||
@@ -154,6 +155,12 @@ class MainWindow(QMainWindow):
|
||||
self.manual_sample_dock.setAllowedAreas(Qt.DockWidgetArea.BottomDockWidgetArea)
|
||||
self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.manual_sample_dock)
|
||||
|
||||
self.face_panel = FaceDetectionPanel(api_base_url=self.__base_url, token=self.__token)
|
||||
self.face_panel_dock = QDockWidget("Face detection", self)
|
||||
self.face_panel_dock.setWidget(self.face_panel)
|
||||
self.face_panel_dock.setAllowedAreas(Qt.DockWidgetArea.RightDockWidgetArea | Qt.DockWidgetArea.LeftDockWidgetArea)
|
||||
self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.face_panel_dock)
|
||||
|
||||
self.setCentralWidget(top_widget)
|
||||
|
||||
self.setWindowTitle("AareGUI")
|
||||
@@ -297,6 +304,8 @@ class MainWindow(QMainWindow):
|
||||
self.daq.raster_scan_completed.connect(self.raster.grid_scan_completed)
|
||||
|
||||
self.manual_sample_panel.sample_manual.connect(self.daq.sample_manual)
|
||||
self.face_panel.face_detection.connect(self.daq.face_detection)
|
||||
self.daq.face_detection_result.connect(self.face_panel.update_plot)
|
||||
|
||||
def create_menu_bar(self):
|
||||
"""Create a menu bar with File->Quit and Help->About."""
|
||||
@@ -332,8 +341,18 @@ class MainWindow(QMainWindow):
|
||||
show_manual_sample_action.setChecked(True)
|
||||
show_manual_sample_action.triggered.connect(self.manual_sample_dock.setVisible)
|
||||
# When dock visibility changes, update the action's checked state
|
||||
show_manual_sample_action.triggered.connect(lambda: self.manual_sample_dock.setVisible(show_job_list_action.isChecked()))
|
||||
show_manual_sample_action.triggered.connect(lambda: self.manual_sample_dock.setVisible(show_manual_sample_action.isChecked()))
|
||||
view_menu.addAction(show_manual_sample_action)
|
||||
|
||||
show_face_panel_action = QAction("Show face detection", self)
|
||||
show_face_panel_action.setCheckable(True)
|
||||
show_face_panel_action.setChecked(True)
|
||||
show_face_panel_action.triggered.connect(self.face_panel_dock.setVisible)
|
||||
# When dock visibility changes, update the action's checked state
|
||||
# show_face_panel_action.triggered.connect(
|
||||
# lambda: self.face_panel_dock.setVisible(show_face_panel_action.isChecked()))
|
||||
self.face_panel_dock.visibilityChanged.connect(show_face_panel_action.setChecked)
|
||||
view_menu.addAction(show_face_panel_action)
|
||||
# Help menu
|
||||
help_menu = menu_bar.addMenu("Help")
|
||||
about_action = QAction("About", self) # Action for 'About'
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
# Python
|
||||
from PySide6.QtCore import Slot, Qt, Signal
|
||||
from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QFrame, QPushButton, QSpacerItem, QSizePolicy, QVBoxLayout, \
|
||||
QHBoxLayout
|
||||
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
||||
from matplotlib.figure import Figure
|
||||
import numpy as np
|
||||
|
||||
from aaregui.widgets.title_label import TitleLabel
|
||||
|
||||
|
||||
class FaceDetectionPanel(QWidget):
|
||||
|
||||
face_detection = Signal()
|
||||
|
||||
def __init__(self, parent=None, api_base_url: str | None = None, token: str | None = None):
|
||||
super().__init__(parent)
|
||||
self.api_base_url = api_base_url or ""
|
||||
self.token = token or ""
|
||||
|
||||
self.fig = Figure(figsize=(5, 4), tight_layout=True)
|
||||
self.canvas = FigureCanvas(self.fig)
|
||||
self.ax1 = self.fig.add_subplot(2, 1, 1) # Height vs angle
|
||||
self.ax2 = self.fig.add_subplot(2, 1, 2) # Area vs angle
|
||||
|
||||
|
||||
_top_layout = QHBoxLayout()
|
||||
_top_layout.addWidget(TitleLabel("TELL sample changer", self))
|
||||
self.status_lbl = QLabel("")
|
||||
_top_layout.addWidget(self.status_lbl)
|
||||
|
||||
self.face_detection_button = QPushButton("Face Detection")
|
||||
self.face_detection_button.setStyleSheet("color: rgb(78, 154, 6);")
|
||||
self.face_detection_button.clicked.connect(self.run_and_refresh)
|
||||
_top_layout.addWidget(self.face_detection_button)
|
||||
|
||||
_layout = QVBoxLayout(self)
|
||||
_layout.addLayout(_top_layout)
|
||||
_layout.addWidget(self.canvas)
|
||||
self.setLayout(_layout)
|
||||
|
||||
def run_and_refresh(self):
|
||||
try:
|
||||
self.face_detection.emit()
|
||||
except Exception as e:
|
||||
self.status_lbl.setText(f"Error: {e}")
|
||||
|
||||
def update_plot(self, data):
|
||||
samples = data.get("samples", [])
|
||||
if not samples:
|
||||
self.ax1.clear()
|
||||
self.ax2.clear()
|
||||
self.ax1.text(0.5, 0.5, "No data", ha="center", va="center")
|
||||
self.ax2.text(0.5, 0.5, "No data", ha="center", va="center")
|
||||
self.canvas.draw_idle()
|
||||
return
|
||||
|
||||
angles = np.array([s["angle_deg"] for s in samples], dtype=float)
|
||||
heights = np.array([s["height"] for s in samples], dtype=float)
|
||||
areas = np.array([s["area"] for s in samples], dtype=float)
|
||||
self.ax1.clear()
|
||||
self.ax2.clear()
|
||||
|
||||
self.ax1.scatter(angles, heights, s=16, c="tab:blue", label="Height")
|
||||
self.ax2.scatter(angles, areas, s=16, c="tab:green", label="Area")
|
||||
|
||||
ang_grid = np.linspace(angles.min(), angles.max(), 400)
|
||||
|
||||
hf = data.get("height_fit", {})
|
||||
if {"A", "B", "phi_rad"} <= hf.keys():
|
||||
A, B, phi = hf["A"], hf["B"], hf["phi_rad"]
|
||||
height_fit = A + B * np.cos(np.deg2rad(ang_grid) - phi)
|
||||
self.ax1.plot(ang_grid, height_fit, color="tab:orange", label="Height fit")
|
||||
if "best_angle_deg" in hf:
|
||||
self.ax1.axvline(hf["best_angle_deg"], color="tab:orange", ls="--", alpha=0.6)
|
||||
|
||||
af = data.get("area_fit", {})
|
||||
if {"A", "B", "phi_rad"} <= af.keys():
|
||||
A2, B2, phi2 = af["A"], af["B"], af["phi_rad"]
|
||||
area_fit = A2 + B2 * np.cos(np.deg2rad(ang_grid) - phi2)
|
||||
self.ax2.plot(ang_grid, area_fit, color="tab:red", label="Area fit")
|
||||
if "best_angle_deg" in af:
|
||||
self.ax2.axvline(af["best_angle_deg"], color="tab:red", ls="--", alpha=0.6)
|
||||
|
||||
self.ax1.set_xlabel("Angle (deg)")
|
||||
self.ax1.set_ylabel("Height")
|
||||
self.ax1.legend()
|
||||
self.ax1.grid(True, alpha=0.3)
|
||||
|
||||
self.ax2.set_xlabel("Angle (deg)")
|
||||
self.ax2.set_ylabel("Area")
|
||||
self.ax2.legend()
|
||||
self.ax2.grid(True, alpha=0.3)
|
||||
|
||||
self.canvas.draw_idle()
|
||||
Reference in New Issue
Block a user