imgsegclassic.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import sys
  2. import cv2
  3. import numpy as np
  4. from PyQt5.QtWidgets import (
  5. QApplication, QMainWindow, QLabel, QVBoxLayout, QHBoxLayout, QPushButton,
  6. QSlider, QFileDialog, QWidget, QComboBox, QSpinBox
  7. )
  8. from PyQt5.QtCore import Qt
  9. from PyQt5.QtGui import QPixmap, QImage
  10. from skimage.segmentation import active_contour
  11. from scipy import ndimage as ndi
  12. from skimage.filters import threshold_otsu
  13. from skimage.segmentation import watershed
  14. from skimage.feature import peak_local_max
  15. class ImageSegmentationApp(QMainWindow):
  16. def __init__(self):
  17. super().__init__()
  18. self.setWindowTitle("Image Segmentation Explorer")
  19. self.image = None
  20. self.segmented_image = None
  21. self.initUI()
  22. def initUI(self):
  23. # Main layout
  24. main_layout = QVBoxLayout()
  25. # Image display
  26. self.image_label = QLabel()
  27. self.image_label.setAlignment(Qt.AlignCenter)
  28. main_layout.addWidget(self.image_label)
  29. # Controls layout
  30. controls_layout = QHBoxLayout()
  31. # Load image button
  32. load_button = QPushButton("Load Image")
  33. load_button.clicked.connect(self.load_image)
  34. controls_layout.addWidget(load_button)
  35. # Segmentation method selection
  36. self.method_combo = QComboBox()
  37. self.method_combo.addItems([
  38. "Thresholding", "Active Contours", "Region-Based", "Watershed"
  39. ])
  40. self.method_combo.currentIndexChanged.connect(self.update_parameters)
  41. controls_layout.addWidget(self.method_combo)
  42. # Parameter controls
  43. self.param_label = QLabel("Parameter:")
  44. controls_layout.addWidget(self.param_label)
  45. self.param_slider = QSlider(Qt.Horizontal)
  46. self.param_slider.setMinimum(0)
  47. self.param_slider.setMaximum(255)
  48. self.param_slider.setValue(128)
  49. self.param_slider.valueChanged.connect(self.apply_segmentation)
  50. controls_layout.addWidget(self.param_slider)
  51. self.param_spinbox = QSpinBox()
  52. self.param_spinbox.setMinimum(0)
  53. self.param_spinbox.setMaximum(255)
  54. self.param_spinbox.setValue(128)
  55. self.param_spinbox.valueChanged.connect(self.param_slider.setValue)
  56. self.param_slider.valueChanged.connect(self.param_spinbox.setValue)
  57. controls_layout.addWidget(self.param_spinbox)
  58. main_layout.addLayout(controls_layout)
  59. # Apply segmentation button
  60. apply_button = QPushButton("Apply Segmentation")
  61. apply_button.clicked.connect(self.apply_segmentation)
  62. main_layout.addWidget(apply_button)
  63. # Set central widget
  64. container = QWidget()
  65. container.setLayout(main_layout)
  66. self.setCentralWidget(container)
  67. def load_image(self):
  68. options = QFileDialog.Options()
  69. file_name, _ = QFileDialog.getOpenFileName(
  70. self, "Open Image File", "", "Images (*.png *.jpg *.bmp)", options=options
  71. )
  72. if file_name:
  73. self.image = cv2.imread(file_name, cv2.IMREAD_GRAYSCALE)
  74. self.display_image(self.image)
  75. def display_image(self, image):
  76. height, width = image.shape
  77. bytes_per_line = width
  78. q_image = QImage(image.data, width, height, bytes_per_line, QImage.Format_Grayscale8)
  79. pixmap = QPixmap.fromImage(q_image)
  80. self.image_label.setPixmap(pixmap.scaled(
  81. self.image_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation
  82. ))
  83. def update_parameters(self):
  84. method = self.method_combo.currentText()
  85. if method == "Thresholding":
  86. self.param_label.setText("Threshold:")
  87. self.param_slider.setMaximum(255)
  88. self.param_slider.setValue(128)
  89. elif method == "Active Contours":
  90. self.param_label.setText("Iterations:")
  91. self.param_slider.setMaximum(500)
  92. self.param_slider.setValue(100)
  93. elif method == "Region-Based":
  94. self.param_label.setText("Sigma:")
  95. self.param_slider.setMaximum(10)
  96. self.param_slider.setValue(2)
  97. elif method == "Watershed":
  98. self.param_label.setText("Markers:")
  99. self.param_slider.setMaximum(10)
  100. self.param_slider.setValue(2)
  101. def apply_segmentation(self):
  102. if self.image is None:
  103. return
  104. method = self.method_combo.currentText()
  105. param_value = self.param_slider.value()
  106. if method == "Thresholding":
  107. _, self.segmented_image = cv2.threshold(
  108. self.image, param_value, 255, cv2.THRESH_BINARY
  109. )
  110. elif method == "Active Contours":
  111. s = np.linspace(0, 2 * np.pi, 400)
  112. x = 100 + 50 * np.cos(s)
  113. y = 100 + 50 * np.sin(s)
  114. init = np.array([x, y]).T
  115. self.segmented_image = active_contour(
  116. self.image, init, max_iterations=param_value
  117. )
  118. elif method == "Region-Based":
  119. denoised = ndi.gaussian_filter(self.image, sigma=param_value)
  120. self.segmented_image = denoised > threshold_otsu(denoised)
  121. elif method == "Watershed":
  122. distance = ndi.distance_transform_edt(self.image)
  123. local_maxi = peak_local_max(
  124. distance, indices=False, footprint=np.ones((3, 3)), labels=self.image
  125. )
  126. markers, _ = ndi.label(local_maxi)
  127. self.segmented_image = watershed(-distance, markers, mask=self.image)
  128. self.display_image(self.segmented_image.astype(np.uint8) * 255)
  129. if __name__ == "__main__":
  130. app = QApplication(sys.argv)
  131. window = ImageSegmentationApp()
  132. window.show()
  133. sys.exit(app.exec_())