| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- """
- RGB Top View Panel
- Panel for displaying top-down RGB camera view with defect markers and analysis.
- """
- import os
- from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QSizePolicy
- from PyQt5.QtCore import Qt
- from PyQt5.QtGui import QFont, QPixmap, QImage, QPainter, QColor, QPen, QBrush
- from ui.widgets.panel_header import PanelHeader
- class QualityRGBTopPanel(QWidget):
- """
- Panel for RGB top view camera display with defect detection overlays.
- Shows sample fruit image with defect markers and analysis information.
- """
- def __init__(self, parent=None):
- super().__init__(parent)
- self.sample_image = None
- self.defect_markers = []
- self.init_ui()
- def init_ui(self):
- """Initialize the panel UI."""
- # Set size policy to expand equally
- self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
- layout = QVBoxLayout(self)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setSpacing(0)
- # Main panel container with card styling
- self.setStyleSheet("""
- QWidget {
- background-color: white;
- border: 1px solid #ddd;
- }
- """)
- # Header using the PanelHeader widget
- header = PanelHeader(
- title="RGB Top View",
- color="#3498db" # Blue for RGB
- )
- layout.addWidget(header)
- # Content area
- content = QWidget()
- content.setStyleSheet("""
- background-color: #2c3e50;
- border: 1px solid #34495e;
- border-top: none;
- """)
- content_layout = QVBoxLayout(content)
- content_layout.setContentsMargins(10, 10, 10, 10)
- content_layout.setAlignment(Qt.AlignCenter)
- content_layout.setSpacing(5)
- # Create sample fruit image with defects
- self.image_display = SampleFruitWidget()
- self.image_display.setMinimumSize(200, 150)
- content_layout.addWidget(self.image_display)
- # Info labels
- info_widget = QWidget()
- info_layout = QVBoxLayout(info_widget)
- info_layout.setContentsMargins(0, 5, 0, 0)
- info_layout.setSpacing(2)
- # Resolution info (grayed out)
- res_label = QLabel("1920x1080 @ 30fps")
- res_label.setFont(QFont("Arial", 10))
- res_label.setStyleSheet("color: #7f8c8d;")
- res_label.setAlignment(Qt.AlignCenter)
- info_layout.addWidget(res_label)
- # Status info
- status_label = QLabel("🟢 ONLINE (Live Coming Soon)")
- status_label.setFont(QFont("Arial", 9))
- status_label.setStyleSheet("color: #27ae60; font-weight: bold;")
- status_label.setAlignment(Qt.AlignCenter)
- info_layout.addWidget(status_label)
- content_layout.addWidget(info_widget)
- layout.addWidget(content, 1)
- def update_defects(self, defects):
- """Update the defect markers on the image."""
- self.defect_markers = defects
- self.image_display.update_defects(defects)
- self.update()
- def set_image(self, image_path=None):
- """Set the image to display."""
- if image_path and os.path.exists(image_path):
- try:
- pixmap = QPixmap(image_path)
- if not pixmap.isNull():
- # Scale to fit display area
- scaled_pixmap = pixmap.scaled(
- 240, 170, Qt.KeepAspectRatio, Qt.SmoothTransformation
- )
- # Update display (you would need to modify SampleFruitWidget
- # to accept external images in a real implementation)
- self.image_display.update_with_image(scaled_pixmap)
- # Update status
- filename = os.path.basename(image_path)
- self.image_display.setToolTip(f"Loaded: {filename}")
- except Exception as e:
- print(f"Error loading image: {e}")
- else:
- # Show sample data
- self.image_display.update()
- class SampleFruitWidget(QWidget):
- """Widget showing sample fruit with defect markers."""
- def __init__(self, parent=None):
- super().__init__(parent)
- self.defect_markers = []
- self.setAttribute(Qt.WA_StyledBackground, True)
- def update_defects(self, defects):
- """Update defect markers."""
- self.defect_markers = defects
- self.update()
- def paintEvent(self, event):
- """Custom paint event to draw fruit, defects, or external image."""
- painter = QPainter(self)
- painter.setRenderHint(QPainter.Antialiasing)
- # Get widget dimensions
- width = self.width()
- height = self.height()
- # If we have an external image, display it
- if hasattr(self, 'external_pixmap') and self.external_pixmap:
- # Draw the external image scaled to fit
- scaled_pixmap = self.external_pixmap.scaled(
- width, height, Qt.KeepAspectRatio, Qt.SmoothTransformation
- )
- # Center the image
- x = (width - scaled_pixmap.width()) // 2
- y = (height - scaled_pixmap.height()) // 2
- painter.drawPixmap(x, y, scaled_pixmap)
- else:
- # Draw default fruit visualization
- self._draw_fruit_visualization(painter, width, height)
- def _draw_fruit_visualization(self, painter, width, height):
- """Draw the default fruit visualization."""
- center_x = width // 2
- center_y = height // 2
- # Draw background
- painter.fillRect(0, 0, width, height, QColor("#2c3e50"))
- # Draw main fruit (circular shape)
- fruit_radius = min(width, height) // 4
- fruit_rect = (
- center_x - fruit_radius,
- center_y - fruit_radius,
- fruit_radius * 2,
- fruit_radius * 2
- )
- # Fruit body
- fruit_color = QColor("#8B4513") # Brown/orange fruit color
- painter.setBrush(fruit_color)
- painter.setPen(QPen(QColor("#654321"), 2)) # Darker border
- painter.drawEllipse(*fruit_rect)
- # Add some texture/pattern to fruit
- self._add_fruit_texture(painter, center_x, center_y, fruit_radius)
- # Draw defect markers if any
- for i, defect in enumerate(self.defect_markers):
- self._draw_defect_marker(painter, defect, center_x, center_y, fruit_radius)
- # Draw some sample defects for demonstration
- if not self.defect_markers:
- self._draw_sample_defects(painter, center_x, center_y, fruit_radius)
- # Draw locule counting visualization
- self._draw_locule_counting(painter, center_x, center_y, fruit_radius)
- def _add_fruit_texture(self, painter, center_x, center_y, radius):
- """Add texture pattern to fruit."""
- # Add some darker spots for texture
- import math
- for _ in range(5):
- spot_x = center_x + (-radius//2 + hash(str(_)) % radius)
- spot_y = center_y + (-radius//2 + hash(str(_*2)) % radius)
- spot_radius = 3
- # Only draw if within fruit bounds
- distance = math.sqrt((spot_x - center_x) ** 2 + (spot_y - center_y) ** 2)
- if distance + spot_radius <= radius:
- painter.setBrush(QBrush(QColor("#654321")))
- painter.setPen(Qt.NoPen)
- painter.drawEllipse(spot_x - spot_radius, spot_y - spot_radius,
- spot_radius * 2, spot_radius * 2)
- def _draw_defect_marker(self, painter, defect, center_x, center_y, fruit_radius):
- """Draw a single defect marker."""
- # Position relative to fruit center
- marker_x = center_x + (defect['x'] * fruit_radius // 50)
- marker_y = center_y + (defect['y'] * fruit_radius // 50)
- # Draw marker circle
- marker_radius = max(8, defect.get('size', 8))
- painter.setBrush(QBrush(QColor(defect.get('color', '#f39c12'))))
- painter.setPen(QPen(QColor('#e67e22'), 2))
- painter.drawEllipse(marker_x - marker_radius, marker_y - marker_radius,
- marker_radius * 2, marker_radius * 2)
- # Draw confidence text if available
- confidence = defect.get('confidence', 0)
- if confidence > 0:
- painter.setPen(QPen(QColor('white'), 1))
- painter.drawText(marker_x - 20, marker_y - marker_radius - 5,
- f"{confidence:.1f}%")
- def _draw_sample_defects(self, painter, center_x, center_y, fruit_radius):
- """Draw sample defects for demonstration."""
- sample_defects = [
- {'x': -20, 'y': -15, 'color': '#f39c12', 'confidence': 87.3, 'size': 8},
- {'x': 25, 'y': 30, 'color': '#f39c12', 'confidence': 72.8, 'size': 6},
- ]
- for defect in sample_defects:
- self._draw_defect_marker(painter, defect, center_x, center_y, fruit_radius)
- def _draw_locule_counting(self, painter, center_x, center_y, fruit_radius):
- """Draw locule counting visualization."""
- # Draw locule segments (colored regions within the fruit)
- locule_colors = ["#3498db", "#e74c3c", "#2ecc71", "#f39c12", "#9b59b6"]
- # Draw 4 sample locules (colored pie segments)
- num_locules = 4
- angle_step = 360 / num_locules
- for i in range(num_locules):
- start_angle = int(i * angle_step)
- span_angle = int(angle_step)
- # Create pie segment path
- painter.setBrush(QBrush(QColor(locule_colors[i % len(locule_colors)])))
- painter.setPen(QPen(QColor("#34495e"), 2))
- painter.drawPie(
- center_x - fruit_radius, center_y - fruit_radius,
- fruit_radius * 2, fruit_radius * 2,
- start_angle * 16, span_angle * 16 # Qt uses 1/16th degree units
- )
- def update(self):
- """Override update to ensure repaint."""
- super().update()
- self.repaint()
- def update_with_image(self, pixmap):
- """Update display with external image."""
- self.external_pixmap = pixmap
- self.has_external_image = True
- self.update()
|