Commit 1911d4e7 authored by Robert's avatar Robert Committed by ohmacht@zwei-g.de

-create square particles, where gepard did not find a contour matching a ps measurement

-assign 'not yet measured' on contours found by gepard, that do not contain a ps measurement
parent 4fcd0f47
......@@ -75,6 +75,12 @@ class ParticleContainer(object):
particle.measurements = []
def setMeasurementScanIndex(self, indexOfMeasurment, scanIndex):
"""
associates measurment/contour/particle with scan result via its (scan) index
:param indexOfMeasurment:
:param scanIndex:
:return:
"""
self.measurements[indexOfMeasurment].specScanIndex = scanIndex
def setMeasurementPixelCoords(self, indexOfMeasurment, x, y):
......
......@@ -219,6 +219,7 @@ class DataSet(object):
self.resultsUploadedToSQL = []
self.seedParticles = None
self.contourSeedMapping = None
self.stickToSeedPoints = False
self.readin = True # a value that is always set to True at loadData
......
......@@ -29,7 +29,8 @@ import matplotlib.pyplot as plt
from threading import Thread
from typing import TYPE_CHECKING
from ..segmentation import Segmentation
from ..particlescoutimporter import ParticleScoutImporter
from ..segmentation import Segmentation, MeasurementPoint
from ..analysis.particleCharacterization import getParticleStatsWithPixelScale, loadZValImageFromDataset
from ..errors import InvalidParticleError, showErrorMessageAsWidget
from .uielements import TimeEstimateProgressbar
......@@ -37,6 +38,7 @@ from ..scenePyramid import ScenePyramid
from ..gepardlogging import setDefaultLoggingConfig
from ..helperfunctions import needsFTIRAperture, positionWidgetOnScreen
if TYPE_CHECKING:
from ..sampleview import SampleView
from .viewItemHandler import ViewItemHandler
......@@ -848,32 +850,46 @@ class ParticleDetectionView(QtWidgets.QWidget):
if self.dataset.stickToSeedPoints:
self.dataset.specscandone = True
# remove all detected particles that do not contain seedpoints
finalContours = []
finalPoints = []
# contour index and all associated seedpoints/spectra
contourSeedMapping = {}
# used seedpoints
usedSeeds = []
# check contours
# for all remaining contours
for i, c in enumerate(contours):
# for having a seedpoint
hasSeedPoint = False
# check for having a/more than one seedpoint
for j, p in enumerate(self.dataset.seedpoints):
# inside of or on them
hasSeedPoint = hasSeedPoint or 0 <= cv2.pointPolygonTest(c, (p[0], p[1]), False)
if hasSeedPoint:
# found, save index
if 0 <= cv2.pointPolygonTest(c, (p[0], p[1]), False):
# found, record list of seedpoint indices for every contour index
if i not in contourSeedMapping:
contourSeedMapping[i] = []
contourSeedMapping[i].append(j)
usedSeeds.append(j)
# next
break
if hasSeedPoint:
# seedpoint found inside contour
finalContours.append(c)
finalPoints.append(measurementPoints[i])
# seedpoints, that did not get detected by gepard
unusedSeeds = [j for j in range(self.dataset.seedpoints.shape[0]) if j not in usedSeeds]
if 0 < len(unusedSeeds):
# add oddly 'shaped' contour at these seedpoints
for i in unusedSeeds:
p = self.dataset.seedpoints[i]
idx = len(contours)
contours.append(
ParticleScoutImporter.notFoundByGepardStamp(
p,
self.img.shape[1],
self.img.shape[0]
)
)
measurementPoints.append([MeasurementPoint(idx, p[0], p[1])])
usedSeeds.append(i)
if idx not in contourSeedMapping:
contourSeedMapping[idx] = []
contourSeedMapping[idx].append(i)
# order seed particles and spectra by measurement/contour order
self.dataset.seedParticles = [self.dataset.seedParticles[i] for i in usedSeeds]
contours = finalContours
measurementPoints = finalPoints
#self.dataset.seedParticles = [self.dataset.seedParticles[i] for i in usedSeeds]
self.dataset.contourSeedMapping = contourSeedMapping
particlestats, invalidParticleIndices = self.getParticleStats(contours)
contours = removeInvalidContours(contours, invalidParticleIndices)
......@@ -905,9 +921,9 @@ class ParticleDetectionView(QtWidgets.QWidget):
ftir: bool = needsFTIRAperture(self.view)
for contourIndex, contour in enumerate(contours):
try:
stats = getParticleStatsWithPixelScale(contour, self.dataset, fullimage=self.img, zimg=zvalimg,
ftir=ftir)
stats = getParticleStatsWithPixelScale(
contour, self.dataset, fullimage=self.img, zimg=zvalimg, ftir=ftir
)
except InvalidParticleError:
self.logger.debug('Invalid contour in detection, skipping particle.')
invalidParticleIndices.append(contourIndex)
......
......@@ -138,7 +138,8 @@ class SpecScanUI(QtWidgets.QWidget):
# if imported from particle scout
if self.dataset.stickToSeedPoints:
spectra = []
# particles are in the same order as the measurements/spectra
# collect all particle scout spectra
# some of them may be located in the same contour/measurement/particle
for i, p in enumerate(self.dataset.seedParticles):
# first particle
if 0 == len(spectra):
......@@ -146,8 +147,34 @@ class SpecScanUI(QtWidgets.QWidget):
spectra = np.array([np.array(p['spectrum'])[:, 0]])
# get particle spectrum
spectra = np.concatenate((spectra, np.array([np.array(p['spectrum'])[:, 1]])))
# associate spectrum idx with measurement
self.dataset.particleContainer.setMeasurementScanIndex(i, i)
# @todo: add 'virtual' scan index to measurements without data from particle scout
for contourIdx, seedpoints in self.dataset.contourSeedMapping.items():
# associate spectrum idx with measurement/particle/contour
# in some rare cases, multiple particle scout scan results lie within one gepard contour
# take first scan result and inform via console
if 1 < len(seedpoints):
materials = [p['material'] for p in [self.dataset.seedParticles[i] for i in seedpoints]]
self.logger.info(
f'we have more than one spectrum for a contour ({",".join(materials)}), taking first'
)
self.dataset.particleContainer.setMeasurementScanIndex(
contourIdx,
seedpoints[0]# + 1 # +1 because first spectra rec is the header
)
# if gepard detected more particles/contours, than particle scout provided
# check for measurements without spectrum association
diff = 0
base = spectra.shape[0] - 1 # without -1 bc first rec is the header
sl = len(p['spectrum'])
for m in self.dataset.particleContainer.measurements:
if np.isnan(m.getScanIndex()):
# add 'virtual' spectrum and associate measurement with it
spectra = np.concatenate((spectra, [np.zeros(sl, dtype=np.int)]))
m.specScanIndex = base + diff
diff += 1
# write spectrum file
# 2d array with
# num(cols) = num(particle/measurements/spectra)
......@@ -160,9 +187,18 @@ class SpecScanUI(QtWidgets.QWidget):
fname = os.path.join(self.dataset.path, f'{self.dataset.name}_TrueMatchResults.txt')
with open(fname, 'w') as fp:
fp.write("Search Spectrum Name;HQI 1;Found Spectrum Name 1;IsMarked;\n")
for i, p in enumerate(self.dataset.seedParticles):
for contourIdx, seedpoints in self.dataset.contourSeedMapping.items():
i = seedpoints[0]
p = self.dataset.seedParticles[i]
fp.write(f"Spectrum {i+1};100;{p['material']};yes;\n")
if 0 < diff:
# add virtual spectra
for v in range(diff):
fp.write(f"Spectrum {base + v + 1};100;not yet measured;yes;\n")
self.dataset.stickToSeedPoints = False
@QtCore.pyqtSlot()
def cancelScan(self):
if self.process is not None and self.process.is_alive():
......
......@@ -35,6 +35,37 @@ if TYPE_CHECKING: # avoids cyclic imports due to type hints..
from .sampleview import SampleView
class ParticleScoutImporter:
@staticmethod
def notFoundByGepardStamp(p, maxX, maxY):
'''
returns square with side length of 300px, clipped at img edges, with center at p
:param p:
:param maxX:
:param maxY:
:return:
'''
sideLength = 100
xmin = int(p[0] - sideLength / 2)
if 0 > xmin:
xmin = 0
xmax = int(p[0] + sideLength / 2)
if maxX < xmax:
xmax = maxX
ymin = int(p[1] - sideLength / 2)
if 0 > ymin:
ymin = 0
ymax = int(p[1] + sideLength / 2)
if maxY < ymax:
ymax = maxY
return np.array([
[[xmin, ymin]], [[xmax, ymin]], [[xmax, ymax]], [[xmin, ymax]]
], dtype=np.int_)
def __init__(self, fname, parent=None):
self.parent: SampleView = parent
self.dataSet = None
......@@ -117,7 +148,7 @@ class ParticleScoutImporter:
coords = {}
with open(os.path.join(self.path, f"{self.basename}.txt"), 'r') as fp:
for line in fp:
match = re.match(r'^\s*(?P<var>[^:]+):\s*(?P<value>[0-9-,]+)$', line)
match = re.match(r'^\s*(?P<var>[^:]+):\s*(?P<value>[0-9-.,]+)$', line)
if match:
coords[match.group('var').lower()] = float(match.group('value').replace(',', '.'))
......@@ -186,6 +217,12 @@ class ParticleScoutImporter:
return missing, merged
def buildDataSet(self, coords, particles):
'''
computes parameters from given particle scout data
:param coords: coordinate system parameters given in txt file
:param particles:
:return:
'''
fname = QtWidgets.QFileDialog.getSaveFileName(
self.parent,
'Create New GEPARD Project',
......@@ -223,8 +260,10 @@ class ParticleScoutImporter:
self.dataSet.readin = False
# set image center as reference point (assume just one tile)
# in upright coord system the given coords point to center point of image
coords['y'] += coords['height'] / 2
coords['x'] -= coords['width'] / 2
centerPointGiven = False
if centerPointGiven:
coords['y'] += coords['height'] / 2
coords['x'] -= coords['width'] / 2
# in upright coord system now the coords point to upper left point of image
# coord of (unrotated) center with origin in upper left corner
m = (coords['width'] / 2, -coords['height'] / 2)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment