yesssssssssss ; it fucking wooooooooooorks !!!!
This commit is contained in:
360
mucapy/main.py
360
mucapy/main.py
@@ -1302,6 +1302,14 @@ class MainWindow(QMainWindow):
|
||||
# Initialize configuration
|
||||
self.config = Config()
|
||||
|
||||
# Initialize default values
|
||||
self.current_layout = 0 # Default to single camera layout
|
||||
self.detector = MultiCamYOLODetector()
|
||||
self.camera_settings = {}
|
||||
|
||||
# Load saved settings first
|
||||
self.load_saved_settings()
|
||||
|
||||
# Set dark theme style
|
||||
self.setStyleSheet("""
|
||||
QMainWindow, QWidget {
|
||||
@@ -1401,16 +1409,18 @@ class MainWindow(QMainWindow):
|
||||
palette.setColor(palette.HighlightedText, Qt.black)
|
||||
self.setPalette(palette)
|
||||
|
||||
self.detector = MultiCamYOLODetector()
|
||||
self.camera_settings = {}
|
||||
|
||||
# Load saved settings
|
||||
self.load_saved_settings()
|
||||
|
||||
self.create_menus()
|
||||
# Initialize UI elements
|
||||
self.init_ui()
|
||||
|
||||
# Create menus
|
||||
self.create_menus()
|
||||
|
||||
# Initialize timer
|
||||
self.init_timer()
|
||||
|
||||
|
||||
# Apply saved settings to UI
|
||||
self.apply_saved_settings()
|
||||
|
||||
def load_saved_settings(self):
|
||||
"""Load saved settings from configuration"""
|
||||
# Load model directory
|
||||
@@ -1426,11 +1436,16 @@ class MainWindow(QMainWindow):
|
||||
# Load layout setting
|
||||
self.current_layout = int(self.config.load_setting('layout', 0))
|
||||
|
||||
def save_settings(self):
|
||||
"""Save current settings to configuration"""
|
||||
self.config.save_setting('model_dir', self.detector.model_dir)
|
||||
self.config.save_setting('fps', self.fps_spin.value())
|
||||
self.config.save_setting('layout', self.layout_combo.currentIndex())
|
||||
def apply_saved_settings(self):
|
||||
"""Apply loaded settings to UI elements"""
|
||||
if hasattr(self, 'fps_spin'):
|
||||
self.fps_spin.setValue(self.detector.target_fps)
|
||||
|
||||
if hasattr(self, 'layout_combo'):
|
||||
self.layout_combo.setCurrentIndex(self.current_layout)
|
||||
|
||||
if hasattr(self, 'model_label') and self.detector.model_dir:
|
||||
self.model_label.setText(f"Model: {os.path.basename(self.detector.model_dir)}")
|
||||
|
||||
def create_menus(self):
|
||||
menubar = self.menuBar()
|
||||
@@ -1452,6 +1467,7 @@ class MainWindow(QMainWindow):
|
||||
|
||||
# Add Camera Selector action
|
||||
select_cameras_action = QAction('Select Cameras...', self)
|
||||
select_cameras_action.setIcon(QIcon.fromTheme('camera-web'))
|
||||
select_cameras_action.triggered.connect(self.show_camera_selector)
|
||||
self.camera_menu.addAction(select_cameras_action)
|
||||
|
||||
@@ -1459,41 +1475,240 @@ class MainWindow(QMainWindow):
|
||||
|
||||
# Add Network Camera Settings action
|
||||
network_camera_action = QAction('Network Camera Settings...', self)
|
||||
network_camera_action.setIcon(QIcon.fromTheme('network-wireless'))
|
||||
network_camera_action.triggered.connect(self.show_network_camera_dialog)
|
||||
self.camera_menu.addAction(network_camera_action)
|
||||
|
||||
self.camera_menu.addSeparator()
|
||||
|
||||
self.camera_action_group = QActionGroup(self)
|
||||
self.camera_action_group.setExclusive(False)
|
||||
# Create camera groups
|
||||
self.local_camera_menu = QMenu('Local Cameras', self)
|
||||
self.network_camera_menu = QMenu('Network Cameras', self)
|
||||
self.camera_menu.addMenu(self.local_camera_menu)
|
||||
self.camera_menu.addMenu(self.network_camera_menu)
|
||||
|
||||
# Create action groups for each camera type
|
||||
self.local_camera_group = QActionGroup(self)
|
||||
self.local_camera_group.setExclusive(False)
|
||||
self.network_camera_group = QActionGroup(self)
|
||||
self.network_camera_group.setExclusive(False)
|
||||
|
||||
# Initial population
|
||||
self.populate_camera_menu()
|
||||
|
||||
def populate_camera_menu(self):
|
||||
"""Populate the camera menu with available cameras"""
|
||||
# Clear existing camera actions (except refresh and network camera settings)
|
||||
for action in self.camera_menu.actions()[3:]:
|
||||
self.camera_menu.removeAction(action)
|
||||
# Clear existing camera actions
|
||||
self.local_camera_menu.clear()
|
||||
self.network_camera_menu.clear()
|
||||
|
||||
# Add refresh action to both menus
|
||||
refresh_action = QAction('Refresh List', self)
|
||||
refresh_action.triggered.connect(self.populate_camera_menu)
|
||||
self.local_camera_menu.addAction(refresh_action)
|
||||
self.local_camera_menu.addSeparator()
|
||||
|
||||
available_cams = self.detector.scan_for_cameras()
|
||||
for cam_path in available_cams:
|
||||
# Display friendly name
|
||||
if cam_path.startswith('net:'):
|
||||
name = cam_path[4:] # Use the camera name directly
|
||||
display_name = f"{name}"
|
||||
elif cam_path.startswith('/dev/'):
|
||||
display_name = os.path.basename(cam_path)
|
||||
else:
|
||||
display_name = f"Camera {cam_path}"
|
||||
|
||||
action = QAction(display_name, self, checkable=True)
|
||||
action.setData(cam_path)
|
||||
self.camera_action_group.addAction(action)
|
||||
self.camera_menu.addAction(action)
|
||||
local_cams_found = False
|
||||
network_cams_found = False
|
||||
|
||||
if not available_cams:
|
||||
no_cam_action = QAction('No cameras found', self)
|
||||
no_cam_action.setEnabled(False)
|
||||
self.camera_menu.addAction(no_cam_action)
|
||||
for cam_path in available_cams:
|
||||
if cam_path.startswith('net:'):
|
||||
# Network camera
|
||||
name = cam_path[4:]
|
||||
action = QAction(name, self)
|
||||
action.setCheckable(True)
|
||||
action.setData(cam_path)
|
||||
self.network_camera_group.addAction(action)
|
||||
self.network_camera_menu.addAction(action)
|
||||
network_cams_found = True
|
||||
else:
|
||||
# Local camera
|
||||
if cam_path.startswith('/dev/'):
|
||||
display_name = os.path.basename(cam_path)
|
||||
else:
|
||||
display_name = f"Camera {cam_path}"
|
||||
|
||||
action = QAction(display_name, self)
|
||||
action.setCheckable(True)
|
||||
action.setData(cam_path)
|
||||
self.local_camera_group.addAction(action)
|
||||
self.local_camera_menu.addAction(action)
|
||||
local_cams_found = True
|
||||
|
||||
# Add placeholder text if no cameras found
|
||||
if not local_cams_found:
|
||||
no_local = QAction('No local cameras found', self)
|
||||
no_local.setEnabled(False)
|
||||
self.local_camera_menu.addAction(no_local)
|
||||
|
||||
if not network_cams_found:
|
||||
no_net = QAction('No network cameras found', self)
|
||||
no_net.setEnabled(False)
|
||||
self.network_camera_menu.addAction(no_net)
|
||||
|
||||
# Update the camera label
|
||||
self.update_selection_labels()
|
||||
|
||||
def update_selection_labels(self):
|
||||
"""Update the model and camera selection labels"""
|
||||
selected_cams = []
|
||||
|
||||
# Check local cameras
|
||||
for action in self.local_camera_group.actions():
|
||||
if action.isChecked():
|
||||
selected_cams.append(action.text())
|
||||
|
||||
# Check network cameras
|
||||
for action in self.network_camera_group.actions():
|
||||
if action.isChecked():
|
||||
selected_cams.append(action.text())
|
||||
|
||||
if selected_cams:
|
||||
self.cameras_label.setText(f"Selected Cameras: {', '.join(selected_cams)}")
|
||||
else:
|
||||
self.cameras_label.setText("Selected Cameras: None")
|
||||
|
||||
def start_detection(self):
|
||||
"""Start the detection process"""
|
||||
if not self.detector.model_dir:
|
||||
QMessageBox.critical(self, "Error", "No model directory selected!")
|
||||
return
|
||||
|
||||
# Get selected cameras
|
||||
selected_cameras = []
|
||||
|
||||
# Get local cameras
|
||||
for action in self.local_camera_group.actions():
|
||||
if action.isChecked():
|
||||
selected_cameras.append(action.data())
|
||||
|
||||
# Get network cameras
|
||||
for action in self.network_camera_group.actions():
|
||||
if action.isChecked():
|
||||
selected_cameras.append(action.data())
|
||||
|
||||
if not selected_cameras:
|
||||
QMessageBox.critical(self, "Error", "No cameras selected!")
|
||||
return
|
||||
|
||||
# Set FPS
|
||||
self.detector.target_fps = self.fps_spin.value()
|
||||
self.detector.frame_interval = 1.0 / self.detector.target_fps
|
||||
|
||||
# Connect to cameras
|
||||
if not self.detector.connect_cameras(selected_cameras):
|
||||
QMessageBox.critical(self, "Error", "Failed to connect to cameras!")
|
||||
return
|
||||
|
||||
# Update UI
|
||||
self.update_selection_labels()
|
||||
self.start_btn.setEnabled(False)
|
||||
self.stop_btn.setEnabled(True)
|
||||
self.fps_spin.setEnabled(False)
|
||||
|
||||
# Start timer
|
||||
self.timer.start(int(1000 / self.detector.target_fps))
|
||||
|
||||
def show_camera_selector(self):
|
||||
"""Show a simplified camera selector dialog"""
|
||||
dialog = QDialog(self)
|
||||
dialog.setWindowTitle("Select Cameras")
|
||||
dialog.setModal(True)
|
||||
layout = QVBoxLayout(dialog)
|
||||
|
||||
# Create tabs for different camera types
|
||||
tabs = QTabWidget()
|
||||
local_tab = QWidget()
|
||||
network_tab = QWidget()
|
||||
|
||||
# Local cameras tab
|
||||
local_layout = QVBoxLayout(local_tab)
|
||||
local_list = QListWidget()
|
||||
local_layout.addWidget(QLabel("Available Local Cameras:"))
|
||||
local_layout.addWidget(local_list)
|
||||
|
||||
# Network cameras tab
|
||||
network_layout = QVBoxLayout(network_tab)
|
||||
network_list = QListWidget()
|
||||
network_layout.addWidget(QLabel("Available Network Cameras:"))
|
||||
network_layout.addWidget(network_list)
|
||||
|
||||
# Add tabs
|
||||
tabs.addTab(local_tab, "Local Cameras")
|
||||
tabs.addTab(network_tab, "Network Cameras")
|
||||
layout.addWidget(tabs)
|
||||
|
||||
# Populate lists
|
||||
available_cams = self.detector.scan_for_cameras()
|
||||
for cam_path in available_cams:
|
||||
if cam_path.startswith('net:'):
|
||||
name = cam_path[4:]
|
||||
item = QListWidgetItem(name)
|
||||
item.setData(Qt.UserRole, cam_path)
|
||||
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
||||
item.setCheckState(Qt.Unchecked)
|
||||
network_list.addItem(item)
|
||||
else:
|
||||
display_name = os.path.basename(cam_path) if cam_path.startswith('/dev/') else f"Camera {cam_path}"
|
||||
item = QListWidgetItem(display_name)
|
||||
item.setData(Qt.UserRole, cam_path)
|
||||
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
||||
item.setCheckState(Qt.Unchecked)
|
||||
local_list.addItem(item)
|
||||
|
||||
# Check currently selected cameras
|
||||
for action in self.local_camera_group.actions():
|
||||
if action.isChecked():
|
||||
for i in range(local_list.count()):
|
||||
item = local_list.item(i)
|
||||
if item.data(Qt.UserRole) == action.data():
|
||||
item.setCheckState(Qt.Checked)
|
||||
|
||||
for action in self.network_camera_group.actions():
|
||||
if action.isChecked():
|
||||
for i in range(network_list.count()):
|
||||
item = network_list.item(i)
|
||||
if item.data(Qt.UserRole) == action.data():
|
||||
item.setCheckState(Qt.Checked)
|
||||
|
||||
# Buttons
|
||||
btn_layout = QHBoxLayout()
|
||||
ok_btn = QPushButton("OK")
|
||||
cancel_btn = QPushButton("Cancel")
|
||||
btn_layout.addWidget(ok_btn)
|
||||
btn_layout.addWidget(cancel_btn)
|
||||
layout.addLayout(btn_layout)
|
||||
|
||||
ok_btn.clicked.connect(dialog.accept)
|
||||
cancel_btn.clicked.connect(dialog.reject)
|
||||
|
||||
if dialog.exec_() == QDialog.Accepted:
|
||||
# Update camera selections
|
||||
for action in self.local_camera_group.actions():
|
||||
action.setChecked(False)
|
||||
for action in self.network_camera_group.actions():
|
||||
action.setChecked(False)
|
||||
|
||||
# Update local camera selections
|
||||
for i in range(local_list.count()):
|
||||
item = local_list.item(i)
|
||||
if item.checkState() == Qt.Checked:
|
||||
cam_path = item.data(Qt.UserRole)
|
||||
for action in self.local_camera_group.actions():
|
||||
if action.data() == cam_path:
|
||||
action.setChecked(True)
|
||||
|
||||
# Update network camera selections
|
||||
for i in range(network_list.count()):
|
||||
item = network_list.item(i)
|
||||
if item.checkState() == Qt.Checked:
|
||||
cam_path = item.data(Qt.UserRole)
|
||||
for action in self.network_camera_group.actions():
|
||||
if action.data() == cam_path:
|
||||
action.setChecked(True)
|
||||
|
||||
self.update_selection_labels()
|
||||
|
||||
def load_model_directory(self):
|
||||
"""Open file dialog to select model directory"""
|
||||
@@ -1631,12 +1846,6 @@ class MainWindow(QMainWindow):
|
||||
|
||||
# Start with sidebar expanded
|
||||
self.sidebar.expand()
|
||||
|
||||
# Set saved FPS value
|
||||
self.fps_spin.setValue(self.detector.target_fps)
|
||||
|
||||
# Set saved layout
|
||||
self.layout_combo.setCurrentIndex(self.current_layout)
|
||||
|
||||
def change_camera_layout(self, index):
|
||||
"""Change the camera display layout"""
|
||||
@@ -1674,40 +1883,6 @@ class MainWindow(QMainWindow):
|
||||
self.timer = QTimer()
|
||||
self.timer.timeout.connect(self.update_feeds)
|
||||
|
||||
def start_detection(self):
|
||||
"""Start the detection process"""
|
||||
if not self.detector.model_dir:
|
||||
QMessageBox.critical(self, "Error", "No model directory selected!")
|
||||
return
|
||||
|
||||
# Get selected cameras
|
||||
selected_cameras = []
|
||||
for action in self.camera_action_group.actions():
|
||||
if action.isChecked():
|
||||
selected_cameras.append(action.data())
|
||||
|
||||
if not selected_cameras:
|
||||
QMessageBox.critical(self, "Error", "No cameras selected!")
|
||||
return
|
||||
|
||||
# Set FPS
|
||||
self.detector.target_fps = self.fps_spin.value()
|
||||
self.detector.frame_interval = 1.0 / self.detector.target_fps
|
||||
|
||||
# Connect to cameras
|
||||
if not self.detector.connect_cameras(selected_cameras):
|
||||
QMessageBox.critical(self, "Error", "Failed to connect to cameras!")
|
||||
return
|
||||
|
||||
# Update UI
|
||||
self.update_selection_labels()
|
||||
self.start_btn.setEnabled(False)
|
||||
self.stop_btn.setEnabled(True)
|
||||
self.fps_spin.setEnabled(False)
|
||||
|
||||
# Start timer
|
||||
self.timer.start(int(1000 / self.detector.target_fps))
|
||||
|
||||
def stop_detection(self):
|
||||
"""Stop the detection process"""
|
||||
self.timer.stop()
|
||||
@@ -1730,15 +1905,6 @@ class MainWindow(QMainWindow):
|
||||
}
|
||||
""")
|
||||
|
||||
def update_selection_labels(self):
|
||||
"""Update the model and camera selection labels"""
|
||||
# Update cameras label
|
||||
selected_cams = []
|
||||
for action in self.camera_action_group.actions():
|
||||
if action.isChecked():
|
||||
selected_cams.append(action.text())
|
||||
self.cameras_label.setText(f"Selected Cameras: {', '.join(selected_cams) or 'None'}")
|
||||
|
||||
def update_feeds(self):
|
||||
"""Update the camera feeds in the display"""
|
||||
frames = self.detector.get_frames()
|
||||
@@ -1793,30 +1959,6 @@ class MainWindow(QMainWindow):
|
||||
dialog.exec_()
|
||||
# Refresh camera list after dialog closes
|
||||
self.populate_camera_menu()
|
||||
|
||||
def show_camera_selector(self):
|
||||
"""Show the camera selector dialog"""
|
||||
dialog = CameraSelectorDialog(self)
|
||||
if dialog.exec_() == QDialog.Accepted and dialog.selected_cameras:
|
||||
# Stop current detection if running
|
||||
was_running = False
|
||||
if self.stop_btn.isEnabled():
|
||||
was_running = True
|
||||
self.stop_detection()
|
||||
|
||||
# Update selected cameras
|
||||
for action in self.camera_action_group.actions():
|
||||
action.setChecked(action.data() in dialog.selected_cameras)
|
||||
|
||||
# Restart detection if it was running
|
||||
if was_running:
|
||||
self.start_detection()
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""Handle window close event"""
|
||||
self.stop_detection()
|
||||
self.save_settings()
|
||||
super().closeEvent(event)
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
Reference in New Issue
Block a user