| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- """
- Quality Sample Data Generator
- Utility for generating sample data and images for quality tab demonstration.
- """
- import numpy as np
- from PyQt5.QtGui import QPixmap, QImage, QColor, QPainter, QPen, QBrush
- from PyQt5.QtCore import Qt, QPoint, QRect
- import random
- import math
- class QualitySampleDataGenerator:
- """Generator for sample quality assessment data."""
- def __init__(self):
- self.fruit_colors = [
- QColor("#8B4513"), # Brown/orange
- QColor("#CD853F"), # Peru
- QColor("#DEB887"), # Burlywood
- QColor("#F4A460"), # Sandy brown
- ]
- self.defect_colors = [
- QColor("#F39C12"), # Orange for mechanical damage
- QColor("#E67E22"), # Carrot for surface blemish
- QColor("#E74C3C"), # Red for severe defects
- ]
- def generate_sample_fruit_top_view(self, width=300, height=250):
- """Generate a sample top view fruit image with defects."""
- image = QImage(width, height, QImage.Format_RGB32)
- image.fill(QColor("#2C3E50"))
- painter = QPainter(image)
- painter.setRenderHint(QPainter.Antialiasing)
- # Draw main fruit
- fruit_radius = min(width, height) // 4
- center_x = width // 2
- center_y = height // 2
- # Fruit body with gradient
- fruit_color = random.choice(self.fruit_colors)
- painter.setBrush(QBrush(fruit_color))
- painter.setPen(QPen(QColor("#654321"), 2))
- painter.drawEllipse(center_x - fruit_radius, center_y - fruit_radius,
- fruit_radius * 2, fruit_radius * 2)
- # Add some texture/pattern to fruit
- self._add_fruit_texture(painter, center_x, center_y, fruit_radius)
- # Add defect markers
- defects = self._generate_sample_defects()
- for defect in defects:
- self._draw_defect_on_fruit(painter, defect, center_x, center_y, fruit_radius)
- painter.end()
- return image, defects
- def generate_sample_fruit_side_view(self, width=300, height=200):
- """Generate a sample side view fruit image with shape outline."""
- image = QImage(width, height, QImage.Format_RGB32)
- image.fill(QColor("#2C3E50"))
- painter = QPainter(image)
- painter.setRenderHint(QPainter.Antialiasing)
- # Draw main fruit (elliptical for side view)
- fruit_width = width * 3 // 5
- fruit_height = fruit_width * 3 // 4
- center_x = width // 2
- center_y = height // 2
- # Fruit body
- fruit_color = random.choice(self.fruit_colors)
- painter.setBrush(QBrush(fruit_color))
- painter.setPen(QPen(QColor("#654321"), 2))
- painter.drawEllipse(center_x - fruit_width // 2, center_y - fruit_height // 2,
- fruit_width, fruit_height)
- # Draw shape outline (dashed)
- painter.setBrush(Qt.NoBrush)
- painter.setPen(QPen(QColor("#27AE60"), 2, Qt.DashLine))
- painter.drawEllipse(center_x - fruit_width // 2, center_y - fruit_height // 2,
- fruit_width, fruit_height)
- # Draw symmetry indicators
- self._draw_symmetry_indicators(painter, center_x, center_y, fruit_width)
- painter.end()
- # Generate shape analysis data
- symmetry = random.uniform(85, 95)
- aspect_ratio = fruit_width / fruit_height
- return image, symmetry, aspect_ratio
- def generate_thermal_gradient(self, width=300, height=200, base_temp=28.5):
- """Generate thermal gradient visualization."""
- image = QImage(width, height, QImage.Format_RGB32)
- image.fill(QColor("#000000"))
- painter = QPainter(image)
- painter.setRenderHint(QPainter.Antialiasing)
- # Create thermal gradient background
- center_x = width // 2
- center_y = height // 2
- # Main thermal area (elliptical)
- thermal_width = width * 3 // 4
- thermal_height = height * 2 // 3
- # Create radial gradient for thermal effect
- radial_gradient = QRadialGradient(center_x, center_y, max(thermal_width, thermal_height) // 2)
- # Center is hottest (red), edges cooler
- radial_gradient.setColorAt(0.0, QColor("#E74C3C")) # Hot center
- radial_gradient.setColorAt(0.7, QColor("#F39C12")) # Medium
- radial_gradient.setColorAt(1.0, QColor("#F1C40F")) # Cool edges
- painter.setBrush(QBrush(radial_gradient))
- painter.setPen(Qt.NoPen)
- painter.drawEllipse(center_x - thermal_width // 2, center_y - thermal_height // 2,
- thermal_width, thermal_height)
- # Add temperature scale overlay
- self._add_temperature_scale(painter, width, height, base_temp)
- painter.end()
- return image, base_temp
- def generate_quality_grading_data(self):
- """Generate sample quality grading data."""
- # Simulate quality metrics
- metrics = {
- "size_weight": random.uniform(85, 95),
- "shape_regularity": random.uniform(87, 94),
- "surface_quality": random.uniform(65, 80),
- "color_uniformity": random.uniform(78, 88),
- "firmness_thermal": 0 # Not available (thermal offline)
- }
- # Calculate overall score
- available_metrics = [v for k, v in metrics.items() if v > 0]
- overall_score = sum(available_metrics) / len(available_metrics)
- # Determine grade
- if overall_score >= 90:
- grade = "A"
- elif overall_score >= 75:
- grade = "B"
- else:
- grade = "C"
- # Generate additional metrics
- additional_metrics = {
- "estimated_weight": round(random.uniform(150, 220), 1),
- "diameter": random.randint(65, 80),
- "aspect_ratio": round(random.uniform(0.8, 0.9), 2),
- "surface_defect_coverage": round(random.uniform(2, 8), 1),
- "processing_time": round(random.uniform(2.0, 3.5), 1)
- }
- return {
- "grade": grade,
- "overall_score": round(overall_score, 1),
- "metrics": metrics,
- "additional_metrics": additional_metrics,
- "model_version": "QualityNet v2.8"
- }
- def _generate_sample_defects(self):
- """Generate sample defect data."""
- defects = []
- # Mechanical damage
- defects.append({
- 'type': 'Mechanical Damage',
- 'x': random.randint(-20, 20),
- 'y': random.randint(-20, 20),
- 'size': random.randint(6, 12),
- 'confidence': round(random.uniform(80, 95), 1),
- 'color': '#F39C12',
- 'location': 'Top-Left',
- 'size_mm2': round(random.uniform(6, 12), 1)
- })
- # Surface blemish (sometimes)
- if random.random() > 0.5:
- defects.append({
- 'type': 'Surface Blemish',
- 'x': random.randint(-15, 25),
- 'y': random.randint(-10, 25),
- 'size': random.randint(4, 8),
- 'confidence': round(random.uniform(70, 85), 1),
- 'color': '#E67E22',
- 'location': 'Side',
- 'size_mm2': round(random.uniform(3, 7), 1)
- })
- return defects
- def _add_fruit_texture(self, painter, center_x, center_y, radius):
- """Add texture pattern to fruit."""
- # Add some darker spots for texture
- for _ in range(5):
- spot_x = center_x + random.randint(-radius // 2, radius // 2)
- spot_y = center_y + random.randint(-radius // 2, radius // 2)
- spot_radius = random.randint(3, 8)
- # 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_on_fruit(self, painter, defect, center_x, center_y, fruit_radius):
- """Draw a defect marker on the fruit."""
- # Calculate 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(6, defect['size'])
- painter.setBrush(QBrush(QColor(defect['color'])))
- painter.setPen(QPen(QColor('#D35400'), 2))
- painter.drawEllipse(marker_x - marker_radius, marker_y - marker_radius,
- marker_radius * 2, marker_radius * 2)
- # Draw confidence text
- painter.setPen(QPen(QColor('white'), 1))
- painter.drawText(marker_x - 15, marker_y - marker_radius - 3,
- f"{defect['confidence']}%")
- def _draw_symmetry_indicators(self, painter, center_x, center_y, fruit_width):
- """Draw symmetry indicator lines."""
- # Draw symmetry axis lines
- symmetry_y = center_y
- line_length = fruit_width // 6
- painter.setPen(QPen(QColor("#3498DB"), 2, Qt.SolidLine))
- # Left indicator
- left_x = center_x - fruit_width // 4
- painter.drawLine(left_x, symmetry_y - line_length, left_x, symmetry_y + line_length)
- # Right indicator
- right_x = center_x + fruit_width // 4
- painter.drawLine(right_x, symmetry_y - line_length, right_x, symmetry_y + line_length)
- def _add_temperature_scale(self, painter, width, height, base_temp):
- """Add temperature scale overlay."""
- # Temperature scale at bottom
- scale_width = width * 3 // 4
- scale_height = 15
- scale_x = (width - scale_width) // 2
- scale_y = height - 30
- # Draw scale background
- painter.setBrush(QBrush(QColor("#34495E")))
- painter.setPen(Qt.NoPen)
- painter.drawRect(scale_x, scale_y, scale_width, scale_height)
- # Draw temperature gradient in scale
- temp_gradient = QBrush()
- temp_gradient = QLinearGradient(scale_x, 0, scale_x + scale_width, 0)
- temp_gradient.setColorAt(0.0, QColor("#3498DB")) # Cool (22°C)
- temp_gradient.setColorAt(0.25, QColor("#27AE60"))
- temp_gradient.setColorAt(0.5, QColor("#F1C40F"))
- temp_gradient.setColorAt(0.75, QColor("#E67E22"))
- temp_gradient.setColorAt(1.0, QColor("#E74C3C")) # Hot (32°C)
- painter.setBrush(temp_gradient)
- painter.drawRect(scale_x, scale_y, scale_width, scale_height)
- # Draw scale border
- painter.setPen(QPen(QColor("#ECF0F1"), 1))
- painter.drawRect(scale_x, scale_y, scale_width, scale_height)
- # Draw temperature labels
- painter.setPen(QPen(QColor("white"), 1))
- min_temp = "22°C"
- max_temp = "32°C"
- current_temp = f"{base_temp}°C"
- # Min temperature
- painter.drawText(scale_x + 5, scale_y - 2, min_temp)
- # Current temperature (centered)
- current_rect = QRect(scale_x + scale_width // 2 - 20, scale_y - 18, 40, 15)
- painter.drawText(current_rect, Qt.AlignCenter, current_temp)
- # Max temperature
- max_temp_rect = QRect(scale_x + scale_width - 35, scale_y - 2, 30, 12)
- painter.drawText(max_temp_rect, Qt.AlignRight, max_temp)
- # Global instance for easy access
- sample_data_generator = QualitySampleDataGenerator()
- def get_sample_fruit_top_view():
- """Get a sample top view image and defects data."""
- return sample_data_generator.generate_sample_fruit_top_view()
- def get_sample_fruit_side_view():
- """Get a sample side view image and analysis data."""
- return sample_data_generator.generate_sample_fruit_side_view()
- def get_thermal_gradient():
- """Get a thermal gradient visualization."""
- return sample_data_generator.generate_thermal_gradient()
- def get_quality_grading_data():
- """Get sample quality grading data."""
- return sample_data_generator.generate_quality_grading_data()
- def generate_defect_detection_results():
- """Generate sample defect detection results."""
- defects = sample_data_generator._generate_sample_defects()
- # Convert to format expected by panels
- formatted_defects = []
- for defect in defects:
- formatted_defects.append({
- 'type': defect['type'],
- 'location': defect['location'],
- 'size': f"{defect['size_mm2']}mm²",
- 'confidence': defect['confidence'],
- 'color': defect['color'],
- 'category': 'warning'
- })
- # Add shape analysis
- formatted_defects.append({
- 'type': 'Shape Analysis',
- 'result': 'Regular',
- 'symmetry': '91.2%',
- 'confidence': 94.1,
- 'color': '#27ae60',
- 'category': 'success'
- })
- # Add locule count
- formatted_defects.append({
- 'type': 'Locule Count',
- 'count': '4',
- 'confidence': 94.5,
- 'color': '#3498db',
- 'category': 'info'
- })
- return formatted_defects
|