# -*- coding: utf-8 -*- """ GEPARD - Gepard-Enabled PARticle Detection Copyright (C) 2018 Lars Bittrich and Josef Brandt, Leibniz-Institut für Polymerforschung Dresden e. V. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program, see COPYING. If not, see . """ import numpy as np import operator import os from PyQt5 import QtWidgets from analysis import importSpectra from analysis.particleAndMeasurement import Particle, Measurement class ParticleContainer(object): def __init__(self, datasetParent): super(ParticleContainer, self).__init__() self.datasetParent = datasetParent self.particles = [] self.measurements = [] self.spectra = None self.inconsistentParticles = [] self.typeHistogram = None def addEmptyMeasurement(self): newMeas = Measurement() self.measurements.append(newMeas) return self.measurements.index(newMeas) def clearParticles(self): self.particles = [] def clearMeasurements(self): self.measurements = [] def setMeasurementScanIndex(self, indexOfMeasurment, scanIndex): self.measurements[indexOfMeasurment].ramanScanIndex = scanIndex def setMeasurementPixelCoords(self, indexOfMeasurment, x, y): self.measurements[indexOfMeasurment].pixelcoord_x = x self.measurements[indexOfMeasurment].pixelcoord_y = y def getMeasurementScanindex(self, indexOfMeasurement): return self.measurements[indexOfMeasurement].getScanIndex() def getSpectraFromDisk(self): spectra = None specPath = self.datasetParent.getSpectraFileName() if os.path.exists(specPath): spectra = np.load(specPath) else: fname = QtWidgets.QFileDialog.getOpenFileName(QtWidgets.QWidget(), 'Select Spectra File', self.datasetParent.path, 'text file (*.txt)')[0] if fname: #TODO: implement a more elegant way of testing through the individual imports... try: spectra, spectraNames = importSpectra.importWITecSpectra(fname) except ImportError: try: spectra, spectraNames = importSpectra.importRenishawSpectra(fname) except ImportError: try: spectra, spectraNames = importSpectra.importPerkinElmerSpectra(fname) except ImportError: pass if spectra is not None: np.save(self.datasetParent.getSpectraFileName(), spectra) return spectra def initializeParticles(self, numParticles): self.particles = [] for i in range(numParticles): newParticle = Particle() newParticle.index = i self.particles.append(newParticle) def setParticleContours(self, contours): assert len(self.particles) == len(contours) for index, particle in enumerate(self.particles): particle.contour = contours[index] def setParticleStats(self, particlestats): assert len(self.particles) == len(particlestats) #particlestats is list of [long, short, longellipse, shortellipse, cv2.contourArea(cnt)] for index, particle in enumerate(self.particles): particle.longSize_box = float(particlestats[index][0]) particle.shortSize_box = float(particlestats[index][1]) particle.longSize_ellipse = float(particlestats[index][2]) particle.shortSize_ellipse = float(particlestats[index][3]) particle.area = float(particlestats[index][4]) def testForInconsistentParticles(self): #i.e., particles that have multiple measurements with different assignments self.inconsistentParticles = [] for particle in self.particles: if not particle.measurementsHaveSameOrigAssignment(): self.inconsistentParticles.append(particle) if len(self.inconsistentParticles) > 0: print('Warning, inconsistent particles found!') for particle in self.inconsistentParticles: print(f'Particle with index {particle.index} has the following assignments:') for assignment in particle.getOrigMeasurementAssignments(): print(assignment) else: print('All particles have consistent spectra assignments') def applyPixelScaleToParticleStats(self, pixelscale): for index, particle in enumerate(self.particles): particle.longSize_box *= pixelscale particle.shortSize_box *= pixelscale particle.longSize_ellipse *= pixelscale particle.shortSize_ellipse *= pixelscale particle.area *= pixelscale**2 def applyHQITresholdToParticles(self, minHQI): for particle in self.particles: particle.applyHQITresholdToMeasurements(minHQI) def applyAssignmentListToParticleMeasurements(self, assignmentList): '''AssignmentList is list of spectra assignments in order of spectra indices''' indicesOfTransferredAssignments = [None]*len(assignmentList) for particle in self.particles: for meas in particle.getMeasurements(): scanIndex = meas.getScanIndex() meas.setAssignment(assignmentList[scanIndex]) indicesOfTransferredAssignments[scanIndex] = scanIndex assert not None in indicesOfTransferredAssignments def applyHQIListToParticleMeasurements(self, hqiList): '''HQI-List is list of spectra hqis in order of spectra indices''' indicesOfTransferredHQIs = [None]*len(hqiList) for particle in self.particles: for meas in particle.getMeasurements(): scanIndex = meas.getScanIndex() meas.setHQI(hqiList[scanIndex]) indicesOfTransferredHQIs[scanIndex] = scanIndex assert not None in indicesOfTransferredHQIs def reassignParticleToAssignment(self, particleIndex, newAssignment): particle = self.getParticleOfIndex(particleIndex) particle.setAllSpectraToNewAssignment(newAssignment) def getParticleOfIndex(self, index): try: particle = self.particles[index] except: print('failed getting particle') print('requested Index:', index) print('len particles', len(self.particles)) assert particle.index == index, f'particle.index ({particle.index}) does match requested index in particleList ({index})' return particle def getParticleIndexContainingSpecIndex(self, index): for particle in self.particles: if index in particle.getMeasurementIndices(): return particle.index def getNumberOfParticles(self): return len(self.particles) def getParticleContours(self): contours = [part.contour for part in self.particles] return contours def getParticleContoursByIndex(self, partIndices): contours = [] for index in partIndices: particle = self.getParticleOfIndex(index) contours.append(particle.contour) return contours def getParticleAssignmentByIndex(self, partIndex): particle = self.getParticleOfIndex(partIndex) return particle.getParticleAssignment() def getMeasurementPixelCoords(self): coords = [] for meas in self.measurements: coords.append([meas.pixelcoord_x, meas.pixelcoord_y]) return coords def getNumberOfParticlesOfAssignment(self, assignment): num = 0 for particle in self.particles: if particle.getParticleAssignment() == assignment: num += 1 return num def getNumberOfSpectraOfParticle(self, particleIndex): particle = self.getParticleOfIndex(particleIndex) return particle.getNumberOfMeasurements() def getSpectraIndicesOfParticle(self, particleIndex): particle = self.getParticleOfIndex(particleIndex) return particle.getMeasurementIndices() def getListOfParticleAssignments(self): particleAssignments = [] for particle in self.particles: particleAssignments.append(particle.getParticleAssignment()) return particleAssignments def getListOfHighestHQIs(self): hqis = [] for particle in self.particles: hqis.append(particle.getHighestHQI()) return hqis def getHQIOfSpectrumIndex(self, specIndex): for particle in self.particles: if specIndex in particle.getMeasurementIndices(): return particle.getHQIOfMeasurementIndex(specIndex) def getSizesOfAllParticles(self): particleSizes = [] for particle in self.particles: particleSizes.append(particle.getParticleSize()) return particleSizes def getShortSizesOfAllParticles(self): shortSizes = [] for particle in self.particles: shortSizes.append(particle.getShortParticleSize()) return shortSizes def getAreasOfAllParticles(self): areas = [] for particle in self.particles: areas.append(particle.getArea()) return areas def getSizesOfParticleType(self, assignment): particleSizes = [] for particle in self.particles: if particle.getParticleAssignment() == assignment: particleSizes.append(particle.getParticleSize()) return particleSizes def getIndicesOfParticleType(self, assignment): indices = [] for particle in self.particles: if particle.getParticleAssignment() == assignment: indices.append(particle.index) return indices def getSizeOfParticleByIndex(self, index): particle = self.getParticleOfIndex(index) return particle.getParticleSize() def getUniquePolymers(self): typeHist = self.getTypeHistogram() return typeHist.keys() def getTypeHistogram(self): uniquePolymers = np.unique(self.getListOfParticleAssignments()) typehistogram = {i: 0 for i in uniquePolymers} for assignment in self.getListOfParticleAssignments(): typehistogram[assignment] += 1 ##sort typehistogram, it will be converted into a list!! sorted_typehistogram = sorted(typehistogram.items(), key = operator.itemgetter(1), reverse = True) #convert back to dsetParticlecontoursict final_typehistogram = {i[0]: i[1] for i in sorted_typehistogram} return final_typehistogram def addMergedParticle(self, particleIndices, newContour, newStats, newAssignment=None): newParticle = Particle() #copy Measurements for index in particleIndices: particle = self.getParticleOfIndex(index) for meas in particle.getMeasurements(): if newAssignment is not None: meas.setAssignment(newAssignment) meas.setHQI(100) newParticle.addMeasurement(meas) #set Particle Stats long, short, longellipse, shortellipse, area = newStats newParticle.longSize_box = long newParticle.shortSize_box = short newParticle.longSize_ellipse = longellipse newParticle.shortSize_ellipse = shortellipse newParticle.area = area newParticle.contour = newContour self.particles.append(newParticle) print('added new particle') def removeParticle(self, index): particle = self.getParticleOfIndex(index) #just for asserting to have the correct particle! del self.particles[index] def resetParticleIndices(self): for newIndex, particle in enumerate(self.particles): particle.index = newIndex