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: `MultibandImage` or list of `Image`, array 
   39         Images to extract the footprint from 
   41         All pixels above `thresh` will be included in the footprint 
   43         Location of the minimum value of the images bounding box 
   44         (if images is an array, otherwise the image bounding box is used). 
   49         Union of all spans in the images above the threshold 
   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: `MaskedImage` or `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 `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. 
  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: `MultibandImage`, or list of `Image` 
  196             A `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: `MultibandImage`, or list of `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. 
  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 `MaskedImage` 
  237             MaskedImages to extract the single band heavy footprints from. 
  238             Like `fromImage`, 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)