23 """Support for image defects""" 25 __all__ = (
"Defects",)
29 import collections.abc
30 from deprecated.sphinx
import deprecated
47 log = logging.getLogger(__name__)
50 @deprecated(reason=
"Policy defect files no longer supported (will be removed after v18)",
51 category=FutureWarning)
53 """Given a Policy file describing a CCD's bad pixels, return a vector of BadRegion::Ptr""" 55 badPixelsPolicy = policy.Policy.createPolicy(policyFile)
58 if badPixelsPolicy.exists(
"Defects"):
59 d = badPixelsPolicy.getArray(
"Defects")
62 width = reg.get(
"width")
68 if reg.exists(
"height"):
69 height = reg.get(
"height")
75 badPixels.append(Defect(bbox))
80 class Defects(collections.abc.MutableSequence):
81 """Collection of `lsst.meas.algorithms.Defect`. 85 defectList : iterable of `lsst.meas.algorithms.Defect` 86 or `lsst.geom.BoxI`, optional 87 Collections of defects to apply to the image. 91 """The calibration type used for ingest.""" 93 def __init__(self, defectList=None, metadata=None):
96 if metadata
is not None:
101 if defectList
is None:
108 def _check_value(self, value):
109 """Check that the supplied value is a `~lsst.meas.algorithms.Defect` 110 or can be converted to one. 119 new : `~lsst.meas.algorithms.Defect` 120 Either the supplied value or a new object derived from it. 125 Raised if the supplied value can not be converted to 126 `~lsst.meas.algorithms.Defect` 128 if isinstance(value, Defect):
131 value = Defect(value)
135 value = Defect(value.getBBox())
137 raise ValueError(f
"Defects must be of type Defect, BoxI, or PointI, not '{value!r}'")
147 """Can be given a `~lsst.meas.algorithms.Defect` or a `lsst.geom.BoxI` 158 """Compare if two `Defects` are equal. 160 Two `Defects` are equal if their bounding boxes are equal and in 161 the same order. Metadata content is ignored. 163 if not isinstance(other, self.__class__):
167 for d1, d2
in zip(self, other):
168 if d1.getBBox() != d2.getBBox():
174 return "Defects(" +
",".join(str(d.getBBox())
for d
in self) +
")" 180 """Retrieve metadata associated with these `Defects`. 184 meta : `lsst.daf.base.PropertyList` 185 Metadata. The returned `~lsst.daf.base.PropertyList` can be 186 modified by the caller and the changes will be written to 192 """Store a copy of the supplied metadata with the defects. 196 metadata : `lsst.daf.base.PropertyList`, optional 197 Metadata to associate with the defects. Will be copied and 198 overwrite existing metadata. If not supplied the existing 199 metadata will be reset. 210 """Copy the defects to a new list, creating new defects from the 216 New list with new `Defect` entries. 220 This is not a shallow copy in that new `Defect` instances are 221 created from the original bounding boxes. It's also not a deep 222 copy since the bounding boxes are not recreated. 224 return self.__class__(d.getBBox()
for d
in self)
227 """Make a transposed copy of this defect list. 231 retDefectList : `Defects` 232 Transposed list of defects. 234 retDefectList = self.__class__()
236 bbox = defect.getBBox()
237 dimensions = bbox.getDimensions()
240 retDefectList.append(nbbox)
244 """Set mask plane based on these defects. 248 maskedImage : `lsst.afw.image.MaskedImage` 249 Image to process. Only the mask plane is updated. 250 maskName : str, optional 251 Mask plane name to use. 254 mask = maskedImage.getMask()
255 bitmask = mask.getPlaneBitMask(maskName)
257 bbox = defect.getBBox()
261 """Convert defect list to `~lsst.afw.table.BaseCatalog` 265 table : `lsst.afw.table.BaseCatalog` 266 Defects in tabular form. 270 The table created uses the 271 `FITS regions <https://fits.gsfc.nasa.gov/registry/region.html>`_ 272 definition tabular format. The ``X`` and ``Y`` coordinates are 273 converted to FITS Physical coordinates that have origin pixel (1, 1) 274 rather than the (0, 0) used in LSST software. 277 x = schema.addField(
"X", type=
"D", units=
"pix")
278 y = schema.addField(
"Y", type=
"D", units=
"pix")
279 shape = schema.addField(
"SHAPE", type=
"String", size=16)
280 r = schema.addField(
"R", type="ArrayD", size=2, units="pix")
281 rotang = schema.addField(
"ROTANG", type=
"D", units=
"deg")
282 component = schema.addField(
"COMPONENT", type=
"I")
285 for i, defect
in enumerate(self.
_defects):
286 box = defect.getBBox()
287 record = table.addNew()
289 record.set(x, box.getCenterX() + 1.0)
290 record.set(y, box.getCenterY() + 1.0)
291 width = box.getWidth()
292 height = box.getHeight()
294 if width == 1
and height == 1:
299 record.set(shape, shapeType)
300 record.set(r, np.array([width, height], dtype=np.float64))
301 record.set(rotang, 0.0)
302 record.set(component, i)
307 table.setMetadata(metadata)
312 """Write defect list to FITS. 317 Arguments to be forwarded to 318 `lsst.afw.table.BaseCatalog.writeFits`. 323 metadata = table.getMetadata()
324 now = datetime.datetime.utcnow()
325 metadata[
"DATE"] = now.isoformat()
326 metadata[
"CALIB_CREATION_DATE"] = now.strftime(
"%Y-%m-%d")
327 metadata[
"CALIB_CREATION_TIME"] = now.strftime(
"%T %Z").strip()
329 table.writeFits(*args)
332 def _get_values(values, n=1):
333 """Retrieve N values from the supplied values. 337 values : `numbers.Number` or `list` or `np.array` 340 Number of values to retrieve. 344 vals : `list` or `np.array` or `numbers.Number` 345 Single value from supplied list if ``n`` is 1, or `list` 346 containing first ``n`` values from supplied values. 350 Some supplied tables have vectors in some columns that can also 351 be scalars. This method can be used to get the first number as 352 a scalar or the first N items from a vector as a vector. 355 if isinstance(values, numbers.Number):
364 """Construct a `Defects` from the contents of a 365 `~lsst.afw.table.BaseCatalog`. 369 table : `lsst.afw.table.BaseCatalog` 370 Table with one row per defect. 379 Two table formats are recognized. The first is the 380 `FITS regions <https://fits.gsfc.nasa.gov/registry/region.html>`_ 381 definition tabular format written by `toTable` where the pixel origin 382 is corrected from FITS 1-based to a 0-based origin. The second is 383 the legacy defects format using columns ``x0``, ``y0`` (bottom left 384 hand pixel of box in 0-based coordinates), ``width`` and ``height``. 386 The FITS standard regions can only read BOX, POINT, or ROTBOX with 387 a zero degree rotation. 392 schema = table.getSchema()
395 if "X" in schema
and "Y" in schema
and "R" in schema and "SHAPE" in schema:
399 elif "x0" in schema
and "y0" in schema
and "width" in schema
and "height" in schema:
404 raise ValueError(
"Unsupported schema for defects extraction")
407 record = r.extract(
"*")
415 shape = record[
"SHAPE"].upper()
420 elif shape ==
"POINT":
424 elif shape ==
"ROTBOX":
428 if math.isclose(rotang % 90.0, 0.0):
431 if math.isclose(rotang % 180.0, 0.0):
440 log.warning(
"Defect can not be defined using ROTBOX with non-aligned rotation angle")
443 log.warning(
"Defect lists can only be defined using BOX or POINT not %s", shape)
446 elif "x0" in record
and "y0" in record
and "width" in record
and "height" in record:
451 defectList.append(box)
453 return cls(defectList)
457 """Read defect list from FITS table. 462 Arguments to be forwarded to 463 `lsst.afw.table.BaseCatalog.writeFits`. 468 Defects read from a FITS table. 470 table = lsst.afw.table.BaseCatalog.readFits(*args)
472 defects.setMetadata(table.getMetadata())
477 """Read defects information from an LSST format text file. 482 Name of text file containing the defect information. 491 These defect text files are used as the human readable definitions 492 of defects in calibration data definition repositories. The format 493 is to use four columns defined as follows: 496 X coordinate of bottom left corner of box. 498 Y coordinate of bottom left corner of box. 506 defect_array = np.loadtxt(filename,
507 dtype=[(
"x0",
"int"), (
"y0",
"int"),
508 (
"x_extent",
"int"), (
"y_extent",
"int")])
512 for row
in defect_array)
516 """Compute a defect list from a footprint list, optionally growing 521 fpList : `list` of `lsst.afw.detection.Footprint` 522 Footprint list to process. 534 """Compute a defect list from a specified mask plane. 538 maskedImage : `lsst.afw.image.MaskedImage` 540 maskName : `str` or `list` 541 Mask plane name, or list of names to convert. 546 Defect list constructed from masked pixels. 548 mask = maskedImage.getMask()
550 lsst.afw.detection.Threshold.BITMASK)
def fromFootprintList(cls, fpList)
def maskPixels(self, maskedImage, maskName="BAD")
def setMetadata(self, metadata=None)
def _check_value(self, value)
def __setitem__(self, index, value)
def __init__(self, defectList=None, metadata=None)
def policyToBadRegionList(policyFile)
def readLsstDefectsFile(cls, filename)
def __getitem__(self, index)
std::vector< lsst::geom::Box2I > footprintToBBoxList(Footprint const &footprint)
def writeFits(self, args)
def __delitem__(self, index)
def fromTable(cls, table)
def insert(self, index, value)
static Box2I makeCenteredBox(Point2D const ¢er, Extent const &size)
def _get_values(values, n=1)
def fromMask(cls, maskedImage, maskName)