22__all__ = [
'CalexpCutoutTaskConfig',
'CalexpCutoutTask']
29DETECTOR_DIMENSIONS = (
'instrument',
'visit',
'detector')
33 dimensions=DETECTOR_DIMENSIONS,
35 """Connections class for CalexpCutoutTask
37 in_table = pipeBase.connectionTypes.Input(
38 doc="Locations for cutouts",
39 name=
"cutout_positions",
40 storageClass=
"AstropyQTable",
41 dimensions=DETECTOR_DIMENSIONS,
43 calexp = pipeBase.connectionTypes.Input(
46 storageClass=
"ExposureF",
47 dimensions=DETECTOR_DIMENSIONS,
49 cutouts = pipeBase.connectionTypes.Output(
51 name=
"calexp_cutouts",
52 storageClass=
"Stamps",
53 dimensions=DETECTOR_DIMENSIONS,
58 pipelineConnections=CalexpCutoutTaskConnections):
59 """Configuration for CalexpCutoutTask
61 max_cutouts = Field(dtype=int, default=100, doc='Maximum number of entries to process. '
62 'The result will be the first N in the input table.')
63 skip_bad = Field(dtype=bool, default=
True, doc=
'Skip cutouts that do not fall completely within'
64 ' the calexp bounding box? If set to False a ValueError'
65 ' is raised instead.')
69 """Task for computing cutouts on a specific calexp given
70 positions, xspans, and yspans of the stamps.
72 ConfigClass = CalexpCutoutTaskConfig
73 _DefaultName = "calexpCutoutTask"
75 def run(self, in_table, calexp):
76 """Compute and return the cutouts.
80 in_table : `astropy.QTable`
81 A table containing at least the following columns: position, xspan
82 and yspan. The position should be an `astropy.SkyCoord`. The
83 xspan
and yspan are the extent of the cutout
in x
and y
in pixels.
84 calexp : `lsst.afw.image.ExposureF`
85 The calibrated exposure
from which to extract cutouts
89 output : `lsst.pipe.base.Struct`
92 * cutouts: an `lsst.meas.algorithms.Stamps` object
93 that wraps a list of masked images of the cutouts
and a
94 `PropertyList` containing the metadata to be persisted
95 with the cutouts. The exposure metadata
is preserved
and,
96 in addition, arrays holding the RA
and Dec of each stamp
97 in degrees are added to the metadata. Note: the origin
98 of the output stamps
is `lsst.afw.image.PARENT`.
100 stamps that were skiped
for being off the image
101 or partially off the image
106 If the input catalog doesn
't have the required columns,
107 a ValueError is raised
109 cols = in_table.colnames
110 if 'position' not in cols
or 'xspan' not in cols
or 'yspan' not in cols:
111 raise ValueError(
'Required column missing from the input table. '
112 'Required columns are "position", "xspan", and "yspan". '
113 f
'The column names are: {in_table.colnames}')
114 wcs = calexp.getWcs()
116 raise RuntimeError(
"Calexp has no WCS, so cannot compute sky positions.")
117 max_idx = self.config.max_cutouts
119 mim = calexp.getMaskedImage()
122 skipped_positions = []
123 for rec
in in_table[:max_idx]:
124 ra = rec[
'position'].ra.degree
125 dec = rec[
'position'].dec.degree
130 pix = wcs.skyToPixel(pt)
131 xspan = rec[
'xspan'].value
132 yspan = rec[
'yspan'].value
136 if not mim.getBBox().contains(box):
137 if not self.config.skip_bad:
138 raise ValueError(f
'Cutout bounding box is not completely contained in the image: {box}')
140 skipped_positions.append(pt)
142 sub = mim.Factory(mim, box)
143 stamp = Stamp(stamp_im=sub, position=pt)
144 cutout_list.append(stamp)
145 metadata = calexp.getMetadata()
146 metadata[
'RA_DEG'] = ras
147 metadata[
'DEC_DEG'] = decs
148 return pipeBase.Struct(cutouts=Stamps(cutout_list, metadata=metadata),
149 skipped_positions=skipped_positions)