particleAndMeasurement.py 5.71 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 23 24 25 26
from typing import List, TYPE_CHECKING

if TYPE_CHECKING:
    from .particleCharacterization import FTIRAperture

27 28 29 30

class Particle(object):
    def __init__(self):
        super(Particle, self).__init__()
31 32 33 34 35 36 37 38 39 40 41 42 43
        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:
44
        refToMeasurement.assignedParticle = self
45
        self.measurements.append(refToMeasurement)
46

47
    def setAllSpectraToNewAssignment(self, newAssignment) -> None:
48 49 50 51
        for meas in self.measurements:
            meas.setAssignment(newAssignment)
            meas.setHQI(100)

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

117
    def getOrigMeasurementAssignments(self) -> List[str]:
118 119 120
        assignments = [meas.getOrigAssignment() for meas in self.measurements]
        return assignments

121
    def applyHQITresholdToMeasurements(self, minHQI) -> None:
122 123
        for measurement in self.measurements:
            measurement.applyHQIThreshold(minHQI)
124

125 126 127 128
    
class Measurement(object):
    def __init__(self):
        super(Measurement, self).__init__()
129
        self.specScanIndex: int = np.nan
130 131
        self.pixelcoord_x: int = np.nan
        self.pixelcoord_y: int = np.nan
132
        
133 134 135
        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
136 137
        self.measurementResults: dict = {}

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