particleAndMeasurement.py 5.86 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
# -*- coding: utf-8 -*-
"""
GEPARD - Gepard-Enabled PARticle Detection
Copyright (C) 2018  Lars Bittrich and Josef Brandt, Leibniz-Institut für 
Polymerforschung Dresden e. V. <bittrich-lars@ipfdd.de>    

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 <https://www.gnu.org/licenses/>.
"""
import numpy as np
22
from typing import List, TYPE_CHECKING
Josef Brandt's avatar
Josef Brandt committed
23 24
# from .. import dataset
from gepard import dataset
25 26 27 28

if TYPE_CHECKING:
    from .particleCharacterization import FTIRAperture

29 30 31 32

class Particle(object):
    def __init__(self):
        super(Particle, self).__init__()
Josef Brandt's avatar
Josef Brandt committed
33 34 35
        # from ...gepard.dataset import DataSet

        self.uid: int = dataset.DataSet.getUID()
36 37 38 39 40 41 42 43 44 45 46 47 48
        self.index: int = np.nan
        self.longSize: float = np.nan
        self.shortSize: float = np.nan
        self.height: float = np.nan
        self.area: float = np.nan
        self.contour: np.ndarray = None
        self.aperture: 'FTIRAperture' = None
        self.measurements: List['Measurement'] = []
        self.color: str = 'None'
        self.shape: str = 'None'
        self.wasManuallyEdited: bool = False
    
    def addMeasurement(self, refToMeasurement) -> None:
49
        refToMeasurement.assignedParticle = self
50
        self.measurements.append(refToMeasurement)
51

52
    def setAllSpectraToNewAssignment(self, newAssignment) -> None:
53 54 55 56
        for meas in self.measurements:
            meas.setAssignment(newAssignment)
            meas.setHQI(100)

57
    def getParticleAssignment(self) -> str:
Josef Brandt's avatar
Josef Brandt committed
58
        assignment = 'Excluded from Spectrum Scan'
59
        if len(self.measurements) > 0:
60
            assignment = self.getMeasAssignmentWithHighestHQI()
61
        return assignment
62
    
63 64
    def getHighestHQI(self) -> float:
        maxHQI: float = 0.0
65
        if len(self.measurements) > 0:
66
            hqis: List[float] = []
67 68 69 70
            for meas in self.measurements:
                hqis.append(meas.getHQI())
            maxHQI = max(hqis)
        return maxHQI
71
    
72
    def getHQIOfMeasurementIndex(self, index) -> float:
73
        for meas in self.measurements:
74
            if meas.specScanIndex == index:
75 76
                return meas.getHQI()
    
77 78
    def getMeasurementIndices(self) -> List[int]:
        indices: List[int] = []
79
        for meas in self.measurements:
80
            indices.append(meas.specScanIndex)
81 82
        return indices
    
83
    def getMeasurements(self) -> List['Measurement']:
84 85
        return self.measurements
    
86
    def getMeasAssignmentWithHighestHQI(self) -> str:
87 88 89 90 91 92 93
        hqis = []
        assignments = []
        for meas in self.measurements:
            hqis.append(meas.getHQI())
            assignments.append(meas.getAssignment())
        indexOfHighestHQI = hqis.index(max(hqis))
        return assignments[indexOfHighestHQI]
JosefBrandt's avatar
JosefBrandt committed
94
    
95
    def getParticleSize(self) -> float:
96
        if np.isnan(self.longSize):
97 98
            print(f'Error, particle size requested, but not yet set.\nParticle Index is {self.index}')
            raise ValueError
99 100
        else:
            return self.longSize
101
    
102
    def getShortParticleSize(self) -> float:
103
        if np.isnan(self.shortSize):
104 105
            print(f'Error, particle size requested, but not yet set.\nParticle Index is {self.index}')
            raise ValueError
106 107
        else:
            return self.shortSize
108
    
109
    def getNumberOfMeasurements(self) -> int:
110 111
        return len(self.measurements)
    
112
    def getArea(self) -> float:
JosefBrandt's avatar
JosefBrandt committed
113 114
        return np.round(self.area)
    
115
    def measurementsHaveSameOrigAssignment(self) -> bool:
116 117 118 119 120 121
        allResults = [meas.getOrigAssignment() for meas in self.measurements]
        if len(np.unique(allResults)) == 1:
            return True
        elif len(np.unique(allResults)) > 1:
            return False

122
    def getOrigMeasurementAssignments(self) -> List[str]:
123 124 125
        assignments = [meas.getOrigAssignment() for meas in self.measurements]
        return assignments

126
    def applyHQITresholdToMeasurements(self, minHQI) -> None:
127 128
        for measurement in self.measurements:
            measurement.applyHQIThreshold(minHQI)
129

130 131 132 133
    
class Measurement(object):
    def __init__(self):
        super(Measurement, self).__init__()
134
        self.specScanIndex: int = np.nan
135 136
        self.pixelcoord_x: int = np.nan
        self.pixelcoord_y: int = np.nan
137
        
138 139 140
        self.assignment_orig: str = 'Not yet measured'
        self.assignment_afterHQI: str = 'Not yet measured'
        self.hqi: float = 0
Josef Brandt's avatar
Josef Brandt committed
141 142
        self.measurementResults: dict = {}

143
        self.assignedParticle: 'Particle' = None
144
    
145
    def setAssignment(self, assignment) -> None:
146 147 148
        self.assignment_orig = assignment
        self.applyHQIThreshold()
        
149
    def setHQI(self, hqi) -> None:
150 151 152
        self.hqi = hqi
        self.applyHQIThreshold()
    
153 154
    def applyHQIThreshold(self, minHQI=0) -> None:
        if not np.isnan(self.hqi):  # i.e. skip for initial setup, when hqi is not yet aplied...
155 156 157 158 159
            if self.hqi >= minHQI:
                self.assignment_afterHQI = self.assignment_orig
            else:
                self.assignment_afterHQI = 'unknown'
    
160
    def getHQI(self) -> float:
161 162
        return self.hqi
    
163
    def getAssignment(self) -> str:
164 165 166 167 168
        if self.assignment_afterHQI is None:
            return self.assignment_orig
        else:
            return self.assignment_afterHQI
        
169
    def getOrigAssignment(self) -> str:
170 171
        return self.assignment_orig
    
172
    def getScanIndex(self) -> int:
173
        return self.specScanIndex