22 __all__ = [
"MultibandFootprint"]
28 from lsst.afw.image import Mask, Image, MaskedImage, MultibandImage, MultibandMaskedImage
30 from .
import Footprint, makeHeavyFootprint
34 """Create a Footprint from a set of Images
38 images : `lsst.afw.image.MultibandImage` or list of `lsst.afw.image.Image`, array
39 Images to extract the footprint from
41 All pixels above `thresh` will be included in the footprint
42 xy0 : `lsst.geom.Point2I`
43 Location of the minimum value of the images bounding box
44 (if images is an array, otherwise the image bounding box is used).
48 spans : `lsst.afw.geom.SpanSet`
49 Union of all spans in the images above the threshold
50 imageBBox : `lsst.afw.detection.Box2I`
51 Bounding box for the input images.
54 if not hasattr(thresh,
"__len__"):
55 thresh = [thresh] * len(images)
59 if isinstance(images, MultibandBase)
or isinstance(images[0], Image):
61 for n, image
in enumerate(images):
62 mask = image.array > thresh[n]
63 mask =
Mask(mask.astype(np.int32), xy0=image.getBBox().getMin())
64 spans = spans.union(SpanSet.fromMask(mask))
65 imageBBox = images[0].getBBox()
68 thresh = np.array(thresh)
71 mask = np.any(images > thresh[:,
None,
None], axis=0)
72 mask =
Mask(mask.astype(np.int32), xy0=xy0)
73 spans = SpanSet.fromMask(mask)
74 imageBBox = mask.getBBox()
75 return spans, imageBBox
79 """Create an image of a HeavyFootprint
83 heavy : `HeavyFootprint`
84 The HeavyFootprint to insert into the image
86 Number to fill the pixels in the image that are not
89 Bounding box of the output image.
91 This should be either a `MaskedImage` or `Image` and describes
92 the type of the output image.
96 image : `lsst.afw.image.MaskedImage` or `lsst.afw.image.Image`
97 An image defined by `bbox` and padded with `fill` that
98 contains the projected flux in `heavy`.
101 bbox = heavy.getBBox()
102 image = imageType(bbox, dtype=heavy.getImageArray().dtype)
109 """Multiband Footprint class
111 A `MultibandFootprint` is a collection of HeavyFootprints that have
112 the same `SpanSet` and `peakCatalog` but different flux in each band.
117 List of filter names.
119 A list of single band `HeavyFootprint` objects.
120 Each `HeavyFootprint` should have the same `PeakCatalog`
121 and the same `SpanSet`, however to save CPU cycles there
122 is no internal check for consistency of the peak catalog.
128 if not all([heavy.getSpans() == spans
for heavy
in singles]):
129 raise ValueError(
"All HeavyFootprints in singles are expected to have the same SpanSet")
133 footprint.setPeakCatalog(singles[0].
getPeaks())
137 def fromArrays(filters, image, mask=None, variance=None, footprint=None, xy0=None, thresh=0, peaks=None):
138 """Create a `MultibandFootprint` from an `image`, `mask`, `variance`
143 List of filter names.
145 An array to convert into `lsst.afw.detection.HeavyFootprint` objects.
146 Only pixels above the `thresh` value for at least one band
147 will be included in the `SpanSet` and resulting footprints.
149 Mask for the `image` array.
151 Variance of the `image` array.
152 footprint : `Footprint`
153 `Footprint` that contains the `SpanSet` and `PeakCatalog`
154 to use for the `HeavyFootprint` in each band.
155 If `footprint` is `None` then the `thresh` is used to create a
156 `Footprint` based on the pixels above the `thresh` value.
158 If `image` is an array and `footprint` is `None` then specifying
159 `xy0` gives the location of the minimum `x` and `y` value of the
161 thresh : `float` or list of floats
162 Threshold in each band (or the same threshold to be used in all bands)
163 to include a pixel in the `SpanSet` of the `MultibandFootprint`.
164 If `Footprint` is not `None` then `thresh` is ignored.
165 peaks : `PeakCatalog`
166 Catalog containing information about the peaks located in the
171 result : `MultibandFootprint`
172 MultibandFootprint created from the arrays
175 if footprint
is None:
179 imageBBox = footprint.getBBox()
181 if peaks
is not None:
182 footprint.setPeakCatalog(peaks)
183 mMaskedImage = MultibandMaskedImage.fromArrays(filters, image, mask, variance, imageBBox)
184 singles = [
makeHeavyFootprint(footprint, maskedImage)
for maskedImage
in mMaskedImage]
188 def fromImages(filters, image, mask=None, variance=None, footprint=None, thresh=0, peaks=None):
189 """Create a `MultibandFootprint` from an `image`, `mask`, `variance`
194 List of filter names.
195 image : `lsst.afw.image.MultibandImage`, or list of `lsst.afw.image.Image`
196 A `lsst.afw.image.MultibandImage` (or collection of images in each band)
197 to convert into `HeavyFootprint` objects.
198 Only pixels above the `thresh` value for at least one band
199 will be included in the `SpanSet` and resulting footprints.
200 mask : `MultibandMask` or list of `Mask`
201 Mask for the `image`.
202 variance : `lsst.afw.image.MultibandImage`, or list of `lsst.afw.image.Image`
203 Variance of the `image`.
204 thresh : `float` or `list` of floats
205 Threshold in each band (or the same threshold to be used in all bands)
206 to include a pixel in the `SpanSet` of the `MultibandFootprint`.
207 If `Footprint` is not `None` then `thresh` is ignored.
208 peaks : `PeakCatalog`
209 Catalog containing information about the peaks located in the
214 result : `MultibandFootprint`
215 MultibandFootprint created from the image, mask, and variance
218 if footprint
is None:
222 if peaks
is not None:
223 footprint.setPeakCatalog(peaks)
225 singles = [
makeHeavyFootprint(footprint, maskedImage)
for maskedImage
in mMaskedImage]
230 """Create a `MultibandFootprint` from a list of `MaskedImage`
232 See `fromImages` for a description of the parameters not listed below
236 maskedImages : `list` of `lsst.afw.image.MaskedImage`
237 MaskedImages to extract the single band heavy footprints from.
238 Like `fromImages`, if a `footprint` is not specified then all
239 pixels above `thresh` will be used, and `peaks` will be added
240 to the `PeakCatalog`.
244 result : `MultibandFootprint`
245 MultibandFootprint created from the image, mask, and variance
247 image = [maskedImage.image
for maskedImage
in maskedImages]
248 mask = [maskedImage.mask
for maskedImage
in maskedImages]
249 variance = [maskedImage.variance
for maskedImage
in maskedImages]
250 return MultibandFootprint.fromImages(filters, image, mask, variance, footprint, thresh, peaks)
253 """Get the full `SpanSet`"""
258 """Common SpanSet and peak catalog for the single band footprints"""
263 """MultibandMaskedImage that the footprints present a view into"""
264 return self._mMaskedImage
268 """`SpanSet` of the `MultibandFootprint`"""
272 """Get the `PeakCatalog`"""
277 """`PeakCatalog` of the `MultibandFootprint`"""
280 def _slice(self, filters, filterIndex, indices):
281 """Slice the current object and return the result
283 `MultibandFootprint` objects cannot be sliced along the image
284 dimension, so an error is thrown if `indices` has any elements.
286 See `Multiband._slice` for a list of the parameters.
289 raise IndexError(
"MultibandFootprints can only be sliced in the filter dimension")
291 if isinstance(filterIndex, slice):
292 singles = self.
singles[filterIndex]
294 singles = [self.
singles[idx]
for idx
in filterIndex]
298 def getImage(self, bbox=None, fill=np.nan, imageType=MultibandMaskedImage):
299 """Convert a `MultibandFootprint` to a `MultibandImage`
301 This returns the heavy footprints converted into an `MultibandImage` or
302 `MultibandMaskedImage` (depending on `imageType`).
303 This might be different than the internal `mMaskedImage` property
304 of the `MultibandFootprint`, as the `mMaskedImage` might contain
305 some non-zero pixels not contained in the footprint but present in
311 Bounding box of the resulting image.
312 If no bounding box is specified, then the bounding box
313 of the footprint is used.
315 Value to use for any pixel in the resulting image
316 outside of the `SpanSet`.
318 This should be either a `MultibandMaskedImage`
319 or `MultibandImage` and describes the type of the output image.
323 result : `MultibandBase`
324 The resulting `MultibandImage` or `MultibandMaskedImage` created
325 from the `MultibandHeavyFootprint`.
327 if imageType == MultibandMaskedImage:
328 singleType = MaskedImage
329 elif imageType == MultibandImage:
332 raise TypeError(
"Expected imageType to be either MultibandImage or MultibandMaskedImage")
334 mMaskedImage = imageType.fromImages(self.
filters, maskedImages)
338 """Copy the current object
343 Whether or not to make a deep copy
347 result : `MultibandFootprint`
348 The cloned footprint.
353 footprint.addPeak(peak.getX(), peak.getY(), peak.getValue())
355 filters = tuple([f
for f
in self.
filters])
356 result = MultibandFootprint.fromMaskedImages(filters, mMaskedImage, footprint)