Commit eeaa9d71 authored by JosefBrandt's avatar JosefBrandt

DownScaling of too large connectedComponents, Progressbar

A new parameter allows setting a maximum size of connected Components. Larger components are scaled down accordingly to avoid MemoryErrors.

A progress bar is implemented for visualizing the detection progress.
The progress bar is put in a dedicated class (in uielements.py) and it is now also used by opticalscan and ramanscanui.
parent 690e2849
...@@ -27,6 +27,7 @@ from threading import Thread ...@@ -27,6 +27,7 @@ from threading import Thread
from .segmentation import Segmentation from .segmentation import Segmentation
from .analysis.particleCharacterization import getParticleStatsWithPixelScale, loadZValImageFromDataset from .analysis.particleCharacterization import getParticleStatsWithPixelScale, loadZValImageFromDataset
from .errors import InvalidParticleError from .errors import InvalidParticleError
from .uielements import TimeEstimateProgressbar
Nscreen = 1000 Nscreen = 1000
...@@ -288,6 +289,7 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -288,6 +289,7 @@ class ParticleDetectionView(QtWidgets.QWidget):
self.img = img self.img = img
self.imgclip = 0,0,0,0 self.imgclip = 0,0,0,0
self.seg = Segmentation(self.dataset, self) self.seg = Segmentation(self.dataset, self)
self.seg.detectionState.connect(self.updateDetectionState)
self.thread = None self.thread = None
self.view = parent self.view = parent
...@@ -417,6 +419,9 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -417,6 +419,9 @@ class ParticleDetectionView(QtWidgets.QWidget):
self.autoUpdateCheckBox.setMaximumWidth(200) self.autoUpdateCheckBox.setMaximumWidth(200)
self.autoUpdateCheckBox.setChecked(True) self.autoUpdateCheckBox.setChecked(True)
vbox.addWidget(self.autoUpdateCheckBox) vbox.addWidget(self.autoUpdateCheckBox)
self.progressbar = TimeEstimateProgressbar()
vbox.addWidget(self.progressbar)
hbox2 = QtWidgets.QHBoxLayout() hbox2 = QtWidgets.QHBoxLayout()
self.pdetectsub = QtWidgets.QPushButton("Detect", self) self.pdetectsub = QtWidgets.QPushButton("Detect", self)
...@@ -642,6 +647,10 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -642,6 +647,10 @@ class ParticleDetectionView(QtWidgets.QWidget):
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def detectParticles(self): def detectParticles(self):
"""
Detect all particles
:return:
"""
self.saveDetectParams(self.dataset) self.saveDetectParams(self.dataset)
if self.thread is not None and self.thread.is_alive(): if self.thread is not None and self.thread.is_alive():
self.cancelThread() self.cancelThread()
...@@ -661,6 +670,7 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -661,6 +670,7 @@ class ParticleDetectionView(QtWidgets.QWidget):
if self.thread is not None: if self.thread is not None:
if not self.threadrunning: if not self.threadrunning:
self.thread = None self.thread = None
self.progressbar.disable()
self.unBlockUI() self.unBlockUI()
self.pdetectall.setText("Detect all") self.pdetectall.setText("Detect all")
self.imageUpdate.emit(self.view.microscopeMode) self.imageUpdate.emit(self.view.microscopeMode)
...@@ -670,6 +680,25 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -670,6 +680,25 @@ class ParticleDetectionView(QtWidgets.QWidget):
self.setWindowTitle(f'{numParticles} Particles ({numMeasurements} Measurements)') self.setWindowTitle(f'{numParticles} Particles ({numMeasurements} Measurements)')
else: else:
self.timer.start(100.) self.timer.start(100.)
@QtCore.pyqtSlot(str)
def updateDetectionState(self, message):
"""
Updates the progressbar and its text-label to the current state of the detection
:return:
"""
if message.find('DO') == -1:
self.progressbar.setMessage(message)
else:
if message.find('setup') != -1:
self.progressbar.resetTimerAndCounter()
self.progressbar.enable()
elif message.find('maxVal') != -1:
maxVal = int(message.split('=')[-1])
self.progressbar.setMaxValue(maxVal)
elif message.find('newVal') != -1:
newVal = int(message.split('=')[-1])
self.progressbar.setValue(newVal)
def _worker(self): def _worker(self):
kwargs = {} kwargs = {}
...@@ -681,8 +710,9 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -681,8 +710,9 @@ class ParticleDetectionView(QtWidgets.QWidget):
kwargs[name] = valuefunc() kwargs[name] = valuefunc()
seedradius = self.seedradiusedit.value() seedradius = self.seedradiusedit.value()
self.seg.setParameters(**kwargs) self.seg.setParameters(**kwargs)
measurementPoints, contours= self.seg.apply2Image(self.img, seedpoints, deletepoints, seedradius, self.dataset) measurementPoints, contours= self.seg.apply2Image(self.img, seedpoints, deletepoints, seedradius, self.dataset)
if measurementPoints is None: # computation was canceled if measurementPoints is None: # computation was canceled
return return
......
...@@ -28,9 +28,9 @@ import os ...@@ -28,9 +28,9 @@ import os
import cv2 import cv2
from .helperfunctions import cv2imread_fix, cv2imwrite_fix from .helperfunctions import cv2imread_fix, cv2imwrite_fix
from time import time from time import time
import datetime
import sys import sys
from .opticalbackground import BackGroundManager from .opticalbackground import BackGroundManager
from .uielements import TimeEstimateProgressbar
def scan(path, sol, zpositions, grid, controlclass, dataqueue, def scan(path, sol, zpositions, grid, controlclass, dataqueue,
stopevent, logpath='', ishdr=False): stopevent, logpath='', ishdr=False):
...@@ -289,11 +289,8 @@ class OpticalScan(QtWidgets.QWidget): ...@@ -289,11 +289,8 @@ class OpticalScan(QtWidgets.QWidget):
self.pexit.released.connect(self.stopScan) self.pexit.released.connect(self.stopScan)
self.prun.setEnabled(False) self.prun.setEnabled(False)
self.timelabeltext = "Estimated time to finish: " self.progressbar = TimeEstimateProgressbar()
self.progressbar = QtWidgets.QProgressBar(self) self.progressbar.disable()
self.progresstime = QtWidgets.QLabel(self.timelabeltext, self)
self.progresstime.setEnabled(False)
self.progressbar.setEnabled(False)
radioGroup = QtWidgets.QGroupBox('Shape') radioGroup = QtWidgets.QGroupBox('Shape')
radioLayout = QtWidgets.QHBoxLayout() radioLayout = QtWidgets.QHBoxLayout()
...@@ -349,7 +346,6 @@ class OpticalScan(QtWidgets.QWidget): ...@@ -349,7 +346,6 @@ class OpticalScan(QtWidgets.QWidget):
vbox.addWidget(self.areaOptionsGroup) vbox.addWidget(self.areaOptionsGroup)
vbox.addWidget(furtherOptionsGroup) vbox.addWidget(furtherOptionsGroup)
vbox.addLayout(btnLayout) vbox.addLayout(btnLayout)
vbox.addWidget(self.progresstime)
vbox.addWidget(self.progressbar) vbox.addWidget(self.progressbar)
self.setLayout(vbox) self.setLayout(vbox)
...@@ -382,6 +378,7 @@ class OpticalScan(QtWidgets.QWidget): ...@@ -382,6 +378,7 @@ class OpticalScan(QtWidgets.QWidget):
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.Yes |
QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No) QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes: if reply == QtWidgets.QMessageBox.Yes:
self.progressbar.resetTimerAndCounter()
self.timer.stop() self.timer.stop()
self.processstopevent.set() self.processstopevent.set()
self.process.join() self.process.join()
...@@ -603,11 +600,9 @@ class OpticalScan(QtWidgets.QWidget): ...@@ -603,11 +600,9 @@ class OpticalScan(QtWidgets.QWidget):
self.dataqueue, self.processstopevent, self.dataqueue, self.processstopevent,
self.logpath, self.hdrcheck.isChecked())) self.logpath, self.hdrcheck.isChecked()))
self.process.start() self.process.start()
self.starttime = time() self.progressbar.enable()
self.progresstime.setEnabled(True) self.progressbar.resetTimerAndCounter()
self.progressbar.setEnabled(True) self.progressbar.setMaxValue(len(self.dataset.grid))
self.progressbar.setRange(0, len(self.dataset.grid))
self.progressbar.setValue(0)
self.view.imgdata = None self.view.imgdata = None
self.view.blockUI() self.view.blockUI()
grid = np.asarray(self.dataset.grid) grid = np.asarray(self.dataset.grid)
...@@ -647,11 +642,6 @@ class OpticalScan(QtWidgets.QWidget): ...@@ -647,11 +642,6 @@ class OpticalScan(QtWidgets.QWidget):
self.view.imgdata, self.dataset.zvalimg = loadAndPasteImage(names, self.view.imgdata, self.dataset.zvalimg, width, height, self.view.imgdata, self.dataset.zvalimg = loadAndPasteImage(names, self.view.imgdata, self.dataset.zvalimg, width, height,
rotationvalue, p0, p1, p, background=background_img) rotationvalue, p0, p1, p, background=background_img)
self.progressbar.setValue(i+1) self.progressbar.setValue(i+1)
if i>3:
timerunning = time()-self.starttime
ttot = timerunning*Ngrid/(i+1)
time2go = ttot - timerunning
self.progresstime.setText(self.timelabeltext + str(datetime.timedelta(seconds=round(time2go))))
self.imageUpdate.emit(self.view.microscopeMode) self.imageUpdate.emit(self.view.microscopeMode)
if i==Ngrid-1: if i==Ngrid-1:
...@@ -672,9 +662,8 @@ class OpticalScan(QtWidgets.QWidget): ...@@ -672,9 +662,8 @@ class OpticalScan(QtWidgets.QWidget):
self.view.saveDataSet() self.view.saveDataSet()
self.view.unblockUI() self.view.unblockUI()
self.view.switchMode("ParticleDetection") self.view.switchMode("ParticleDetection")
self.progressbar.setValue(0) self.progressbar.resetTimerAndCounter()
self.progressbar.setEnabled(False) self.progressbar.disable()
self.progresstime.setEnabled(False)
self.close() self.close()
return return
self.timer.start(100.) self.timer.start(100.)
......
...@@ -24,10 +24,10 @@ import numpy as np ...@@ -24,10 +24,10 @@ import numpy as np
from multiprocessing import Process, Queue, Event from multiprocessing import Process, Queue, Event
import queue import queue
from time import time from time import time
from .external import tsp
import datetime
import sys import sys
import os import os
from .external import tsp
from .uielements import TimeEstimateProgressbar
def reorder(points, N=20): def reorder(points, N=20):
y0, y1 = points[:,1].min(), points[:,1].max() y0, y1 = points[:,1].min(), points[:,1].max()
...@@ -129,18 +129,15 @@ class RamanScanUI(QtWidgets.QWidget): ...@@ -129,18 +129,15 @@ class RamanScanUI(QtWidgets.QWidget):
self.pexit = QtWidgets.QPushButton("Cancel", self) self.pexit = QtWidgets.QPushButton("Cancel", self)
self.pexit.released.connect(self.stopScan) self.pexit.released.connect(self.stopScan)
self.prun.setEnabled(False) self.prun.setEnabled(False)
self.progressbar = QtWidgets.QProgressBar(self)
self.timelabeltext = "Estimated time to finish: " self.progressbar = TimeEstimateProgressbar()
self.progresstime = QtWidgets.QLabel(self.timelabeltext, self) self.progressbar.disable()
self.progresstime.setEnabled(False)
self.progressbar.setEnabled(False)
hbox.addStretch() hbox.addStretch()
hbox.addWidget(self.pexit) hbox.addWidget(self.pexit)
vbox.addWidget(self.group2) vbox.addWidget(self.group2)
vbox.addLayout(hbox) vbox.addLayout(hbox)
vbox.addWidget(self.progresstime)
vbox.addWidget(self.progressbar) vbox.addWidget(self.progressbar)
self.setLayout(vbox) self.setLayout(vbox)
...@@ -173,6 +170,7 @@ class RamanScanUI(QtWidgets.QWidget): ...@@ -173,6 +170,7 @@ class RamanScanUI(QtWidgets.QWidget):
if reply == QtWidgets.QMessageBox.Yes: if reply == QtWidgets.QMessageBox.Yes:
self.ramanctrl.finishMeasurement() self.ramanctrl.finishMeasurement()
self.timer.stop() self.timer.stop()
self.progressbar.resetTimerAndCounter()
self.processstopevent.set() self.processstopevent.set()
self.process.join() self.process.join()
self.dataqueue.close() self.dataqueue.close()
...@@ -248,10 +246,9 @@ class RamanScanUI(QtWidgets.QWidget): ...@@ -248,10 +246,9 @@ class RamanScanUI(QtWidgets.QWidget):
self.view.highLightRamanIndex(0) self.view.highLightRamanIndex(0)
self.view.blockUI() self.view.blockUI()
self.group2.setEnabled(False) self.group2.setEnabled(False)
self.progresstime.setEnabled(True) self.progressbar.enable()
self.progressbar.setEnabled(True) self.progressbar.resetTimerAndCounter()
self.progressbar.setRange(0, len(scanpoints)) self.progressbar.setMaxValue(len(scanpoints))
self.progressbar.setValue(0)
self.ramanctrl.disconnect() self.ramanctrl.disconnect()
self.processstopevent = Event() self.processstopevent = Event()
self.dataqueue = Queue() self.dataqueue = Queue()
...@@ -279,11 +276,6 @@ class RamanScanUI(QtWidgets.QWidget): ...@@ -279,11 +276,6 @@ class RamanScanUI(QtWidgets.QWidget):
self.view.highLightRamanIndex(i+1) #go to next scanmarker self.view.highLightRamanIndex(i+1) #go to next scanmarker
Npoints = len(self.dataset.particleContainer.getMeasurementPixelCoords()) Npoints = len(self.dataset.particleContainer.getMeasurementPixelCoords())
if i>3:
timerunning = time()-self.starttime
ttot = timerunning*Npoints/(i+1)
time2go = ttot - timerunning
self.progresstime.setText(self.timelabeltext + str(datetime.timedelta(seconds=round(time2go))))
if i==Npoints-1: if i==Npoints-1:
self.process.join() self.process.join()
self.dataqueue.close() self.dataqueue.close()
...@@ -291,9 +283,8 @@ class RamanScanUI(QtWidgets.QWidget): ...@@ -291,9 +283,8 @@ class RamanScanUI(QtWidgets.QWidget):
self.dataset.ramanscandone = True self.dataset.ramanscandone = True
self.view.saveDataSet() self.view.saveDataSet()
self.view.unblockUI() self.view.unblockUI()
self.progressbar.setValue(0) self.progressbar.resetTimerAndCounter()
self.progressbar.setEnabled(False) self.progressbar.disable()
self.progresstime.setEnabled(False)
self.close() self.close()
return return
self.timer.start(100.) self.timer.start(100.)
......
...@@ -28,6 +28,8 @@ from skimage.feature import peak_local_max ...@@ -28,6 +28,8 @@ from skimage.feature import peak_local_max
from skimage.morphology import watershed from skimage.morphology import watershed
import skfuzzy as fuzz import skfuzzy as fuzz
import random import random
from PyQt5 import QtCore
def closeHolesOfSubImage(subimg): def closeHolesOfSubImage(subimg):
subimg = cv2.copyMakeBorder(subimg, 1, 1, 1, 1, 0) subimg = cv2.copyMakeBorder(subimg, 1, 1, 1, 1, 0)
...@@ -63,8 +65,10 @@ class MeasurementPoint(object): ...@@ -63,8 +65,10 @@ class MeasurementPoint(object):
self.x = x self.x = x
self.y = y self.y = y
class Segmentation(object): class Segmentation(QtCore.QObject):
def __init__(self, dataset=None, parent=None): detectionState = QtCore.pyqtSignal(str)
def __init__(self, dataset=None, parent=None):
super(Segmentation, self).__init__()
self.cancelcomputation = False self.cancelcomputation = False
self.parent = parent self.parent = parent
self.defaultParams = {'adaptiveHistEqu': False, self.defaultParams = {'adaptiveHistEqu': False,
...@@ -84,6 +88,7 @@ class Segmentation(object): ...@@ -84,6 +88,7 @@ class Segmentation(object):
'minparticledistance': 20, 'minparticledistance': 20,
'closeBackground': False, 'closeBackground': False,
'fuzzycluster': False, 'fuzzycluster': False,
'maxComponentSize': 20000,
'measurefrac': 1, 'measurefrac': 1,
'compactness': 0.0, 'compactness': 0.0,
'seedRad': 3} 'seedRad': 3}
...@@ -115,6 +120,7 @@ class Segmentation(object): ...@@ -115,6 +120,7 @@ class Segmentation(object):
Parameter("measurefrac", float, self.detectParams['measurefrac'], 0, 1, 2, stepsize = 0.05, helptext="measure fraction of particles", show=False), Parameter("measurefrac", float, self.detectParams['measurefrac'], 0, 1, 2, stepsize = 0.05, helptext="measure fraction of particles", show=False),
Parameter("closeBackground", np.bool, self.detectParams['closeBackground'], helptext="close holes in sure background", show=False), Parameter("closeBackground", np.bool, self.detectParams['closeBackground'], helptext="close holes in sure background", show=False),
Parameter("fuzzycluster", np.bool, self.detectParams['fuzzycluster'], helptext='Enable Fuzzy Clustering', show=False), Parameter("fuzzycluster", np.bool, self.detectParams['fuzzycluster'], helptext='Enable Fuzzy Clustering', show=False),
Parameter("maxComponentSize", int, self.detectParams['maxComponentSize'], 100, 1E6, 0, 100, helptext='Maximum size in x or y of connected component.\nLarger components are scaled down accordingly', show=False),
Parameter("sure_fg", None, helptext="Show sure foreground", show=True), Parameter("sure_fg", None, helptext="Show sure foreground", show=True),
Parameter("compactness", float, self.detectParams['compactness'], 0, 1, 2, 0.05, helptext="watershed compactness", show=False), Parameter("compactness", float, self.detectParams['compactness'], 0, 1, 2, 0.05, helptext="watershed compactness", show=False),
Parameter("watershed", None, helptext="Show watershed markers", show=True), Parameter("watershed", None, helptext="Show watershed markers", show=True),
...@@ -140,8 +146,10 @@ class Segmentation(object): ...@@ -140,8 +146,10 @@ class Segmentation(object):
:return: :return:
""" """
t0 = time() t0 = time()
self.detectionState.emit('DO: setup')
gray = self.convert2Gray(img) gray = self.convert2Gray(img)
self.detectionState.emit('finished GrayScale')
print("gray") print("gray")
if self.adaptiveHistEqu: if self.adaptiveHistEqu:
...@@ -149,6 +157,7 @@ class Segmentation(object): ...@@ -149,6 +157,7 @@ class Segmentation(object):
numTilesY = round(img.shape[0]/self.claheTileSize) numTilesY = round(img.shape[0]/self.claheTileSize)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(numTilesY,numTilesX)) clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(numTilesY,numTilesX))
gray = clahe.apply(gray) gray = clahe.apply(gray)
self.detectionState.emit('finished CLAHE')
if return_step=="claheTileSize": return gray, 0 if return_step=="claheTileSize": return gray, 0
print("adaptive Histogram Adjustment") print("adaptive Histogram Adjustment")
...@@ -158,7 +167,8 @@ class Segmentation(object): ...@@ -158,7 +167,8 @@ class Segmentation(object):
if self.activateContrastCurve: if self.activateContrastCurve:
xi, arr = self.calculateHistFunction(self.contrastCurve) xi, arr = self.calculateHistFunction(self.contrastCurve)
gray = arr[gray] gray = arr[gray]
print("contrast curve") print("contrast curve")
self.detectionState.emit('finished Contrast Curve')
if self.cancelcomputation: if self.cancelcomputation:
return None, None return None, None
...@@ -171,6 +181,7 @@ class Segmentation(object): ...@@ -171,6 +181,7 @@ class Segmentation(object):
del gray del gray
if return_step=="blurRadius": return blur, 0 if return_step=="blurRadius": return blur, 0
self.detectionState.emit('finished Blurring')
print("blur") print("blur")
if self.cancelcomputation: if self.cancelcomputation:
return None, None return None, None
...@@ -215,6 +226,7 @@ class Segmentation(object): ...@@ -215,6 +226,7 @@ class Segmentation(object):
thresh = self.closeBrightHoles(thresh, blur, self.maxholebrightness) thresh = self.closeBrightHoles(thresh, blur, self.maxholebrightness)
del blur del blur
print("thresholded") print("thresholded")
self.detectionState.emit('finished thresholding')
# modify thresh with seedpoints and deletepoints # modify thresh with seedpoints and deletepoints
for p in np.int32(seedpoints): for p in np.int32(seedpoints):
...@@ -235,6 +247,8 @@ class Segmentation(object): ...@@ -235,6 +247,8 @@ class Segmentation(object):
'''the peak_local_max function takes the min distance between peaks. Unfortunately, that means that individual '''the peak_local_max function takes the min distance between peaks. Unfortunately, that means that individual
particles smaller than that distance are consequently disregarded. Hence, we need a connectec_components approach''' particles smaller than that distance are consequently disregarded. Hence, we need a connectec_components approach'''
n, labels, stats, centroids = cv2.connectedComponentsWithStats(thresh, 8, cv2.CV_32S) n, labels, stats, centroids = cv2.connectedComponentsWithStats(thresh, 8, cv2.CV_32S)
self.detectionState.emit('finished connected components search')
self.detectionState.emit(f'DO: maxVal={n-1}')
del thresh del thresh
measurementPoints = {} measurementPoints = {}
...@@ -249,7 +263,6 @@ class Segmentation(object): ...@@ -249,7 +263,6 @@ class Segmentation(object):
else: else:
previewImage = np.zeros(img.shape[:2]) previewImage = np.zeros(img.shape[:2])
for label in range(1, n): for label in range(1, n):
area = stats[label, cv2.CC_STAT_AREA] area = stats[label, cv2.CC_STAT_AREA]
if self.minparticlearea < area < maxArea: if self.minparticlearea < area < maxArea:
...@@ -257,21 +270,35 @@ class Segmentation(object): ...@@ -257,21 +270,35 @@ class Segmentation(object):
left = stats[label, cv2.CC_STAT_LEFT] left = stats[label, cv2.CC_STAT_LEFT]
width = stats[label, cv2.CC_STAT_WIDTH] width = stats[label, cv2.CC_STAT_WIDTH]
height = stats[label, cv2.CC_STAT_HEIGHT] height = stats[label, cv2.CC_STAT_HEIGHT]
subthresh = np.uint8(255 * (labels[up:(up+height), left:(left+width)] == label)) subthresh = np.uint8(255 * (labels[up:(up+height), left:(left+width)] == label))
scaleFactor = 1.0
if width > self.maxComponentSize or height > self.maxComponentSize:
scaleFactor = max([width/self.maxComponentSize, height/self.maxComponentSize])
subthresh = cv2.resize(subthresh, None, fx=1/scaleFactor, fy=1/scaleFactor)
subdist = cv2.distanceTransform(subthresh, cv2.DIST_L2, 3) subdist = cv2.distanceTransform(subthresh, cv2.DIST_L2, 3)
sure_fg = self.getSureForeground(subthresh, subdist, self.minparticledistance) minDistance = round(self.minparticledistance / scaleFactor)
sure_fg = self.getSureForeground(subthresh, subdist, minDistance)
sure_bg = cv2.dilate(subthresh, np.ones((5, 5)), iterations = 1) sure_bg = cv2.dilate(subthresh, np.ones((5, 5)), iterations = 1)
if self.closeBackground: if self.closeBackground:
sure_bg = self.closeHoles(sure_bg) sure_bg = self.closeHoles(sure_bg)
# modify sure_fg and sure_bg with seedpoints and deletepoints # modify sure_fg and sure_bg with seedpoints and deletepoints
for p in np.int32(seedpoints): for p in np.int32(seedpoints):
cv2.circle(sure_fg, tuple([p[0]-left, p[1]-up]), int(p[2]), 1, -1) x = int(round(p[0] / scaleFactor)-left)
cv2.circle(sure_bg, tuple([p[0]-left, p[1]-up]), int(p[2]), 1, -1) y = int(round(p[1] / scaleFactor) - up)
radius = int(round(p[2] / scaleFactor))
cv2.circle(sure_fg, (x, y), radius, 1, -1)
cv2.circle(sure_bg, (x, y), radius, 1, -1)
for p in np.int32(deletepoints): for p in np.int32(deletepoints):
cv2.circle(sure_fg, tuple([p[0]-left, p[1]-up]), int(p[2]), 0, -1) x = int(round(p[0] / scaleFactor) - left)
cv2.circle(sure_bg, tuple([p[0]-left, p[1]-up]), int(p[2]), 0, -1) y = int(round(p[1] / scaleFactor) - up)
radius = int(round(p[2] / scaleFactor))
cv2.circle(sure_fg, (x, y), radius, 1, -1)
cv2.circle(sure_bg, (x, y), radius, 1, -1)
if self.cancelcomputation: if self.cancelcomputation:
return None, None return None, None
...@@ -288,8 +315,12 @@ class Segmentation(object): ...@@ -288,8 +315,12 @@ class Segmentation(object):
markers[unknown==255] = 0 markers[unknown==255] = 0
markers = ndi.label(sure_fg)[0] markers = ndi.label(sure_fg)[0]
markers = watershed(-subdist, markers, mask=sure_bg, compactness = self.compactness, watershed_line = True) #labels = 0 for background, 1... for particles try:
markers = watershed(-subdist, markers, mask=sure_bg, compactness = self.compactness, watershed_line = True) #labels = 0 for background, 1... for particles
except MemoryError:
self.parent.raiseWarning('Segmentation failed due to large connected components.\nPlease reduce maximal connected Component Size.')
return None, None
if self.cancelcomputation: if self.cancelcomputation:
return None, None return None, None
...@@ -307,17 +338,28 @@ class Segmentation(object): ...@@ -307,17 +338,28 @@ class Segmentation(object):
tmpcontours = [contours[i] for i in range(len(contours)) if hierarchy[0,i,3]<0] tmpcontours = [contours[i] for i in range(len(contours)) if hierarchy[0,i,3]<0]
for cnt in tmpcontours: for cnt in tmpcontours:
if cv2.contourArea(cnt) >= self.minparticlearea: contourArea = cv2.contourArea(cnt) * scaleFactor**2
label = markers[cnt[0,0,1],cnt[0,0,0]] if contourArea >= self.minparticlearea:
if label==0: tmplabel = markers[cnt[0,0,1],cnt[0,0,0]]
if tmplabel ==0:
continue continue
x0, x1 = cnt[:,0,0].min(), cnt[:,0,0].max() x0, x1 = cnt[:,0,0].min(), cnt[:,0,0].max()
y0, y1 = cnt[:,0,1].min(), cnt[:,0,1].max() y0, y1 = cnt[:,0,1].min(), cnt[:,0,1].max()
subimg = (markers[y0:y1+1,x0:x1+1]).copy() subimg = (markers[y0:y1+1,x0:x1+1]).copy()
subimg[subimg!=label] = 0 subimg[subimg!=tmplabel ] = 0
y, x = self.getMeasurementPoints(subimg) y, x = self.getMeasurementPoints(subimg)
if scaleFactor != 1:
x0 = int(round(x0 * scaleFactor))
y0 = int(round(y0 * scaleFactor))
x = [int(round(subX * scaleFactor)) for subX in x]
y = [int(round(subY * scaleFactor)) for subY in y]
for i in range(len(cnt)):
cnt[i][0][0] = int(round(cnt[i][0][0] * scaleFactor))
cnt[i][0][1] = int(round(cnt[i][0][1] * scaleFactor))
for i in range(len(cnt)): for i in