コード例 #1
0
    def testString(self):
        imageF = afwImage.ImageF(100, 100)
        imageDSmall = afwImage.ImageD(2, 2)
        imageISmall = afwImage.ImageI(2, 2)
        imageU = afwImage.ImageU(100, 100)

        # NumPy's string representation varies depending on the size of the
        # array; we test both large and small.
        self.assertIn(str(np.zeros((100, 100), dtype=imageF.dtype)),
                      str(imageF))
        self.assertIn("bbox=%s" % str(imageF.getBBox()), str(imageF))

        self.assertIn(str(np.zeros((2, 2), dtype=imageDSmall.dtype)),
                      str(imageDSmall))
        self.assertIn(str(np.zeros((2, 2), dtype=imageISmall.dtype)),
                      str(imageISmall))

        self.assertIn("ImageF=", repr(imageF))
        self.assertIn("ImageU=", repr(imageU))
コード例 #2
0
ファイル: interface.py プロジェクト: jchiang87/afw
    def mtv(self, data, title="", wcs=None):
        """!Display an Image or Mask on a DISPLAY display

        Historical note: the name "mtv" comes from Jim Gunn's forth imageprocessing
        system, Mirella (named after Mirella Freni); The "m" stands for Mirella.
        """
        if hasattr(data, "getXY0"):
            self._xy0 = data.getXY0()
        else:
            self._xy0 = None

        # it's an Exposure; display the MaskedImage with the WCS
        if isinstance(data, afwImage.Exposure):
            if wcs:
                raise RuntimeError(
                    "You may not specify a wcs with an Exposure")
            data, wcs = data.getMaskedImage(), data.getWcs()
        elif isinstance(
                data,
                afwImage.DecoratedImage):  # it's a DecoratedImage; display it
            try:
                wcs = afwGeom.makeSkyWcs(data.getMetadata())
            except TypeError:
                wcs = None
            data = data.image

            self._xy0 = data.getXY0()  # DecoratedImage doesn't have getXY0()

        if isinstance(data, afwImage.Image):  # it's an Image; display it
            self._impl._mtv(data, None, wcs, title)
        # it's a Mask; display it, bitplane by bitplane
        elif isinstance(data, afwImage.Mask):
            #
            # Some displays can't display a Mask without an image; so display an Image too,
            # with pixel values set to the mask
            #
            self._impl._mtv(afwImage.ImageI(data.getArray()), data, wcs, title)
        # it's a MaskedImage; display Image and overlay Mask
        elif isinstance(data, afwImage.MaskedImage):
            self._impl._mtv(data.getImage(), data.getMask(), wcs, title)
        else:
            raise RuntimeError("Unsupported type %s" % repr(data))
コード例 #3
0
    def testSubtractImages(self):
        "Test subtraction"
        # subtract an image
        self.mimage2 -= self.mimage
        self.assertEqual(self.mimage2.get(0, 0),
                         (self.imgVal2 - self.imgVal1, self.EDGE,
                          self.varVal2 + self.varVal1))

        # Subtract an Image<int> from a MaskedImage<int>
        mimage_i = afwImage.MaskedImageI(self.mimage2.getDimensions())
        mimage_i.set(900, 0x0, 1000.0)
        image_i = afwImage.ImageI(mimage_i.getDimensions(), 2)

        mimage_i -= image_i

        self.assertEqual(mimage_i.get(0, 0), (898, 0x0, 1000.0))

        # subtract a scalar
        self.mimage -= self.imgVal1
        self.assertEqual(self.mimage.get(0, 0), (0.0, self.EDGE, self.varVal1))
コード例 #4
0
    def run(self, mapperResults, exposure, **kwargs):
        """Reduce a list of items produced by `ImageMapperSubtask`.

        Either stitch the passed `mapperResults` list
        together into a new Exposure (default) or pass it through
        (if `self.config.reduceOperation` is 'none').

        If `self.config.reduceOperation` is not 'none', then expect
        that the `pipeBase.Struct`s in the `mapperResults` list
        contain sub-exposures named 'subExposure', to be stitched back
        into a single Exposure with the same dimensions, PSF, and mask
        as the input `exposure`. Otherwise, the `mapperResults` list
        is simply returned directly.

        Parameters
        ----------
        mapperResults : list
            list of `pipeBase.Struct` returned by `ImageMapperSubtask.run`.
        exposure : lsst.afw.image.Exposure
            the original exposure which is cloned to use as the
            basis for the resulting exposure (if
            self.config.mapperSubtask.reduceOperation is not 'none')
        kwargs :
            additional keyword arguments propagated from
            `ImageMapReduceTask.run`.

        Returns
        -------
        A `pipeBase.Struct` containing either an `lsst.afw.image.Exposure` (named 'exposure')
        or a list (named 'result'), depending on `config.reduceOperation`.

        Notes
        -----
        1. This currently correctly handles overlapping sub-exposures.
           For overlapping sub-exposures, use `config.reduceOperation='average'`.
        2. This correctly handles varying PSFs, constructing the resulting
           exposure's PSF via CoaddPsf (DM-9629).

        Known issues
        ------------
        1. To be done: correct handling of masks (nearly there)
        2. This logic currently makes *two* copies of the original exposure
           (one here and one in `mapperSubtask.run()`). Possibly of concern
           for large images on memory-constrained systems.
        """
        # No-op; simply pass mapperResults directly to ImageMapReduceTask.run
        if self.config.reduceOperation == 'none':
            return pipeBase.Struct(result=mapperResults)

        if self.config.reduceOperation == 'coaddPsf':
            # Each element of `mapperResults` should contain 'psf' and 'bbox'
            coaddPsf = self._constructPsf(mapperResults, exposure)
            return pipeBase.Struct(result=coaddPsf)

        newExp = exposure.clone()
        newMI = newExp.getMaskedImage()

        reduceOp = self.config.reduceOperation
        if reduceOp == 'copy':
            weights = None
            newMI.getImage()[:, :] = np.nan
            newMI.getVariance()[:, :] = np.nan
        else:
            newMI.getImage()[:, :] = 0.
            newMI.getVariance()[:, :] = 0.
            if reduceOp == 'average':  # make an array to keep track of weights
                weights = afwImage.ImageI(newMI.getBBox())

        for item in mapperResults:
            item = item.subExposure  # Expected named value in the pipeBase.Struct
            if not (isinstance(item, afwImage.ExposureF) or isinstance(item, afwImage.ExposureI) or
                    isinstance(item, afwImage.ExposureU) or isinstance(item, afwImage.ExposureD)):
                raise TypeError("""Expecting an Exposure type, got %s.
                                   Consider using `reduceOperation="none".""" % str(type(item)))
            subExp = newExp.Factory(newExp, item.getBBox())
            subMI = subExp.getMaskedImage()
            patchMI = item.getMaskedImage()
            isValid = ~np.isnan(patchMI.getImage().getArray() * patchMI.getVariance().getArray())

            if reduceOp == 'copy':
                subMI.getImage().getArray()[isValid] = patchMI.getImage().getArray()[isValid]
                subMI.getVariance().getArray()[isValid] = patchMI.getVariance().getArray()[isValid]
                subMI.getMask().getArray()[:, :] |= patchMI.getMask().getArray()

            if reduceOp == 'sum' or reduceOp == 'average':  # much of these two options is the same
                subMI.getImage().getArray()[isValid] += patchMI.getImage().getArray()[isValid]
                subMI.getVariance().getArray()[isValid] += patchMI.getVariance().getArray()[isValid]
                subMI.getMask().getArray()[:, :] |= patchMI.getMask().getArray()
                if reduceOp == 'average':
                    # wtsView is a view into the `weights` Image
                    wtsView = afwImage.ImageI(weights, item.getBBox())
                    wtsView.getArray()[isValid] += 1

        # New mask plane - for debugging map-reduced images
        mask = newMI.getMask()
        for m in self.config.badMaskPlanes:
            mask.addMaskPlane(m)
        bad = mask.getPlaneBitMask(self.config.badMaskPlanes)

        isNan = np.where(np.isnan(newMI.getImage().getArray() * newMI.getVariance().getArray()))
        if len(isNan[0]) > 0:
            # set mask to INVALID for pixels where produced exposure is NaN
            mask.getArray()[isNan[0], isNan[1]] |= bad

        if reduceOp == 'average':
            wts = weights.getArray().astype(np.float)
            self.log.info('AVERAGE: Maximum overlap: %f', np.nanmax(wts))
            self.log.info('AVERAGE: Average overlap: %f', np.nanmean(wts))
            self.log.info('AVERAGE: Minimum overlap: %f', np.nanmin(wts))
            wtsZero = np.equal(wts, 0.)
            wtsZeroInds = np.where(wtsZero)
            wtsZeroSum = len(wtsZeroInds[0])
            self.log.info('AVERAGE: Number of zero pixels: %f (%f%%)', wtsZeroSum,
                          wtsZeroSum * 100. / wtsZero.size)
            notWtsZero = ~wtsZero
            tmp = newMI.getImage().getArray()
            np.divide(tmp, wts, out=tmp, where=notWtsZero)
            tmp = newMI.getVariance().getArray()
            np.divide(tmp, wts, out=tmp, where=notWtsZero)
            if len(wtsZeroInds[0]) > 0:
                newMI.getImage().getArray()[wtsZeroInds] = np.nan
                newMI.getVariance().getArray()[wtsZeroInds] = np.nan
                # set mask to something for pixels where wts == 0.
                # happens sometimes if operation failed on a certain subexposure
                mask.getArray()[wtsZeroInds] |= bad

        # Not sure how to construct a PSF when reduceOp=='copy'...
        if reduceOp == 'sum' or reduceOp == 'average':
            psf = self._constructPsf(mapperResults, exposure)
            newExp.setPsf(psf)

        return pipeBase.Struct(exposure=newExp)