maturity_worker.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. """
  2. Maturity Worker Module
  3. Worker thread for async multispectral maturity classification processing.
  4. """
  5. from typing import Optional
  6. import logging
  7. from PyQt5.QtCore import pyqtSignal
  8. from PyQt5.QtGui import QImage, QPixmap
  9. from workers.base_worker import BaseWorker, WorkerSignals
  10. from models.maturity_model import MaturityModel
  11. logger = logging.getLogger(__name__)
  12. class MaturityWorkerSignals(WorkerSignals):
  13. """
  14. Signals specific to maturity processing.
  15. Signals:
  16. result_ready: Emitted when prediction is complete
  17. (gradcam_image: QImage, class_name: str, confidence: float,
  18. probabilities: dict)
  19. """
  20. result_ready = pyqtSignal(QImage, str, float, dict)
  21. class MaturityWorker(BaseWorker):
  22. """
  23. Worker for processing multispectral TIFF files and predicting maturity.
  24. Runs MaturityModel inference in a background thread without blocking UI.
  25. Supports 8-band multispectral TIFF images.
  26. Attributes:
  27. tif_path: Path to multispectral TIFF file
  28. model: MaturityModel instance
  29. signals: MaturityWorkerSignals for emitting results
  30. """
  31. def __init__(self, tif_path: str, model: Optional[MaturityModel] = None):
  32. """
  33. Initialize the maturity worker.
  34. Args:
  35. tif_path: Path to multispectral TIFF file to process
  36. model: MaturityModel instance (if None, creates new one)
  37. """
  38. super().__init__()
  39. self.tif_path = tif_path
  40. self.model = model
  41. # Replace base signals with maturity-specific signals
  42. self.signals = MaturityWorkerSignals()
  43. # If no model provided, create and load one
  44. if self.model is None:
  45. from utils.config import get_device
  46. self.model = MaturityModel(device=get_device())
  47. self.model.load()
  48. logger.info(f"MaturityWorker created for: {tif_path}")
  49. def process(self):
  50. """
  51. Process the multispectral TIFF file and predict maturity.
  52. Emits result_ready signal with prediction results.
  53. """
  54. if self.is_cancelled():
  55. logger.info("MaturityWorker cancelled before processing")
  56. return
  57. # Update progress
  58. self.emit_progress(10, "Loading multispectral image...")
  59. if not self.model.is_loaded:
  60. logger.warning("Model not loaded, loading now...")
  61. self.emit_progress(30, "Loading model...")
  62. if not self.model.load():
  63. raise RuntimeError("Failed to load maturity model")
  64. # Process TIFF
  65. self.emit_progress(50, "Preprocessing multispectral data...")
  66. result = self.model.predict(self.tif_path)
  67. if self.is_cancelled():
  68. logger.info("MaturityWorker cancelled during processing")
  69. return
  70. if not result['success']:
  71. raise RuntimeError(result['error'])
  72. self.emit_progress(70, "Generating Grad-CAM visualization...")
  73. # Generate Grad-CAM visualization
  74. gradcam_image, pred_name = self.model.run_gradcam(self.tif_path)
  75. if self.is_cancelled():
  76. logger.info("MaturityWorker cancelled during Grad-CAM generation")
  77. return
  78. if gradcam_image is None:
  79. # Create a placeholder pixmap for None Grad-CAM
  80. gradcam_image = QImage(256, 256, QImage.Format_RGB888)
  81. gradcam_image.fill(0x2c3e50) # Dark gray background
  82. self.emit_progress(90, "Finalizing results...")
  83. # Emit results
  84. self.signals.result_ready.emit(
  85. gradcam_image,
  86. result['prediction'],
  87. result['confidence'],
  88. result['probabilities']
  89. )
  90. self.emit_progress(100, "Complete!")
  91. logger.info(f"MaturityWorker completed: {result['prediction']} ({result['confidence']:.2%})")