75 def run(self, in_table, calexp):
76 """Compute and return the cutouts.
77
78 Parameters
79 ----------
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
86
87 Returns
88 -------
89 output : `lsst.pipe.base.Struct`
90 A struct containing:
91
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`.
99 * skipped_positions: a `list` of `lsst.geom.SpherePoint` objects for
100 stamps that were skiped for being off the image
101 or partially off the image
102
103 Raises
104 ------
105 ValueError
106 If the input catalog doesn't have the required columns,
107 a ValueError is raised
108 """
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()
115 if wcs is None:
116 raise RuntimeError("Calexp has no WCS, so cannot compute sky positions.")
117 max_idx = self.config.max_cutouts
118 cutout_list = []
119 mim = calexp.getMaskedImage()
120 ras = []
121 decs = []
122 skipped_positions = []
123 for rec in in_table[:max_idx]:
124 ra = rec['position'].ra.degree
125 dec = rec['position'].dec.degree
126 ras.append(ra)
127 decs.append(dec)
130 pix = wcs.skyToPixel(pt)
131 xspan = rec['xspan'].value
132 yspan = rec['yspan'].value
133
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}')
139 else:
140 skipped_positions.append(pt)
141 continue
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)
A class representing an angle.
An integer coordinate rectangle.
Point in an unspecified spherical coordinate system.