27 from .applyLookupTable
import applyLookupTable
29 __all__ = [
"LinearizeBase",
"LinearizeLookupTable",
"LinearizeSquared"]
33 """Abstract base class functor for correcting non-linearity 35 Subclasses must define __call__ and set class variable LinearityType to a string 36 that will be used for linearity type in AmpInfoCatalog 42 """Correct non-linearity 44 @param[in] image image to be corrected (an lsst.afw.image.Image) 45 @param[in] detector detector information (an instance of lsst::afw::cameraGeom::Detector) 46 @param[in] log logger (an lsst.log.Log), or None to disable logging; 47 a warning is logged if amplifiers are skipped or other worrisome events occur 49 @return an lsst.pipe.base.Struct containing at least the following fields: 50 - numAmps number of amplifiers found 51 - numLinearized number of amplifiers linearized 53 @throw RuntimeError if the linearity type is wrong 54 @throw a subclass of Exception if linearization fails for any other reason 59 """Verify that the linearity type is correct for this detector 61 @warning only checks the first record of the amp info catalog 63 @param[in] detector detector information (an instance of lsst::afw::cameraGeom::Detector) 65 @throw RuntimeError if anything doesn't match 67 ampInfoType = detector.getAmpInfoCatalog()[0].getLinearityType()
68 if self.LinearityType != ampInfoType:
69 raise RuntimeError(
"Linearity types don't match: %s != %s" % (self.LinearityType, ampInfoType))
73 """Correct non-linearity with a persisted lookup table 75 for each i,j of image: 77 colInd = int(c1 + uncorrImage[i,j]) 78 corrImage[i,j] = uncorrImage[i,j] + table[rowInd, colInd] 80 where c0, c1 are collimation coefficients from the AmpInfoTable of the detector: 81 - c0: row index; used to identify which row of the table to use (typically one per amplifier, 82 though one can have multiple amplifiers use the same table) 83 - c1: column index offset; added to the uncorrected image value before truncation; 84 this supports tables that can handle negative image values; also, if the c1 ends with .5 85 then the nearest index is used instead of truncating to the next smaller index 87 In order to keep related data together, the coefficients are persisted along with the table. 89 LinearityType =
"LookupTable" 92 """Construct a LinearizeLookupTable 94 @param[in] table lookup table; a 2-dimensional array of floats: 95 - one row for each row index (value of coef[0] in the amp info catalog) 96 - one column for each image value 97 To avoid copying the table the last index should vary fastest (numpy default "C" order) 98 @param[in] detector detector information (an instance of lsst::afw::cameraGeom::Detector); 99 the name, serial, and amplifier linearization type and coefficients are saved 101 @throw RuntimeError if table is not 2-dimensional, 102 table has fewer columns than rows (indicating that the indices are swapped), 103 or if any row index (linearity coefficient 0) is out of range 105 LinearizeBase.__init__(self)
107 self.
_table = np.array(table, order=
"C")
108 if len(table.shape) != 2:
109 raise RuntimeError(
"table shape = %s; must have two dimensions" % (table.shape,))
110 if table.shape[1] < table.shape[0]:
111 raise RuntimeError(
"table shape = %s; indices are switched" % (table.shape,))
116 ampInfoCat = detector.getAmpInfoCatalog()
118 colIndOffsetList = []
119 numTableRows = table.shape[0]
120 for ampInfo
in ampInfoCat:
121 rowInd, colIndOffset = ampInfo.getLinearityCoeffs()[0:2]
123 if rowInd < 0
or rowInd >= numTableRows:
124 raise RuntimeError(
"Amplifier %s has rowInd=%s not in range[0, %s)" %
125 (ampInfo.getName(), rowInd, numTableRows))
126 rowIndList.append(int(rowInd))
127 colIndOffsetList.append(colIndOffset)
128 self.
_rowIndArr = np.array(rowIndList, dtype=int)
132 """Correct for non-linearity 134 @param[in] image image to be corrected (an lsst.afw.image.Image) 135 @param[in] detector detector info about image (an lsst.afw.cameraGeom.Detector); 136 the name, serial and number of amplifiers must match persisted data; 137 the bbox from each amplifier is read; 138 the linearization coefficients are ignored in favor of the persisted values 139 @param[in] log logger (an lsst.log.Log), or None to disable logging; 140 a warning is logged if any pixels are out of range of their lookup table 142 @return an lsst.pipe.base.Struct containing: 143 - numAmps number of amplifiers found 144 - numLinearized number of amplifiers linearized (always equal to numAmps for this linearizer) 145 - numOutOfRange number of pixels out of range of their lookup table (summed across all amps) 147 @throw RuntimeError if the linearity type is wrong or if the detector name, serial 148 or number of amplifiers does not match the saved data 151 ampInfoCat = detector.getAmpInfoCatalog()
154 bbox = ampInfo.getBBox()
155 ampView = image.Factory(image, bbox)
156 tableRow = self.
_table[rowInd, :]
159 if numOutOfRange > 0
and log
is not None:
160 log.warn(
"%s pixels of detector \"%s\" were out of range of the linearization table",
161 numOutOfRange, detector.getName())
162 numAmps = len(ampInfoCat)
165 numLinearized=numAmps,
166 numOutOfRange=numOutOfRange,
170 """Check detector name and serial number, ampInfo table length and linearity type 172 @param[in] detector detector info about image (an lsst.afw.cameraGeom.Detector); 174 @throw RuntimeError if anything doesn't match 177 raise RuntimeError(
"Detector names don't match: %s != %s" %
180 raise RuntimeError(
"Detector serial numbers don't match: %s != %s" %
183 numAmps = len(detector.getAmpInfoCatalog())
185 raise RuntimeError(
"Detector number of amps = %s does not match saved value %s" %
191 """Correct non-linearity with a squared model 193 corrImage = uncorrImage + c0*uncorrImage^2 195 where c0 is linearity coefficient 0 in the AmpInfoCatalog of the detector 197 LinearityType =
"Squared" 200 """Correct for non-linearity 202 @param[in] image image to be corrected (an lsst.afw.image.Image) 203 @param[in] detector detector info about image (an lsst.afw.cameraGeom.Detector) 204 @param[in] log logger (an lsst.log.Log), or None to disable logging; 205 a warning is logged if any amplifiers are skipped because the square coefficient is 0 207 @return an lsst.pipe.base.Struct containing at least the following fields: 208 - nAmps number of amplifiers found 209 - nLinearized number of amplifiers linearized 211 @throw RuntimeError if the linearity type is wrong 214 ampInfoCat = detector.getAmpInfoCatalog()
216 for ampInfo
in ampInfoCat:
217 sqCoeff = ampInfo.getLinearityCoeffs()[0]
219 bbox = ampInfo.getBBox()
220 ampArr = image.Factory(image, bbox).getArray()
221 ampArr *= (1 + sqCoeff*ampArr)
224 numAmps = len(ampInfoCat)
225 if numAmps > numLinearized
and log
is not None:
226 log.warn(
"%s of %s amps in detector \"%s\" were not linearized (coefficient = 0)",
227 numAmps - numLinearized, numAmps, detector.getName())
230 numLinearized=numLinearized,
def __call__(self, image, detector, log=None)
def __call__(self, image, detector, log=None)
def checkLinearityType(self, detector)
def checkDetector(self, detector)
def __call__(self, image, detector, log=None)
def __init__(self, table, detector)