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
|
# Initialize configuration
|
||||||
self.config = Config()
|
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
|
# Set dark theme style
|
||||||
self.setStyleSheet("""
|
self.setStyleSheet("""
|
||||||
QMainWindow, QWidget {
|
QMainWindow, QWidget {
|
||||||
@@ -1401,16 +1409,18 @@ class MainWindow(QMainWindow):
|
|||||||
palette.setColor(palette.HighlightedText, Qt.black)
|
palette.setColor(palette.HighlightedText, Qt.black)
|
||||||
self.setPalette(palette)
|
self.setPalette(palette)
|
||||||
|
|
||||||
self.detector = MultiCamYOLODetector()
|
# Initialize UI elements
|
||||||
self.camera_settings = {}
|
|
||||||
|
|
||||||
# Load saved settings
|
|
||||||
self.load_saved_settings()
|
|
||||||
|
|
||||||
self.create_menus()
|
|
||||||
self.init_ui()
|
self.init_ui()
|
||||||
|
|
||||||
|
# Create menus
|
||||||
|
self.create_menus()
|
||||||
|
|
||||||
|
# Initialize timer
|
||||||
self.init_timer()
|
self.init_timer()
|
||||||
|
|
||||||
|
# Apply saved settings to UI
|
||||||
|
self.apply_saved_settings()
|
||||||
|
|
||||||
def load_saved_settings(self):
|
def load_saved_settings(self):
|
||||||
"""Load saved settings from configuration"""
|
"""Load saved settings from configuration"""
|
||||||
# Load model directory
|
# Load model directory
|
||||||
@@ -1426,11 +1436,16 @@ class MainWindow(QMainWindow):
|
|||||||
# Load layout setting
|
# Load layout setting
|
||||||
self.current_layout = int(self.config.load_setting('layout', 0))
|
self.current_layout = int(self.config.load_setting('layout', 0))
|
||||||
|
|
||||||
def save_settings(self):
|
def apply_saved_settings(self):
|
||||||
"""Save current settings to configuration"""
|
"""Apply loaded settings to UI elements"""
|
||||||
self.config.save_setting('model_dir', self.detector.model_dir)
|
if hasattr(self, 'fps_spin'):
|
||||||
self.config.save_setting('fps', self.fps_spin.value())
|
self.fps_spin.setValue(self.detector.target_fps)
|
||||||
self.config.save_setting('layout', self.layout_combo.currentIndex())
|
|
||||||
|
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):
|
def create_menus(self):
|
||||||
menubar = self.menuBar()
|
menubar = self.menuBar()
|
||||||
@@ -1452,6 +1467,7 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
# Add Camera Selector action
|
# Add Camera Selector action
|
||||||
select_cameras_action = QAction('Select Cameras...', self)
|
select_cameras_action = QAction('Select Cameras...', self)
|
||||||
|
select_cameras_action.setIcon(QIcon.fromTheme('camera-web'))
|
||||||
select_cameras_action.triggered.connect(self.show_camera_selector)
|
select_cameras_action.triggered.connect(self.show_camera_selector)
|
||||||
self.camera_menu.addAction(select_cameras_action)
|
self.camera_menu.addAction(select_cameras_action)
|
||||||
|
|
||||||
@@ -1459,41 +1475,240 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
# Add Network Camera Settings action
|
# Add Network Camera Settings action
|
||||||
network_camera_action = QAction('Network Camera Settings...', self)
|
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)
|
network_camera_action.triggered.connect(self.show_network_camera_dialog)
|
||||||
self.camera_menu.addAction(network_camera_action)
|
self.camera_menu.addAction(network_camera_action)
|
||||||
|
|
||||||
self.camera_menu.addSeparator()
|
self.camera_menu.addSeparator()
|
||||||
|
|
||||||
self.camera_action_group = QActionGroup(self)
|
# Create camera groups
|
||||||
self.camera_action_group.setExclusive(False)
|
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()
|
self.populate_camera_menu()
|
||||||
|
|
||||||
def populate_camera_menu(self):
|
def populate_camera_menu(self):
|
||||||
"""Populate the camera menu with available cameras"""
|
"""Populate the camera menu with available cameras"""
|
||||||
# Clear existing camera actions (except refresh and network camera settings)
|
# Clear existing camera actions
|
||||||
for action in self.camera_menu.actions()[3:]:
|
self.local_camera_menu.clear()
|
||||||
self.camera_menu.removeAction(action)
|
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()
|
available_cams = self.detector.scan_for_cameras()
|
||||||
for cam_path in available_cams:
|
local_cams_found = False
|
||||||
# Display friendly name
|
network_cams_found = False
|
||||||
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)
|
|
||||||
|
|
||||||
if not available_cams:
|
for cam_path in available_cams:
|
||||||
no_cam_action = QAction('No cameras found', self)
|
if cam_path.startswith('net:'):
|
||||||
no_cam_action.setEnabled(False)
|
# Network camera
|
||||||
self.camera_menu.addAction(no_cam_action)
|
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):
|
def load_model_directory(self):
|
||||||
"""Open file dialog to select model directory"""
|
"""Open file dialog to select model directory"""
|
||||||
@@ -1631,12 +1846,6 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
# Start with sidebar expanded
|
# Start with sidebar expanded
|
||||||
self.sidebar.expand()
|
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):
|
def change_camera_layout(self, index):
|
||||||
"""Change the camera display layout"""
|
"""Change the camera display layout"""
|
||||||
@@ -1674,40 +1883,6 @@ class MainWindow(QMainWindow):
|
|||||||
self.timer = QTimer()
|
self.timer = QTimer()
|
||||||
self.timer.timeout.connect(self.update_feeds)
|
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):
|
def stop_detection(self):
|
||||||
"""Stop the detection process"""
|
"""Stop the detection process"""
|
||||||
self.timer.stop()
|
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):
|
def update_feeds(self):
|
||||||
"""Update the camera feeds in the display"""
|
"""Update the camera feeds in the display"""
|
||||||
frames = self.detector.get_frames()
|
frames = self.detector.get_frames()
|
||||||
@@ -1793,30 +1959,6 @@ class MainWindow(QMainWindow):
|
|||||||
dialog.exec_()
|
dialog.exec_()
|
||||||
# Refresh camera list after dialog closes
|
# Refresh camera list after dialog closes
|
||||||
self.populate_camera_menu()
|
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__":
|
if __name__ == "__main__":
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
|
|||||||
Reference in New Issue
Block a user