23 """Support for image defects""" 25 __all__ = (
"Defects",)
29 import collections.abc
30 from deprecated.sphinx
import deprecated
45 log = logging.getLogger(__name__)
48 @deprecated(reason=
"Policy defect files no longer supported (will be removed after v18)",
49 category=FutureWarning)
51 """Given a Policy file describing a CCD's bad pixels, return a vector of BadRegion::Ptr""" 53 badPixelsPolicy = policy.Policy.createPolicy(policyFile)
56 if badPixelsPolicy.exists(
"Defects"):
57 d = badPixelsPolicy.getArray(
"Defects")
60 width = reg.get(
"width")
66 if reg.exists(
"height"):
67 height = reg.get(
"height")
73 badPixels.append(Defect(bbox))
78 class Defects(collections.abc.MutableSequence):
79 """Collection of `lsst.meas.algorithms.Defect`. 83 defectList : iterable of `lsst.meas.algorithms.Defect` 84 or `lsst.geom.BoxI`, optional 85 Collections of defects to apply to the image. 89 """The calibration type used for ingest.""" 91 def __init__(self, defectList=None, metadata=None):
94 if metadata
is not None:
99 if defectList
is None:
106 def _check_value(self, value):
107 """Check that the supplied value is a `~lsst.meas.algorithms.Defect` 108 or can be converted to one. 117 new : `~lsst.meas.algorithms.Defect` 118 Either the supplied value or a new object derived from it. 123 Raised if the supplied value can not be converted to 124 `~lsst.meas.algorithms.Defect` 126 if isinstance(value, Defect):
129 value = Defect(value)
133 value = Defect(value.getBBox())
135 raise ValueError(f
"Defects must be of type Defect, BoxI, or PointI, not '{value!r}'")
145 """Can be given a `~lsst.meas.algorithms.Defect` or a `lsst.geom.BoxI` 156 """Compare if two `Defects` are equal. 158 Two `Defects` are equal if their bounding boxes are equal and in 159 the same order. Metadata content is ignored. 161 if not isinstance(other, self.__class__):
165 for d1, d2
in zip(self, other):
166 if d1.getBBox() != d2.getBBox():
172 return "Defects(" +
",".join(str(d.getBBox())
for d
in self) +
")" 178 """Retrieve metadata associated with these `Defects`. 182 meta : `lsst.daf.base.PropertyList` 183 Metadata. The returned `~lsst.daf.base.PropertyList` can be 184 modified by the caller and the changes will be written to 190 """Store a copy of the supplied metadata with the defects. 194 metadata : `lsst.daf.base.PropertyList`, optional 195 Metadata to associate with the defects. Will be copied and 196 overwrite existing metadata. If not supplied the existing 197 metadata will be reset. 208 """Copy the defects to a new list, creating new defects from the 214 New list with new `Defect` entries. 218 This is not a shallow copy in that new `Defect` instances are 219 created from the original bounding boxes. It's also not a deep 220 copy since the bounding boxes are not recreated. 222 return self.__class__(d.getBBox()
for d
in self)
225 """Make a transposed copy of this defect list. 229 retDefectList : `Defects` 230 Transposed list of defects. 232 retDefectList = self.__class__()
234 bbox = defect.getBBox()
235 dimensions = bbox.getDimensions()
238 retDefectList.append(nbbox)
242 """Set mask plane based on these defects. 246 maskedImage : `lsst.afw.image.MaskedImage` 247 Image to process. Only the mask plane is updated. 248 maskName : str, optional 249 Mask plane name to use. 252 mask = maskedImage.getMask()
253 bitmask = mask.getPlaneBitMask(maskName)
255 bbox = defect.getBBox()
259 """Convert defect list to `~lsst.afw.table.BaseCatalog` 263 table : `lsst.afw.table.BaseCatalog` 264 Defects in tabular form. 267 x = schema.addField(
"X", type=
"D", units=
"pix")
268 y = schema.addField(
"Y", type=
"D", units=
"pix")
269 shape = schema.addField(
"SHAPE", type=
"String", size=16)
270 r = schema.addField(
"R", type="ArrayD", size=2, units="pix")
271 rotang = schema.addField(
"ROTANG", type=
"D", units=
"deg")
272 component = schema.addField(
"COMPONENT", type=
"I")
275 for i, defect
in enumerate(self.
_defects):
276 box = defect.getBBox()
277 record = table.addNew()
278 record.set(x, box.getCenterX())
279 record.set(y, box.getCenterY())
280 record.set(shape,
"BOX")
281 record.set(r, np.array([box.getWidth(), box.getHeight()], dtype=np.float64))
282 record.set(rotang, 0.0)
283 record.set(component, i)
288 table.setMetadata(metadata)
293 """Write defect list to FITS. 298 Arguments to be forwarded to 299 `lsst.afw.table.BaseCatalog.writeFits`. 304 metadata = table.getMetadata()
305 now = datetime.datetime.utcnow()
306 metadata[
"DATE"] = now.isoformat()
307 metadata[
"CALIB_CREATION_DATE"] = now.strftime(
"%Y-%m-%d")
308 metadata[
"CALIB_CREATION_TIME"] = now.strftime(
"%T %Z").strip()
310 table.writeFits(*args)
314 """Construct a `Defects` from the contents of a 315 `~lsst.afw.table.BaseCatalog`. 319 table : `lsst.afw.table.BaseCatalog` 320 Table with one row per defect. 330 schema = table.getSchema()
333 if "X" in schema
and "Y" in schema
and "R" in schema and "SHAPE" in schema:
337 elif "x0" in schema
and "y0" in schema
and "width" in schema
and "height" in schema:
342 raise ValueError(
"Unsupported schema for defects extraction")
345 record = r.extract(
"*")
348 if record[
"SHAPE"] ==
"BOX":
351 elif record[
"SHAPE"] ==
"POINT":
356 log.warning(
"Defect lists can only be defined using BOX not %s", record[
"SHAPE"])
359 elif "x0" in record
and "y0" in record
and "width" in record
and "height" in record:
364 defectList.append(box)
366 return cls(defectList)
370 """Read defect list from FITS table. 375 Arguments to be forwarded to 376 `lsst.afw.table.BaseCatalog.writeFits`. 381 Defects read from a FITS table. 383 table = lsst.afw.table.BaseCatalog.readFits(*args)
385 print(f
"Meta: {table.getMetadata()!r}")
386 defects.setMetadata(table.getMetadata())
391 """Read defects information from an LSST format text file. 396 Name of text file containing the defect information. 405 These defect text files are used as the human readable definitions 406 of defects in calibration data definition repositories. The format 407 is to use four columns defined as follows: 410 X coordinate of bottom left corner of box. 412 Y coordinate of bottom left corner of box. 420 defect_array = np.loadtxt(filename,
421 dtype=[(
"x0",
"int"), (
"y0",
"int"),
422 (
"x_extent",
"int"), (
"y_extent",
"int")])
426 for row
in defect_array)
430 """Compute a defect list from a footprint list, optionally growing 435 fpList : `list` of `lsst.afw.detection.Footprint` 436 Footprint list to process. 448 """Compute a defect list from a specified mask plane. 452 maskedImage : `lsst.afw.image.MaskedImage` 454 maskName : `str` or `list` 455 Mask plane name, or list of names to convert. 460 Defect list constructed from masked pixels. 462 mask = maskedImage.getMask()
464 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 fromMask(cls, maskedImage, maskName)