Ejemplo n.º 1
0
    def checkEdge(self, footprint):
        """Check that Footprint::findEdgePixels() works"""
        bbox = footprint.getBBox()
        bbox.grow(3)

        def makeImage(footprint):
            """Make an ImageF with 1 in the footprint, and 0 elsewhere"""
            ones = afwImage.ImageI(bbox)
            ones.set(1)
            image = afwImage.ImageI(bbox)
            image.set(0)
            afwDetect.copyWithinFootprintImage(footprint, ones, image)
            return image

        edges = self.foot.findEdgePixels()
        edgeImage = makeImage(edges)

        # Find edges with an edge-detection kernel
        image = makeImage(self.foot)
        kernel = afwImage.ImageD(3, 3)
        kernel.set(1, 1, 4)
        for x, y in [(1, 2), (0, 1), (1, 0), (2, 1)]:
            kernel.set(x, y, -1)
        kernel.setXY0(1, 1)
        result = afwImage.ImageI(bbox)
        result.set(0)
        afwMath.convolve(result, image, afwMath.FixedKernel(kernel), afwMath.ConvolutionControl(False))
        result.getArray().__imul__(image.getArray())
        trueEdges = numpy.where(result.getArray() > 0, 1, 0)

        self.assertTrue(numpy.all(trueEdges == edgeImage.getArray()))
Ejemplo n.º 2
0
    def checkEdge(self, footprint):
        """Check that Footprint::findEdgePixels() works"""
        bbox = footprint.getBBox()
        bbox.grow(3)

        def makeImage(area):
            """Make an ImageF with 1 in the footprint, and 0 elsewhere"""
            ones = afwImage.ImageI(bbox)
            ones.set(1)
            image = afwImage.ImageI(bbox)
            image.set(0)
            if isinstance(area, afwDetect.Footprint):
                area.spans.copyImage(ones, image)
            if isinstance(area, afwGeom.SpanSet):
                area.copyImage(ones, image)
            return image

        edges = self.foot.spans.findEdgePixels()
        edgeImage = makeImage(edges)

        # Find edges with an edge-detection kernel
        image = makeImage(self.foot)
        kernel = afwImage.ImageD(3, 3)
        kernel[1, 1, afwImage.LOCAL] = 4
        for x, y in [(1, 2), (0, 1), (1, 0), (2, 1)]:
            kernel[x, y, afwImage.LOCAL] = -1
        kernel.setXY0(1, 1)
        result = afwImage.ImageI(bbox)
        result.set(0)
        afwMath.convolve(result, image, afwMath.FixedKernel(kernel),
                         afwMath.ConvolutionControl(False))
        result.getArray().__imul__(image.getArray())
        trueEdges = np.where(result.getArray() > 0, 1, 0)

        self.assertTrue(np.all(trueEdges == edgeImage.getArray()))
    def setUp(self):
        self.config = ipDiffim.ImagePsfMatchTask.ConfigClass()
        self.subconfig = self.config.kernel.active
        self.policy = pexConfig.makePolicy(self.subconfig)
        self.kSize = self.policy.getInt('kernelSize')

        # gaussian reference kernel
        self.gSize = self.kSize
        self.gaussFunction = afwMath.GaussianFunction2D(2, 3)
        self.gaussKernel = afwMath.AnalyticKernel(self.gSize, self.gSize,
                                                  self.gaussFunction)

        # known input images
        try:
            self.defDataDir = lsst.utils.getPackageDir('afwdata')
        except Exception:
            self.defDataDir = None

        if self.defDataDir:
            defImagePath = os.path.join(self.defDataDir, "DC3a-Sim", "sci",
                                        "v5-e0", "v5-e0-c011-a00.sci.fits")
            self.templateImage = afwImage.MaskedImageF(defImagePath)
            self.scienceImage = self.templateImage.Factory(
                self.templateImage.getDimensions())

            afwMath.convolve(self.scienceImage, self.templateImage,
                             self.gaussKernel, False)
    def _doConvolve(exposure, kernel):
        """Convolve an Exposure with a decorrelation convolution kernel.

        Parameters
        ----------
        exposure : `lsst.afw.image.Exposure`
            Input exposure to be convolved.
        kernel : `numpy.array`
            Input 2-d numpy.array to convolve the image with

        Returns
        -------
        out : `lsst.afw.image.Exposure`
            a new Exposure with the convolved pixels and the (possibly
            re-centered) kernel.

        Notes
        -----
        We re-center the kernel if necessary and return the possibly re-centered kernel
        """
        kernelImg = afwImage.ImageD(kernel.shape[0], kernel.shape[1])
        kernelImg.getArray()[:, :] = kernel
        kern = afwMath.FixedKernel(kernelImg)
        maxloc = np.unravel_index(np.argmax(kernel), kernel.shape)
        kern.setCtrX(maxloc[0])
        kern.setCtrY(maxloc[1])
        outExp = exposure.clone()  # Do this to keep WCS, PSF, masks, etc.
        convCntrl = afwMath.ConvolutionControl(False, True, 0)
        afwMath.convolve(outExp.getMaskedImage(), exposure.getMaskedImage(), kern, convCntrl)

        return outExp, kern
Ejemplo n.º 5
0
def main():

    gaussFunction = afwMath.GaussianFunction2D(3, 2, 0.5)
    gaussKernel = afwMath.AnalyticKernel(10, 10, gaussFunction)
    inImage = afwImage.ImageF(afwGeom.Extent2I(100, 100))
    inImage.set(1)
    if disp:
        ds9.mtv(inImage, frame = 0)

    # works
    outImage = afwImage.ImageF(afwGeom.Extent2I(100, 100))
    afwMath.convolve(outImage, inImage, gaussKernel, False, True)
    if disp:
        ds9.mtv(outImage, frame = 1)
    print("Should be a number: ", afwMath.makeStatistics(
        outImage, afwMath.MEAN).getValue())
    print("Should be a number: ", afwMath.makeStatistics(
        outImage, afwMath.STDEV).getValue())

    # not works ... now does work
    outImage = afwImage.ImageF(afwGeom.Extent2I(100, 100))
    afwMath.convolve(outImage, inImage, gaussKernel, False, False)
    if disp:
        ds9.mtv(outImage, frame = 2)
    print("Should be a number: ", afwMath.makeStatistics(
        outImage, afwMath.MEAN).getValue())
    print("Should be a number: ", afwMath.makeStatistics(
        outImage, afwMath.STDEV).getValue())

    # This will print nan
    sctrl = afwMath.StatisticsControl()
    sctrl.setNanSafe(False)
    print ("Should be a nan (nanSafe set to False): " +
           str(afwMath.makeStatistics(outImage, afwMath.MEAN, sctrl).getValue()))
Ejemplo n.º 6
0
    def testUnityConvolution(self):
        """Verify that convolution with a centered delta function reproduces the original.
        """
        # create a delta function kernel that has 1,1 in the center
        kFunc = afwMath.IntegerDeltaFunction2D(0.0, 0.0)
        kernel = afwMath.AnalyticKernel(3, 3, kFunc)
        doNormalize = False
        doCopyEdge = False

        afwMath.convolve(self.cnvImage, self.maskedImage.getImage(), kernel, doNormalize, doCopyEdge)
        cnvImArr = self.cnvImage.getArray()
        
        afwMath.convolve(self.cnvMaskedImage, self.maskedImage, kernel, doNormalize, doCopyEdge)
        cnvImMaskVarArr = self.cnvMaskedImage.getArrays()

        refCnvImMaskVarArr = self.maskedImage.getArrays()
        
        skipMaskArr = numpy.isnan(cnvImMaskVarArr[0])

        kernelDescr = "Centered DeltaFunctionKernel (testing unity convolution)"
        errStr = imTestUtils.imagesDiffer(cnvImArr, refCnvImMaskVarArr[0], skipMaskArr=skipMaskArr)
        if errStr:
            self.fail("convolve(Image, kernel=%s, doNormalize=%s, doCopyEdge=%s) failed:\n%s" % \
                (kernelDescr, doNormalize, doCopyEdge, errStr))
        errStr = imTestUtils.maskedImagesDiffer(cnvImMaskVarArr, refCnvImMaskVarArr, skipMaskArr=skipMaskArr)
        if errStr:
            self.fail("convolve(MaskedImage, kernel=%s, doNormalize=%s, doCopyEdge=%s) failed:\n%s" % \
                (kernelDescr, doNormalize, doCopyEdge, errStr))
        self.assert_(sameMaskPlaneDicts(self.cnvMaskedImage, self.maskedImage),
            "convolve(MaskedImage, kernel=%s, doNormalize=%s, doCopyEdge=%s) failed:\n%s" % \
            (kernelDescr, doNormalize, doCopyEdge, "convolved mask dictionary does not match input"))
    def testGood(self):
        ti = afwImage.MaskedImageF(afwGeom.Extent2I(100, 100))
        ti.getVariance().set(0.1)
        ti.set(50, 50, (1., 0x0, 1.))
        sKernel = self.makeSpatialKernel(2)
        si = afwImage.MaskedImageF(ti.getDimensions())
        afwMath.convolve(si, ti, sKernel, True)

        bbox = afwGeom.Box2I(afwGeom.Point2I(25, 25),
                             afwGeom.Point2I(75, 75))
        si   = afwImage.MaskedImageF(si, bbox, afwImage.LOCAL)
        ti   = afwImage.MaskedImageF(ti, bbox, afwImage.LOCAL)
        kc   = ipDiffim.KernelCandidateF(50., 50., ti, si, self.policy)

        sBg      = afwMath.PolynomialFunction2D(1)
        bgCoeffs = [0., 0., 0.]
        sBg.setParameters(bgCoeffs)

        # must be initialized
        bskv = ipDiffim.BuildSingleKernelVisitorF(self.kList, self.policy)
        bskv.processCandidate(kc)
        self.assertEqual(kc.isInitialized(), True)
        #ds9.mtv(kc.getTemplateMaskedImage(), frame=1)
        #ds9.mtv(kc.getScienceMaskedImage(), frame=2)
        #ds9.mtv(kc.getKernelImage(ipDiffim.KernelCandidateF.RECENT), frame=3)
        #ds9.mtv(kc.getDifferenceImage(ipDiffim.KernelCandidateF.RECENT), frame=4)
        
        askv = ipDiffim.AssessSpatialKernelVisitorF(sKernel, sBg, self.policy)
        askv.processCandidate(kc)
        
        self.assertEqual(askv.getNProcessed(), 1)
        self.assertEqual(askv.getNRejected(), 0)
        self.assertEqual(kc.getStatus(), afwMath.SpatialCellCandidate.GOOD)
Ejemplo n.º 8
0
    def run(self, exposure, referencePsfModel, kernelSum=1.0):
        """!Psf-match an exposure to a model Psf

        @param exposure: Exposure to Psf-match to the reference Psf model;
            it must return a valid PSF model via exposure.getPsf()
        @param referencePsfModel: The Psf model to match to (an lsst.afw.detection.Psf)
        @param kernelSum: A multipicative factor to apply to the kernel sum (default=1.0)

        @return
        - psfMatchedExposure: the Psf-matched Exposure.  This has the same parent bbox, Wcs, Calib and
            Filter as the input Exposure but no Psf.  In theory the Psf should equal referencePsfModel but
            the match is likely not exact.
        - psfMatchingKernel: the spatially varying Psf-matching kernel
        - kernelCellSet: SpatialCellSet used to solve for the Psf-matching kernel
        - referencePsfModel: Validated and/or modified reference model used

        Raise a RuntimeError if the Exposure does not contain a Psf model
        """
        if not exposure.hasPsf():
            raise RuntimeError("exposure does not contain a Psf model")

        maskedImage = exposure.getMaskedImage()

        self.log.info("compute Psf-matching kernel")
        result = self._buildCellSet(exposure, referencePsfModel)
        kernelCellSet = result.kernelCellSet
        referencePsfModel = result.referencePsfModel
        fwhmScience = exposure.getPsf().computeShape().getDeterminantRadius() * sigma2fwhm
        fwhmModel = referencePsfModel.computeShape().getDeterminantRadius() * sigma2fwhm

        basisList = makeKernelBasisList(self.kConfig, fwhmScience, fwhmModel, metadata=self.metadata)
        spatialSolution, psfMatchingKernel, backgroundModel = self._solve(kernelCellSet, basisList)

        if psfMatchingKernel.isSpatiallyVarying():
            sParameters = np.array(psfMatchingKernel.getSpatialParameters())
            sParameters[0][0] = kernelSum
            psfMatchingKernel.setSpatialParameters(sParameters)
        else:
            kParameters = np.array(psfMatchingKernel.getKernelParameters())
            kParameters[0] = kernelSum
            psfMatchingKernel.setKernelParameters(kParameters)

        self.log.info("Psf-match science exposure to reference")
        psfMatchedExposure = afwImage.ExposureF(exposure.getBBox(), exposure.getWcs())
        psfMatchedExposure.setFilter(exposure.getFilter())
        psfMatchedExposure.setCalib(exposure.getCalib())
        psfMatchedExposure.setPsf(referencePsfModel)
        psfMatchedMaskedImage = psfMatchedExposure.getMaskedImage()

        # Normalize the psf-matching kernel while convolving since its magnitude is meaningless
        # when PSF-matching one model to another.
        doNormalize = True
        afwMath.convolve(psfMatchedMaskedImage, maskedImage, psfMatchingKernel, doNormalize)

        self.log.info("done")
        return pipeBase.Struct(psfMatchedExposure=psfMatchedExposure,
                               psfMatchingKernel=psfMatchingKernel,
                               kernelCellSet=kernelCellSet,
                               metadata=self.metadata,
                               )
Ejemplo n.º 9
0
def main():
    
    gaussFunction = afwMath.GaussianFunction2D(3, 2, 0.5)
    gaussKernel   = afwMath.AnalyticKernel(10, 10, gaussFunction)
    inImage       = afwImage.ImageF(afwGeom.Extent2I(100, 100))
    inImage.set(1)
    if disp:
        ds9.mtv(inImage, frame = 0)
    
    # works
    outImage      = afwImage.ImageF(afwGeom.Extent2I(100, 100))
    afwMath.convolve(outImage, inImage, gaussKernel, False, True)
    if disp:
        ds9.mtv(outImage, frame = 1)
    print "Should be a number: ", afwMath.makeStatistics(outImage, afwMath.MEAN).getValue()
    print "Should be a number: ", afwMath.makeStatistics(outImage, afwMath.STDEV).getValue()
    
    # not works ... now does work
    outImage      = afwImage.ImageF(afwGeom.Extent2I(100, 100))
    afwMath.convolve(outImage, inImage, gaussKernel, False, False)
    if disp:
        ds9.mtv(outImage, frame = 2)
    print "Should be a number: ", afwMath.makeStatistics(outImage, afwMath.MEAN).getValue()
    print "Should be a number: ", afwMath.makeStatistics(outImage, afwMath.STDEV).getValue()

    # This will print nan
    sctrl = afwMath.StatisticsControl()
    sctrl.setNanSafe(False)
    print ("Should be a nan (nanSafe set to False): " +
           str(afwMath.makeStatistics(outImage, afwMath.MEAN, sctrl).getValue()))
    def testGaussianWithNoise(self):
        # Convolve a real image with a gaussian and try and recover
        # it.  Add noise and perform the same test.

        gsize = self.ps["kernelSize"]
        gaussFunction = afwMath.GaussianFunction2D(2, 3)
        gaussKernel = afwMath.AnalyticKernel(gsize, gsize, gaussFunction)
        kImageIn = afwImage.ImageD(geom.Extent2I(gsize, gsize))
        kSumIn = gaussKernel.computeImage(kImageIn, False)

        imX, imY = self.templateExposure2.getMaskedImage().getDimensions()
        smi = afwImage.MaskedImageF(geom.Extent2I(imX, imY))
        afwMath.convolve(smi, self.templateExposure2.getMaskedImage(), gaussKernel, False)

        bbox = gaussKernel.shrinkBBox(smi.getBBox(afwImage.LOCAL))

        tmi2 = afwImage.MaskedImageF(self.templateExposure2.getMaskedImage(), bbox, origin=afwImage.LOCAL)
        smi2 = afwImage.MaskedImageF(smi, bbox, origin=afwImage.LOCAL)

        kc = ipDiffim.KernelCandidateF(self.x02, self.y02, tmi2, smi2, self.ps)
        kList = ipDiffim.makeKernelBasisList(self.subconfig)
        kc.build(kList)
        self.assertEqual(kc.isInitialized(), True)
        kImageOut = kc.getImage()

        soln = kc.getKernelSolution(ipDiffim.KernelCandidateF.RECENT)
        self.assertAlmostEqual(soln.getKsum(), kSumIn)
        # 8.7499380640430563e-06 != 0.0 within 7 places
        self.assertAlmostEqual(soln.getBackground(), 0.0, 4)

        for j in range(kImageOut.getHeight()):
            for i in range(kImageOut.getWidth()):

                # in the outskirts of the kernel, the ratio can get screwed because of low S/N
                # e.g. 7.45817359824e-09 vs. 1.18062529402e-08
                # in the guts of the kernel it should look closer
                if kImageIn[i, j, afwImage.LOCAL] > 1e-4:
                    # sigh, too bad this sort of thing fails..
                    # 0.99941584433815966 != 1.0 within 3 places
                    self.assertAlmostEqual(kImageOut[i, j, afwImage.LOCAL]/kImageIn[i, j, afwImage.LOCAL],
                                           1.0, 2)

        # now repeat with noise added; decrease precision of comparison
        self.addNoise(smi2)
        kc = ipDiffim.KernelCandidateF(self.x02, self.y02, tmi2, smi2, self.ps)
        kList = ipDiffim.makeKernelBasisList(self.subconfig)
        kc.build(kList)
        self.assertEqual(kc.isInitialized(), True)
        kImageOut = kc.getImage()

        soln = kc.getKernelSolution(ipDiffim.KernelCandidateF.RECENT)
        self.assertAlmostEqual(soln.getKsum(), kSumIn, 3)
        if not self.ps.get("fitForBackground"):
            self.assertEqual(soln.getBackground(), 0.0)

        for j in range(kImageOut.getHeight()):
            for i in range(kImageOut.getWidth()):
                if kImageIn[i, j, afwImage.LOCAL] > 1e-2:
                    self.assertAlmostEqual(kImageOut[i, j, afwImage.LOCAL],
                                           kImageIn[i, j, afwImage.LOCAL], 2)
Ejemplo n.º 11
0
def doConvolve(exposure, kernel, use_scipy=False, fix_kernel=False):
    """! Convolve an Exposure with a decorrelation convolution kernel.
    @param exposure Input afw.image.Exposure to be convolved.
    @param kernel Input 2-d numpy.array to convolve the image with
    @param use_scipy Use scipy to do convolution instead of afwMath
    @return a new Exposure with the convolved pixels and the (possibly
    re-centered) kernel.

    @note We use afwMath.convolve() but keep scipy.convolve for debugging.
    @note We re-center the kernel if necessary and return the possibly re-centered kernel
    """
    outExp = kern = None
    fkernel = kernel
    if fix_kernel:
        fkernel = fixEvenKernel(kernel)
    if use_scipy:
        pci = scipy.ndimage.filters.convolve(exposure.getMaskedImage().getImage().getArray(),
                                             fkernel, mode='constant', cval=np.nan)
        outExp = exposure.clone()
        outExp.getMaskedImage().getImage().getArray()[:, :] = pci
        kern = fkernel

    else:
        kern = arrayToAfwKernel(fkernel)
        outExp = exposure.clone()  # Do this to keep WCS, PSF, masks, etc.
        convCntrl = afwMath.ConvolutionControl(False, True, 0)
        afwMath.convolve(outExp.getMaskedImage(), exposure.getMaskedImage(), kern, convCntrl)

    return outExp, kern
Ejemplo n.º 12
0
    def _makeAndTestUncorrectedDiffim(self):
        """Create the (un-decorrelated) diffim, and verify that its variance is too low.
        """
        # Create the matching kernel. We used Gaussian PSFs for im1 and im2, so we can compute the "expected"
        # matching kernel sigma.
        psf1_sig = self.im1ex.getPsf().computeShape().getDeterminantRadius()
        psf2_sig = self.im2ex.getPsf().computeShape().getDeterminantRadius()
        sig_match = np.sqrt((psf1_sig**2. - psf2_sig**2.))
        # Sanity check - make sure PSFs are correct.
        self.assertFloatsAlmostEqual(sig_match,
                                     np.sqrt((self.psf1_sigma**2. -
                                              self.psf2_sigma**2.)),
                                     rtol=2e-5)
        # mKernel = measAlg.SingleGaussianPsf(31, 31, sig_match)
        x0 = np.arange(-16, 16, 1)
        y0 = x0.copy()
        x0im, y0im = np.meshgrid(x0, y0)
        matchingKernel = singleGaussian2d(x0im,
                                          y0im,
                                          -1.,
                                          -1.,
                                          sigma_x=sig_match,
                                          sigma_y=sig_match)
        kernelImg = afwImage.ImageD(matchingKernel.shape[0],
                                    matchingKernel.shape[1])
        kernelImg.getArray()[:, :] = matchingKernel
        mKernel = afwMath.FixedKernel(kernelImg)

        # Create the matched template by convolving the template with the matchingKernel
        matched_im2ex = self.im2ex.clone()
        convCntrl = afwMath.ConvolutionControl(False, True, 0)
        afwMath.convolve(matched_im2ex.getMaskedImage(),
                         self.im2ex.getMaskedImage(), mKernel, convCntrl)

        # Expected (ideal) variance of difference image
        expected_var = self.svar + self.tvar
        if verbose:
            print('EXPECTED VARIANCE:', expected_var)

        # Create the diffim (uncorrected)
        # Uncorrected diffim exposure - variance plane is wrong (too low)
        tmp_diffExp = self.im1ex.getMaskedImage().clone()
        tmp_diffExp -= matched_im2ex.getMaskedImage()
        var = self._computeVarianceMean(tmp_diffExp)
        self.assertLess(var, expected_var)

        # Uncorrected diffim exposure - variance is wrong (too low) - same as above but on pixels
        diffExp = self.im1ex.clone()
        tmp = diffExp.getMaskedImage()
        tmp -= matched_im2ex.getMaskedImage()
        var = self._computePixelVariance(diffExp.getMaskedImage())
        self.assertLess(var, expected_var)

        # Uncorrected diffim exposure - variance plane is wrong (too low)
        mn = self._computeVarianceMean(diffExp.getMaskedImage())
        self.assertLess(mn, expected_var)
        if verbose:
            print('UNCORRECTED VARIANCE:', var, mn)

        return diffExp, mKernel, expected_var
Ejemplo n.º 13
0
    def checkEdge(self, footprint):
        """Check that Footprint::findEdgePixels() works"""
        bbox = footprint.getBBox()
        bbox.grow(3)

        def makeImage(footprint):
            """Make an ImageF with 1 in the footprint, and 0 elsewhere"""
            ones = afwImage.ImageI(bbox)
            ones.set(1)
            image = afwImage.ImageI(bbox)
            image.set(0)
            afwDetect.copyWithinFootprintImage(footprint, ones, image)
            return image

        edges = self.foot.findEdgePixels()
        edgeImage = makeImage(edges)

        # Find edges with an edge-detection kernel
        image = makeImage(self.foot)
        kernel = afwImage.ImageD(3, 3)
        kernel.set(1, 1, 4)
        for x, y in [(1, 2), (0, 1), (1, 0), (2, 1)]:
            kernel.set(x, y, -1)
        kernel.setXY0(1, 1)
        result = afwImage.ImageI(bbox)
        result.set(0)
        afwMath.convolve(result, image, afwMath.FixedKernel(kernel),
                         afwMath.ConvolutionControl(False))
        result.getArray().__imul__(image.getArray())
        trueEdges = numpy.where(result.getArray() > 0, 1, 0)

        self.assertTrue(numpy.all(trueEdges == edgeImage.getArray()))
    def testGood(self):
        ti = afwImage.MaskedImageF(afwGeom.Extent2I(100, 100))
        ti.getVariance().set(0.1)
        ti.set(50, 50, (1., 0x0, 1.))
        sKernel = self.makeSpatialKernel(2)
        si = afwImage.MaskedImageF(ti.getDimensions())
        afwMath.convolve(si, ti, sKernel, True)

        bbox = afwGeom.Box2I(afwGeom.Point2I(25, 25),
                             afwGeom.Point2I(75, 75))
        si = afwImage.MaskedImageF(si, bbox, origin=afwImage.LOCAL)
        ti = afwImage.MaskedImageF(ti, bbox, origin=afwImage.LOCAL)
        kc = ipDiffim.KernelCandidateF(50., 50., ti, si, self.policy)

        sBg = afwMath.PolynomialFunction2D(1)
        bgCoeffs = [0., 0., 0.]
        sBg.setParameters(bgCoeffs)

        # must be initialized
        bskv = ipDiffim.BuildSingleKernelVisitorF(self.kList, self.policy)
        bskv.processCandidate(kc)
        self.assertEqual(kc.isInitialized(), True)
        #ds9.mtv(kc.getTemplateMaskedImage(), frame=1)
        #ds9.mtv(kc.getScienceMaskedImage(), frame=2)
        #ds9.mtv(kc.getKernelImage(ipDiffim.KernelCandidateF.RECENT), frame=3)
        #ds9.mtv(kc.getDifferenceImage(ipDiffim.KernelCandidateF.RECENT), frame=4)

        askv = ipDiffim.AssessSpatialKernelVisitorF(sKernel, sBg, self.policy)
        askv.processCandidate(kc)

        self.assertEqual(askv.getNProcessed(), 1)
        self.assertEqual(askv.getNRejected(), 0)
        self.assertEqual(kc.getStatus(), afwMath.SpatialCellCandidate.GOOD)
    def testGaussianWithNoise(self):
        # Convolve a real image with a gaussian and try and recover
        # it.  Add noise and perform the same test.

        gsize = self.policy.getInt("kernelSize")
        gaussFunction = afwMath.GaussianFunction2D(2, 3)
        gaussKernel = afwMath.AnalyticKernel(gsize, gsize, gaussFunction)
        kImageIn = afwImage.ImageD(afwGeom.Extent2I(gsize, gsize))
        kSumIn = gaussKernel.computeImage(kImageIn, False)

        imX, imY = self.templateExposure2.getMaskedImage().getDimensions()
        smi = afwImage.MaskedImageF(afwGeom.Extent2I(imX, imY))
        afwMath.convolve(smi, self.templateExposure2.getMaskedImage(), gaussKernel, False)

        bbox = gaussKernel.shrinkBBox(smi.getBBox(afwImage.LOCAL))

        tmi2 = afwImage.MaskedImageF(self.templateExposure2.getMaskedImage(), bbox, origin=afwImage.LOCAL)
        smi2 = afwImage.MaskedImageF(smi, bbox, origin=afwImage.LOCAL)

        kc = ipDiffim.KernelCandidateF(self.x02, self.y02, tmi2, smi2, self.policy)
        kList = ipDiffim.makeKernelBasisList(self.subconfig)
        kc.build(kList)
        self.assertEqual(kc.isInitialized(), True)
        kImageOut = kc.getImage()

        soln = kc.getKernelSolution(ipDiffim.KernelCandidateF.RECENT)
        self.assertAlmostEqual(soln.getKsum(), kSumIn)
        # 8.7499380640430563e-06 != 0.0 within 7 places
        self.assertAlmostEqual(soln.getBackground(), 0.0, 4)

        for j in range(kImageOut.getHeight()):
            for i in range(kImageOut.getWidth()):

                # in the outskirts of the kernel, the ratio can get screwed because of low S/N
                # e.g. 7.45817359824e-09 vs. 1.18062529402e-08
                # in the guts of the kernel it should look closer
                if kImageIn[i, j, afwImage.LOCAL] > 1e-4:
                    # sigh, too bad this sort of thing fails..
                    # 0.99941584433815966 != 1.0 within 3 places
                    self.assertAlmostEqual(kImageOut[i, j, afwImage.LOCAL]/kImageIn[i, j, afwImage.LOCAL],
                                           1.0, 2)

        # now repeat with noise added; decrease precision of comparison
        self.addNoise(smi2)
        kc = ipDiffim.KernelCandidateF(self.x02, self.y02, tmi2, smi2, self.policy)
        kList = ipDiffim.makeKernelBasisList(self.subconfig)
        kc.build(kList)
        self.assertEqual(kc.isInitialized(), True)
        kImageOut = kc.getImage()

        soln = kc.getKernelSolution(ipDiffim.KernelCandidateF.RECENT)
        self.assertAlmostEqual(soln.getKsum(), kSumIn, 3)
        if not (self.policy.get("fitForBackground")):
            self.assertEqual(soln.getBackground(), 0.0)

        for j in range(kImageOut.getHeight()):
            for i in range(kImageOut.getWidth()):
                if kImageIn[i, j, afwImage.LOCAL] > 1e-2:
                    self.assertAlmostEqual(kImageOut[i, j, afwImage.LOCAL],
                                           kImageIn[i, j, afwImage.LOCAL], 2)
Ejemplo n.º 16
0
    def convolveImage(self, maskedImage, psf, doSmooth=True):
        """Convolve the image with the PSF

        We convolve the image with a Gaussian approximation to the PSF,
        because this is separable and therefore fast. It's technically a
        correlation rather than a convolution, but since we use a symmetric
        Gaussian there's no difference.

        The convolution can be disabled with ``doSmooth=False``. If we do
        convolve, we mask the edges as ``EDGE`` and return the convolved image
        with the edges removed. This is because we can't convolve the edges
        because the kernel would extend off the image.

        Parameters
        ----------
        maskedImage : `lsst.afw.image.MaskedImage`
            Image to convolve.
        psf : `lsst.afw.detection.Psf`
            PSF to convolve with (actually with a Gaussian approximation
            to it).
        doSmooth : `bool`
            Actually do the convolution? Set to False when running on
            e.g. a pre-convolved image, or a mask plane.

        Return Struct contents
        ----------------------
        middle : `lsst.afw.image.MaskedImage`
            Convolved image, without the edges.
        sigma : `float`
            Gaussian sigma used for the convolution.
        """
        self.metadata["doSmooth"] = doSmooth
        sigma = psf.computeShape(psf.getAveragePosition()).getDeterminantRadius()
        self.metadata["sigma"] = sigma

        if not doSmooth:
            middle = maskedImage.Factory(maskedImage, deep=True)
            return pipeBase.Struct(middle=middle, sigma=sigma)

        # Smooth using a Gaussian (which is separable, hence fast) of width sigma
        # Make a SingleGaussian (separable) kernel with the 'sigma'
        kWidth = self.calculateKernelSize(sigma)
        self.metadata["smoothingKernelWidth"] = kWidth
        gaussFunc = afwMath.GaussianFunction1D(sigma)
        gaussKernel = afwMath.SeparableKernel(kWidth, kWidth, gaussFunc, gaussFunc)

        convolvedImage = maskedImage.Factory(maskedImage.getBBox())

        afwMath.convolve(convolvedImage, maskedImage, gaussKernel, afwMath.ConvolutionControl())
        #
        # Only search psf-smoothed part of frame
        #
        goodBBox = gaussKernel.shrinkBBox(convolvedImage.getBBox())
        middle = convolvedImage.Factory(convolvedImage, goodBBox, afwImage.PARENT, False)
        #
        # Mark the parts of the image outside goodBBox as EDGE
        #
        self.setEdgeBits(maskedImage, goodBBox, maskedImage.getMask().getPlaneBitMask("EDGE"))

        return pipeBase.Struct(middle=middle, sigma=sigma)
Ejemplo n.º 17
0
def doConvolve(exposure, kernel, use_scipy=False, fix_kernel=False):
    """! Convolve an Exposure with a decorrelation convolution kernel.
    @param exposure Input afw.image.Exposure to be convolved.
    @param kernel Input 2-d numpy.array to convolve the image with
    @param use_scipy Use scipy to do convolution instead of afwMath
    @return a new Exposure with the convolved pixels and the (possibly
    re-centered) kernel.

    @note We use afwMath.convolve() but keep scipy.convolve for debugging.
    @note We re-center the kernel if necessary and return the possibly re-centered kernel
    """
    outExp = kern = None
    fkernel = kernel
    if fix_kernel:
        fkernel = fixEvenKernel(kernel)
    if use_scipy:
        pci = scipy.ndimage.filters.convolve(
            exposure.getMaskedImage().getImage().getArray(),
            fkernel,
            mode='constant',
            cval=np.nan)
        outExp = exposure.clone()
        outExp.getMaskedImage().getImage().getArray()[:, :] = pci
        kern = fkernel

    else:
        kern = arrayToAfwKernel(fkernel)
        outExp = exposure.clone()  # Do this to keep WCS, PSF, masks, etc.
        convCntrl = afwMath.ConvolutionControl(False, True, 0)
        afwMath.convolve(outExp.getMaskedImage(), exposure.getMaskedImage(),
                         kern, convCntrl)

    return outExp, kern
Ejemplo n.º 18
0
    def testUnityConvolution(self):
        """Verify that convolution with a centered delta function reproduces the original.
        """
        # create a delta function kernel that has 1,1 in the center
        kFunc = afwMath.IntegerDeltaFunction2D(0.0, 0.0)
        kernel = afwMath.AnalyticKernel(3, 3, kFunc)
        doNormalize = False
        doCopyEdge = False

        afwMath.convolve(self.cnvImage, self.maskedImage.getImage(), kernel, doNormalize, doCopyEdge)
        cnvImArr = self.cnvImage.getArray()
        
        afwMath.convolve(self.cnvMaskedImage, self.maskedImage, kernel, doNormalize, doCopyEdge)
        cnvImMaskVarArr = self.cnvMaskedImage.getArrays()

        refCnvImMaskVarArr = self.maskedImage.getArrays()
        
        skipMaskArr = numpy.isnan(cnvImMaskVarArr[0])

        kernelDescr = "Centered DeltaFunctionKernel (testing unity convolution)"
        errStr = imTestUtils.imagesDiffer(cnvImArr, refCnvImMaskVarArr[0], skipMaskArr=skipMaskArr)
        if errStr:
            self.fail("convolve(Image, kernel=%s, doNormalize=%s, doCopyEdge=%s) failed:\n%s" % \
                (kernelDescr, doNormalize, doCopyEdge, errStr))
        errStr = imTestUtils.maskedImagesDiffer(cnvImMaskVarArr, refCnvImMaskVarArr, skipMaskArr=skipMaskArr)
        if errStr:
            self.fail("convolve(MaskedImage, kernel=%s, doNormalize=%s, doCopyEdge=%s) failed:\n%s" % \
                (kernelDescr, doNormalize, doCopyEdge, errStr))
        self.assert_(sameMaskPlaneDicts(self.cnvMaskedImage, self.maskedImage),
            "convolve(MaskedImage, kernel=%s, doNormalize=%s, doCopyEdge=%s) failed:\n%s" % \
            (kernelDescr, doNormalize, doCopyEdge, "convolved mask dictionary does not match input"))
    def testGood(self):
        ti = afwImage.MaskedImageF(geom.Extent2I(100, 100))
        ti.getVariance().set(0.1)
        ti[50, 50, afwImage.LOCAL] = (1., 0x0, 1.)
        sKernel = self.makeSpatialKernel(2)
        si = afwImage.MaskedImageF(ti.getDimensions())
        convolutionControl = afwMath.ConvolutionControl()
        convolutionControl.setDoNormalize(True)
        afwMath.convolve(si, ti, sKernel, convolutionControl)

        bbox = geom.Box2I(geom.Point2I(25, 25),
                          geom.Point2I(75, 75))
        si = afwImage.MaskedImageF(si, bbox, origin=afwImage.LOCAL)
        ti = afwImage.MaskedImageF(ti, bbox, origin=afwImage.LOCAL)
        kc = ipDiffim.KernelCandidateF(50., 50., ti, si, self.ps)

        sBg = afwMath.PolynomialFunction2D(1)
        bgCoeffs = [0., 0., 0.]
        sBg.setParameters(bgCoeffs)

        # must be initialized
        bskv = ipDiffim.BuildSingleKernelVisitorF(self.kList, self.ps)
        bskv.processCandidate(kc)
        self.assertEqual(kc.isInitialized(), True)

        askv = ipDiffim.AssessSpatialKernelVisitorF(sKernel, sBg, self.ps)
        askv.processCandidate(kc)

        self.assertEqual(askv.getNProcessed(), 1)
        self.assertEqual(askv.getNRejected(), 0)
        self.assertEqual(kc.getStatus(), afwMath.SpatialCellCandidate.GOOD)
Ejemplo n.º 20
0
def smooth_gauss(masked_image, sigma, nsigma=7.0):
    """
    Smooth image with a Gaussian kernel. 

    Parameters
    ----------
    masked_image : lsst.afw.image.imageLib.MaskedImageF
        Masked image object to be smoothed
    sigma : float
        Standard deviation of Gaussian
    nsigma : float, optional
        Number of sigma for kernel width

    Returns
    -------
    convolved_image : lsst.afw.image.imageLib.MaskedImageF
        The convolved masked image
    """
    width = (int(sigma*nsigma + 0.5) // 2)*2 + 1 # make sure it is odd
    gauss_func = afwMath.GaussianFunction1D(sigma)
    gauss_kern = afwMath.SeparableKernel(width, width, gauss_func, gauss_func)
    convolved_image = masked_image.Factory(masked_image.getBBox())
    afwMath.convolve(convolved_image, masked_image, gauss_kern, 
                     afwMath.ConvolutionControl())
    return convolved_image
Ejemplo n.º 21
0
    def testUnityConvolution(self):
        """Verify that convolution with a centered delta function reproduces the original.
        """
        # create a delta function kernel that has 1,1 in the center
        kFunc = afwMath.IntegerDeltaFunction2D(0.0, 0.0)
        kernel = afwMath.AnalyticKernel(3, 3, kFunc)
        doNormalize = False
        doCopyEdge = False

        afwMath.convolve(self.cnvImage, self.maskedImage.getImage(), kernel,
                         doNormalize, doCopyEdge)

        afwMath.convolve(self.cnvMaskedImage, self.maskedImage, kernel,
                         doNormalize, doCopyEdge)
        cnvImMaskVarArr = self.cnvMaskedImage.getArrays()

        skipMaskArr = numpy.array(numpy.isnan(cnvImMaskVarArr[0]),
                                  dtype=numpy.uint16)

        kernelDescr = "Centered DeltaFunctionKernel (testing unity convolution)"
        self.assertImagesAlmostEqual(self.cnvImage,
                                     self.maskedImage.getImage(),
                                     skipMask=skipMaskArr,
                                     msg=kernelDescr)
        self.assertMaskedImagesAlmostEqual(self.cnvMaskedImage,
                                           self.maskedImage,
                                           skipMask=skipMaskArr,
                                           msg=kernelDescr)
Ejemplo n.º 22
0
    def run(self, exposure, referencePsfModel, kernelSum=1.0):
        """!Psf-match an exposure to a model Psf

        @param exposure: Exposure to Psf-match to the reference Psf model;
            it must return a valid PSF model via exposure.getPsf()
        @param referencePsfModel: The Psf model to match to (an lsst.afw.detection.Psf)
        @param kernelSum: A multipicative factor to apply to the kernel sum (default=1.0)

        @return
        - psfMatchedExposure: the Psf-matched Exposure.  This has the same parent bbox, Wcs, Calib and 
            Filter as the input Exposure but no Psf.  In theory the Psf should equal referencePsfModel but 
            the match is likely not exact.
        - psfMatchingKernel: the spatially varying Psf-matching kernel
        - kernelCellSet: SpatialCellSet used to solve for the Psf-matching kernel

        Raise a RuntimeError if the Exposure does not contain a Psf model
        """
        if not exposure.hasPsf():
            raise RuntimeError("exposure does not contain a Psf model")

        maskedImage = exposure.getMaskedImage()

        self.log.log(pexLog.Log.INFO, "compute Psf-matching kernel")
        kernelCellSet = self._buildCellSet(exposure, referencePsfModel)
        width, height = referencePsfModel.getLocalKernel().getDimensions()
        psfAttr1 = measAlg.PsfAttributes(exposure.getPsf(), width//2, height//2)
        psfAttr2 = measAlg.PsfAttributes(referencePsfModel, width//2, height//2)
        s1 = psfAttr1.computeGaussianWidth(psfAttr1.ADAPTIVE_MOMENT) # gaussian sigma in pixels
        s2 = psfAttr2.computeGaussianWidth(psfAttr2.ADAPTIVE_MOMENT) # gaussian sigma in pixels
        fwhm1 = s1 * sigma2fwhm # science Psf
        fwhm2 = s2 * sigma2fwhm # template Psf

        basisList = makeKernelBasisList(self.kConfig, fwhm1, fwhm2, metadata = self.metadata)
        spatialSolution, psfMatchingKernel, backgroundModel = self._solve(kernelCellSet, basisList)

        if psfMatchingKernel.isSpatiallyVarying():
            sParameters = num.array(psfMatchingKernel.getSpatialParameters())
            sParameters[0][0] = kernelSum
            psfMatchingKernel.setSpatialParameters(sParameters)
        else:
            kParameters = num.array(psfMatchingKernel.getKernelParameters())
            kParameters[0] = kernelSum
            psfMatchingKernel.setKernelParameters(kParameters)

        self.log.log(pexLog.Log.INFO, "Psf-match science exposure to reference")
        psfMatchedExposure = afwImage.ExposureF(exposure.getBBox(), exposure.getWcs())
        psfMatchedExposure.setFilter(exposure.getFilter())
        psfMatchedExposure.setCalib(exposure.getCalib())
        psfMatchedMaskedImage = psfMatchedExposure.getMaskedImage()

        # Normalize the psf-matching kernel while convolving since its magnitude is meaningless
        # when PSF-matching one model to another.
        doNormalize = True
        afwMath.convolve(psfMatchedMaskedImage, maskedImage, psfMatchingKernel, doNormalize)
        
        self.log.log(pexLog.Log.INFO, "done")
        return pipeBase.Struct(psfMatchedExposure=psfMatchedExposure,
                               psfMatchingKernel=psfMatchingKernel,
                               kernelCellSet=kernelCellSet,
                               metadata=self.metadata)
Ejemplo n.º 23
0
    def convolveImage(self, maskedImage, psf, doSmooth=True):
        """Convolve the image with the PSF

            This differs from the standard SourceDetectionTask convolveImage
            in that it allows the user to specify a scaling to the sigma. For GOTO coadds, we found that convolving by the sigma blurred the image too much, meaning that some peaks were missed. By reducing the width of the Gaussian kernel, the smoothing is reduced.

            Parameters
            ----------
            maskedImage : `lsst.afw.image.MaskedImage`
                Image to convolve.
            psf : `lsst.afw.detection.Psf`
                PSF to convolve with (actually with a Gaussian approximation
                to it).
            doSmooth : `bool`
                Actually do the convolution?

            Return Struct contents
            ----------------------
            middle : `lsst.afw.image.MaskedImage`
                Convolved image, without the edges.
            sigma : `float`
                Gaussian sigma used for the convolution.
            """
        self.metadata.set("doSmooth", doSmooth)
        sigma = psf.computeShape().getDeterminantRadius()

        # This is the only thing that differs from SourceDetectionTask:
        sigma *= self.config.scaleSigma
        self.metadata.set("sigma", sigma)

        if not doSmooth:
            middle = maskedImage.Factory(maskedImage)
            return pipeBase.Struct(middle=middle, sigma=sigma)

        # Smooth using a Gaussian (which is separable, hence fast) of width sigma
        # Make a SingleGaussian (separable) kernel with the 'sigma'
        kWidth = self.calculateKernelSize(sigma)
        self.metadata.set("smoothingKernelWidth", kWidth)
        gaussFunc = afwMath.GaussianFunction1D(sigma)
        gaussKernel = afwMath.SeparableKernel(kWidth, kWidth, gaussFunc,
                                              gaussFunc)

        convolvedImage = maskedImage.Factory(maskedImage.getBBox())

        afwMath.convolve(convolvedImage, maskedImage, gaussKernel,
                         afwMath.ConvolutionControl())
        #
        # Only search psf-smoothed part of frame
        #
        goodBBox = gaussKernel.shrinkBBox(convolvedImage.getBBox())
        middle = convolvedImage.Factory(convolvedImage, goodBBox,
                                        afwImage.PARENT, False)
        #
        # Mark the parts of the image outside goodBBox as EDGE

        self.setEdgeBits(maskedImage, goodBBox,
                         maskedImage.getMask().getPlaneBitMask("EDGE"))

        return pipeBase.Struct(middle=middle, sigma=sigma)
Ejemplo n.º 24
0
    def convolveImage(self, maskedImage, psf, doSmooth=True):
        """Convolve the image with the PSF

        We convolve the image with a Gaussian approximation to the PSF,
        because this is separable and therefore fast. It's technically a
        correlation rather than a convolution, but since we use a symmetric
        Gaussian there's no difference.

        The convolution can be disabled with ``doSmooth=False``. If we do
        convolve, we mask the edges as ``EDGE`` and return the convolved image
        with the edges removed. This is because we can't convolve the edges
        because the kernel would extend off the image.

        Parameters
        ----------
        maskedImage : `lsst.afw.image.MaskedImage`
            Image to convolve.
        psf : `lsst.afw.detection.Psf`
            PSF to convolve with (actually with a Gaussian approximation
            to it).
        doSmooth : `bool`
            Actually do the convolution?

        Return Struct contents
        ----------------------
        middle : `lsst.afw.image.MaskedImage`
            Convolved image, without the edges.
        sigma : `float`
            Gaussian sigma used for the convolution.
        """
        self.metadata.set("doSmooth", doSmooth)
        sigma = psf.computeShape().getDeterminantRadius()
        self.metadata.set("sigma", sigma)

        if not doSmooth:
            middle = maskedImage.Factory(maskedImage)
            return pipeBase.Struct(middle=middle, sigma=sigma)

        # Smooth using a Gaussian (which is separable, hence fast) of width sigma
        # Make a SingleGaussian (separable) kernel with the 'sigma'
        kWidth = self.calculateKernelSize(sigma)
        self.metadata.set("smoothingKernelWidth", kWidth)
        gaussFunc = afwMath.GaussianFunction1D(sigma)
        gaussKernel = afwMath.SeparableKernel(kWidth, kWidth, gaussFunc, gaussFunc)

        convolvedImage = maskedImage.Factory(maskedImage.getBBox())

        afwMath.convolve(convolvedImage, maskedImage, gaussKernel, afwMath.ConvolutionControl())
        #
        # Only search psf-smoothed part of frame
        #
        goodBBox = gaussKernel.shrinkBBox(convolvedImage.getBBox())
        middle = convolvedImage.Factory(convolvedImage, goodBBox, afwImage.PARENT, False)
        #
        # Mark the parts of the image outside goodBBox as EDGE
        #
        self.setEdgeBits(maskedImage, goodBBox, maskedImage.getMask().getPlaneBitMask("EDGE"))

        return pipeBase.Struct(middle=middle, sigma=sigma)
Ejemplo n.º 25
0
def doConvolve(exposure, kernel, use_scipy=False):
    """! Convolve an Exposure with a decorrelation convolution kernel.
    @param exposure Input afw.image.Exposure to be convolved.
    @param kernel Input 2-d numpy.array to convolve the image with
    @param use_scipy Use scipy to do convolution instead of afwMath
    @return a new Exposure with the convolved pixels and the (possibly
    re-centered) kernel.

    @note We use afwMath.convolve() but keep scipy.convolve for debugging.
    @note We re-center the kernel if necessary and return the possibly re-centered kernel
    """
    def _fixEvenKernel(kernel):
        """! Take a kernel with even dimensions and make them odd, centered correctly.
        @param kernel a numpy.array
        @return a fixed kernel numpy.array
        """
        # Make sure the peak (close to a delta-function) is in the center!
        maxloc = np.unravel_index(np.argmax(kernel), kernel.shape)
        out = np.roll(kernel, kernel.shape[0] // 2 - maxloc[0], axis=0)
        out = np.roll(out, out.shape[1] // 2 - maxloc[1], axis=1)
        # Make sure it is odd-dimensioned by trimming it.
        if (out.shape[0] % 2) == 0:
            maxloc = np.unravel_index(np.argmax(out), out.shape)
            if out.shape[0] - maxloc[0] > maxloc[0]:
                out = out[:-1, :]
            else:
                out = out[1:, :]
            if out.shape[1] - maxloc[1] > maxloc[1]:
                out = out[:, :-1]
            else:
                out = out[:, 1:]
        return out

    outExp = kern = None
    fkernel = _fixEvenKernel(kernel)
    if use_scipy:
        from scipy.ndimage.filters import convolve
        pci = convolve(exposure.getMaskedImage().getImage().getArray(),
                       fkernel,
                       mode='constant',
                       cval=np.nan)
        outExp = exposure.clone()
        outExp.getMaskedImage().getImage().getArray()[:, :] = pci
        kern = fkernel

    else:
        kernelImg = afwImage.ImageD(fkernel.shape[0], fkernel.shape[1])
        kernelImg.getArray()[:, :] = fkernel
        kern = afwMath.FixedKernel(kernelImg)
        maxloc = np.unravel_index(np.argmax(fkernel), fkernel.shape)
        kern.setCtrX(maxloc[0])
        kern.setCtrY(maxloc[1])
        outExp = exposure.clone()  # Do this to keep WCS, PSF, masks, etc.
        convCntrl = afwMath.ConvolutionControl(False, True, 0)
        afwMath.convolve(outExp.getMaskedImage(), exposure.getMaskedImage(),
                         kern, convCntrl)

    return outExp, kern
Ejemplo n.º 26
0
    def psf(self, exposure, sources):
        """Measure the PSF

        @param exposure Exposure to process
        @param sources Measured sources on exposure
        """
        assert exposure, "No exposure provided"
        assert sources, "No sources provided"
        psfPolicy = self.config['psf']
        selName = psfPolicy['selectName']
        selPolicy = psfPolicy['select'].getPolicy()
        algName = psfPolicy['algorithmName']
        algPolicy = psfPolicy['algorithm'].getPolicy()
        self.log.log(self.log.INFO, "Measuring PSF")

        #
        # Run an extra detection step to mask out faint stars
        #
        if False:
            print "RHL is cleaning faint sources"

            import lsst.afw.math as afwMath

            sigma = 1.0
            gaussFunc = afwMath.GaussianFunction1D(sigma)
            gaussKernel = afwMath.SeparableKernel(15, 15, gaussFunc, gaussFunc)

            im = exposure.getMaskedImage().getImage()
            convolvedImage = im.Factory(im.getDimensions())
            afwMath.convolve(convolvedImage, im, gaussKernel)
            del im

            fs = afwDet.makeFootprintSet(convolvedImage,
                                         afwDet.createThreshold(4, "stdev"))
            fs = afwDet.makeFootprintSet(fs, 3, True)
            fs.setMask(exposure.getMaskedImage().getMask(), "DETECTED")

        starSelector = measAlg.makeStarSelector(selName, selPolicy)
        psfCandidateList = starSelector.selectStars(exposure, sources)

        psfDeterminer = measAlg.makePsfDeterminer(algName, algPolicy)
        psf, cellSet = psfDeterminer.determinePsf(exposure, psfCandidateList)

        # The PSF candidates contain a copy of the source, and so we need to explicitly propagate new flags
        for cand in psfCandidateList:
            cand = measAlg.cast_PsfCandidateF(cand)
            src = cand.getSource()
            if src.getFlagForDetection() & measAlg.Flags.PSFSTAR:
                ident = src.getId()
                src = sources[ident]
                assert src.getId() == ident
                src.setFlagForDetection(src.getFlagForDetection()
                                        | measAlg.Flags.PSFSTAR)

        exposure.setPsf(psf)
        return psf, cellSet
Ejemplo n.º 27
0
def doConvolve(exposure, kernel, use_scipy=False):
    """! Convolve an Exposure with a decorrelation convolution kernel.
    @param exposure Input afw.image.Exposure to be convolved.
    @param kernel Input 2-d numpy.array to convolve the image with
    @param use_scipy Use scipy to do convolution instead of afwMath
    @return a new Exposure with the convolved pixels and the (possibly
    re-centered) kernel.

    @note We use afwMath.convolve() but keep scipy.convolve for debugging.
    @note We re-center the kernel if necessary and return the possibly re-centered kernel
    """
    def _fixEvenKernel(kernel):
        """! Take a kernel with even dimensions and make them odd, centered correctly.
        @param kernel a numpy.array
        @return a fixed kernel numpy.array
        """
        # Make sure the peak (close to a delta-function) is in the center!
        maxloc = np.unravel_index(np.argmax(kernel), kernel.shape)
        out = np.roll(kernel, kernel.shape[0]//2 - maxloc[0], axis=0)
        out = np.roll(out, out.shape[1]//2 - maxloc[1], axis=1)
        # Make sure it is odd-dimensioned by trimming it.
        if (out.shape[0] % 2) == 0:
            maxloc = np.unravel_index(np.argmax(out), out.shape)
            if out.shape[0] - maxloc[0] > maxloc[0]:
                out = out[:-1, :]
            else:
                out = out[1:, :]
            if out.shape[1] - maxloc[1] > maxloc[1]:
                out = out[:, :-1]
            else:
                out = out[:, 1:]
        return out

    outExp = kern = None
    fkernel = _fixEvenKernel(kernel)
    if use_scipy:
        from scipy.ndimage.filters import convolve
        pci = convolve(exposure.getMaskedImage().getImage().getArray(),
                       fkernel, mode='constant', cval=np.nan)
        outExp = exposure.clone()
        outExp.getMaskedImage().getImage().getArray()[:, :] = pci
        kern = fkernel

    else:
        kernelImg = afwImage.ImageD(fkernel.shape[0], fkernel.shape[1])
        kernelImg.getArray()[:, :] = fkernel
        kern = afwMath.FixedKernel(kernelImg)
        maxloc = np.unravel_index(np.argmax(fkernel), fkernel.shape)
        kern.setCtrX(maxloc[0])
        kern.setCtrY(maxloc[1])
        outExp = exposure.clone()  # Do this to keep WCS, PSF, masks, etc.
        convCntrl = afwMath.ConvolutionControl(False, True, 0)
        afwMath.convolve(outExp.getMaskedImage(), exposure.getMaskedImage(), kern, convCntrl)

    return outExp, kern
    def testGaussian(self, imsize=50):
        # Convolve a delta function with a known gaussian; try to
        # recover using delta-function basis

        gsize = self.ps["kernelSize"]
        tsize = imsize + gsize

        gaussFunction = afwMath.GaussianFunction2D(2, 3)
        gaussKernel = afwMath.AnalyticKernel(gsize, gsize, gaussFunction)
        kImageIn = afwImage.ImageD(geom.Extent2I(gsize, gsize))
        gaussKernel.computeImage(kImageIn, False)

        # template image with a single hot pixel in the exact center
        tmi = afwImage.MaskedImageF(geom.Extent2I(tsize, tsize))
        tmi.set(0, 0x0, 1e-4)
        cpix = tsize // 2
        tmi[cpix, cpix, afwImage.LOCAL] = (1, 0x0, 1)

        # science image
        smi = afwImage.MaskedImageF(tmi.getDimensions())
        convolutionControl = afwMath.ConvolutionControl()
        convolutionControl.setDoNormalize(False)
        afwMath.convolve(smi, tmi, gaussKernel, convolutionControl)

        # get the actual kernel sum (since the image is not infinite)
        gscaling = afwMath.makeStatistics(smi,
                                          afwMath.SUM).getValue(afwMath.SUM)

        # grab only the non-masked subregion
        bbox = gaussKernel.shrinkBBox(smi.getBBox(afwImage.LOCAL))

        tmi2 = afwImage.MaskedImageF(tmi, bbox, origin=afwImage.LOCAL)
        smi2 = afwImage.MaskedImageF(smi, bbox, origin=afwImage.LOCAL)

        # make sure its a valid subregion!
        for j in range(tmi2.getHeight()):
            for i in range(tmi2.getWidth()):
                self.assertEqual(tmi2.mask[i, j, afwImage.LOCAL], 0)
                self.assertEqual(smi2.mask[i, j, afwImage.LOCAL], 0)

        kc = ipDiffim.KernelCandidateF(0.0, 0.0, tmi2, smi2, self.ps)
        kList = ipDiffim.makeKernelBasisList(self.subconfig)
        kc.build(kList)
        self.assertEqual(kc.isInitialized(), True)
        kImageOut = kc.getImage()

        soln = kc.getKernelSolution(ipDiffim.KernelCandidateF.RECENT)
        self.assertAlmostEqual(soln.getKsum(), gscaling)
        self.assertAlmostEqual(soln.getBackground(), 0.0)

        for j in range(kImageOut.getHeight()):
            for i in range(kImageOut.getWidth()):
                self.assertAlmostEqual(
                    kImageOut[i, j, afwImage.LOCAL] /
                    kImageIn[i, j, afwImage.LOCAL], 1.0, 5)
Ejemplo n.º 29
0
    def convolve(self, exposure, kernel):
        """Convolve image with kernel

        @param[in] exposure Exposure to convolve
        @param[in] kernel Kernel with which to convolve
        @output Convolved exposure
        """
        convolved = exposure.Factory(exposure)
        afwMath.convolve(convolved.getMaskedImage(), exposure.getMaskedImage(),
                         kernel, false)
        return convolved
Ejemplo n.º 30
0
    def runBasicTest(self, kernel, convControl, refKernel=None, kernelDescr="", rtol=1.0e-05, atol=1e-08):
        """Assert that afwMath::convolve gives the same result as reference convolution for a given kernel.

        Inputs:
        - kernel: convolution kernel
        - convControl: convolution control parameters (afwMath.ConvolutionControl)
        - refKernel: kernel to use for refConvolve (if None then kernel is used)
        - kernelDescr: description of kernel
        - rtol: relative tolerance (see below)
        - atol: absolute tolerance (see below)

        rtol and atol are positive, typically very small numbers.
        The relative difference (rtol * abs(b)) and the absolute difference "atol" are added together
        to compare against the absolute difference between "a" and "b".
        """
        if refKernel is None:
            refKernel = kernel
        # strip garbage characters (whitespace and punctuation) to make a short description for saving files
        shortKernelDescr = self._removeGarbageChars(kernelDescr)

        doNormalize = convControl.getDoNormalize()
        doCopyEdge = convControl.getDoCopyEdge()
        maxInterpDist = convControl.getMaxInterpolationDistance()

        imMaskVar = self.maskedImage.getArrays()
        xy0 = self.maskedImage.getXY0()

        refCnvImMaskVarArr = refConvolve(imMaskVar, xy0, refKernel, doNormalize, doCopyEdge)
        refMaskedImage = afwImage.makeMaskedImageFromArrays(*refCnvImMaskVarArr)

        afwMath.convolve(self.cnvImage, self.maskedImage.getImage(), kernel, convControl)
        self.assertEqual(self.cnvImage.getXY0(), self.xy0)

        afwMath.convolve(self.cnvMaskedImage, self.maskedImage, kernel, convControl)

        if display and False:
            ds9.mtv(displayUtils.Mosaic().makeMosaic([
                self.maskedImage, refMaskedImage, self.cnvMaskedImage]), frame=0)
            if False:
                for (x, y) in ((0, 0), (1, 0), (0, 1), (50, 50)):
                    print("Mask(%d,%d) 0x%x 0x%x" % (x, y, refMaskedImage.getMask().get(x, y),
                                                     self.cnvMaskedImage.getMask().get(x, y)))

        self.assertImagesNearlyEqual(self.cnvImage, refMaskedImage.getImage(), atol=atol, rtol=rtol)
        self.assertMaskedImagesNearlyEqual(self.cnvMaskedImage, refMaskedImage, atol=atol, rtol=rtol)

        if not sameMaskPlaneDicts(self.cnvMaskedImage, self.maskedImage):
            self.cnvMaskedImage.writeFits("act%s" % (shortKernelDescr,))
            refMaskedImage.writeFits("des%s" % (shortKernelDescr,))
            self.fail("convolve(MaskedImage, kernel=%s, doNormalize=%s, "
                      "doCopyEdge=%s, maxInterpDist=%s) failed:\n%s" %
                      (kernelDescr, doNormalize, doCopyEdge, maxInterpDist,
                       "convolved mask dictionary does not match input"))
Ejemplo n.º 31
0
    def runStdTest(self,
                   kernel,
                   refKernel=None,
                   kernelDescr="",
                   rtol=1.0e-05,
                   atol=1e-08,
                   maxInterpDist=10):
        """Assert that afwMath::convolve gives the same result as reference convolution for a given kernel.

        Inputs:
        - kernel: convolution kernel
        - refKernel: kernel to use for refConvolve (if None then kernel is used)
        - kernelDescr: description of kernel
        - rtol: relative tolerance (see below)
        - atol: absolute tolerance (see below)
        - maxInterpDist: maximum allowed distance for linear interpolation during convolution

        rtol and atol are positive, typically very small numbers.
        The relative difference (rtol * abs(b)) and the absolute difference "atol" are added together
        to compare against the absolute difference between "a" and "b".
        """
        convControl = afwMath.ConvolutionControl()
        convControl.setMaxInterpolationDistance(maxInterpDist)

        # verify dimension assertions:
        # - output image dimensions = input image dimensions
        # - input image width and height >= kernel width and height
        # Note: the assertion kernel size > 0 is tested elsewhere
        for inWidth in (kernel.getWidth() - 1, self.width - 1, self.width,
                        self.width + 1):
            for inHeight in (kernel.getHeight() - 1, self.width - 1,
                             self.width, self.width + 1):
                if (inWidth == self.width) and (inHeight == self.height):
                    continue
                inMaskedImage = afwImage.MaskedImageF(
                    afwGeom.Extent2I(inWidth, inHeight))
                with self.assertRaises(Exception):
                    afwMath.convolve(self.cnvMaskedImage, inMaskedImage,
                                     kernel)

        for doNormalize in (True, ):  # (False, True):
            convControl.setDoNormalize(doNormalize)
            for doCopyEdge in (False, ):  # (False, True):
                convControl.setDoCopyEdge(doCopyEdge)
                self.runBasicTest(kernel,
                                  convControl=convControl,
                                  refKernel=refKernel,
                                  kernelDescr=kernelDescr,
                                  rtol=rtol,
                                  atol=atol)

        # verify that basicConvolve does not write to edge pixels
        self.runBasicConvolveEdgeTest(kernel, kernelDescr)
Ejemplo n.º 32
0
def smoothExp(exp, smoothing, kernelSize=7):
    """Use for DISPLAY ONLY!
    Return a smoothed copy of the exposure with the original mask plane in place."""
    psf = measAlg.DoubleGaussianPsf(
        kernelSize, kernelSize, smoothing / (2 * math.sqrt(2 * math.log(2))))
    newExp = exp.clone()
    originalMask = exp.mask

    kernel = psf.getKernel()
    afwMath.convolve(newExp.maskedImage, newExp.maskedImage, kernel,
                     afwMath.ConvolutionControl())
    newExp.mask = originalMask
    return newExp
    def testGaussian(self, imsize = 50):
        # Convolve a delta function with a known gaussian; try to
        # recover using delta-function basis

        gsize = self.policy.getInt("kernelSize")
        tsize = imsize + gsize

        gaussFunction = afwMath.GaussianFunction2D(2, 3)
        gaussKernel   = afwMath.AnalyticKernel(gsize, gsize, gaussFunction)
        kImageIn      = afwImage.ImageD(afwGeom.Extent2I(gsize, gsize))
        gaussKernel.computeImage(kImageIn, False)

        # template image with a single hot pixel in the exact center
        tmi = afwImage.MaskedImageF(afwGeom.Extent2I(tsize, tsize))
        tmi.set(0, 0x0, 1e-4)
        cpix = tsize // 2
        tmi.set(cpix, cpix, (1, 0x0, 1))

        # science image
        smi = afwImage.MaskedImageF(tmi.getDimensions())
        afwMath.convolve(smi, tmi, gaussKernel, False)

        # get the actual kernel sum (since the image is not infinite)
        gscaling = afwMath.makeStatistics(smi, afwMath.SUM).getValue(afwMath.SUM)

        # grab only the non-masked subregion
        bbox = gaussKernel.shrinkBBox(smi.getBBox(afwImage.LOCAL))

        tmi2 = afwImage.MaskedImageF(tmi, bbox, afwImage.LOCAL)
        smi2 = afwImage.MaskedImageF(smi, bbox, afwImage.LOCAL)

        # make sure its a valid subregion!
        for j in range(tmi2.getHeight()):
            for i in range(tmi2.getWidth()):
                self.assertEqual(tmi2.getMask().get(i, j), 0)
                self.assertEqual(smi2.getMask().get(i, j), 0)


        kc = ipDiffim.KernelCandidateF(0.0, 0.0, tmi2, smi2, self.policy)
        kList = ipDiffim.makeKernelBasisList(self.subconfig)
        kc.build(kList)
        self.assertEqual(kc.isInitialized(), True)
        kImageOut = kc.getImage()

        soln = kc.getKernelSolution(ipDiffim.KernelCandidateF.RECENT)
        self.assertAlmostEqual(soln.getKsum(), gscaling)
        self.assertAlmostEqual(soln.getBackground(), 0.0)

        for j in range(kImageOut.getHeight()):
            for i in range(kImageOut.getWidth()):
                self.assertAlmostEqual(kImageOut.get(i, j)/kImageIn.get(i, j), 1.0, 5)
Ejemplo n.º 34
0
def findBrightestStarRHL(exp, minArea=100, maxRadialOffset=1500):
    import lsst.afw.detection as afwDetect
    import lsst.afw.image as afwImage
    import lsst.afw.math as afwMath

    cexp = exp.clone()

    sigma = 4

    ksize = 1 + 4*int(sigma + 1)
    gauss1d = afwMath.GaussianFunction1D(sigma)
    kernel = afwMath.SeparableKernel(ksize, ksize, gauss1d, gauss1d)

    convolvedImage = cexp.maskedImage.Factory(cexp.maskedImage.getBBox())
    afwMath.convolve(convolvedImage, cexp.maskedImage, kernel)
    bbox = geom.BoxI(geom.PointI(ksize//2, ksize//2), geom.PointI(cexp.getWidth() - ksize//2 - 1, cexp.getHeight() - ksize//2 - 1))
    tmp = cexp.maskedImage[bbox]
    cexp.image *= 0
    tmp[bbox, afwImage.PARENT] = convolvedImage[bbox]

    del convolvedImage; del tmp

    if False:
        defectBBoxes = [
            geom.BoxI(geom.PointI(548, 3562), geom.PointI(642, 3999)),
            geom.BoxI(geom.PointI(474, 3959), geom.PointI(1056, 3999)),
            geom.BoxI(geom.PointI(500, 0),    geom.PointI(680, 40)),
        ]
        for bbox in defectBBoxes:
            cexp.maskedImage[bbox] = 0

    threshold = 1000
    feet = afwDetect.FootprintSet(cexp.maskedImage, afwDetect.Threshold(threshold), "DETECTED").getFootprints()

    maxVal = None
    centroid = None
    for foot in feet:
        peak = foot.peaks[0]
        
        if minArea > 0 and foot.getArea() < minArea:
            continue
            
        x, y = peak.getCentroid()
        if np.hypot(x - 2036, y - 2000) > maxRadialOffset:
            continue

        if maxVal is None or peak.getPeakValue() > maxVal:
            maxVal = peak.getPeakValue()
            centroid = peak.getCentroid()
            
    return centroid
Ejemplo n.º 35
0
    def runBasicTest(self, kernel, convControl, refKernel=None, kernelDescr="", rtol=1.0e-05, atol=1e-08): 
        """Assert that afwMath::convolve gives the same result as reference convolution for a given kernel.
        
        Inputs:
        - kernel: convolution kernel
        - convControl: convolution control parameters (afwMath.ConvolutionControl)
        - refKernel: kernel to use for refConvolve (if None then kernel is used)
        - kernelDescr: description of kernel
        - rtol: relative tolerance (see below)
        - atol: absolute tolerance (see below)
        
        rtol and atol are positive, typically very small numbers.
        The relative difference (rtol * abs(b)) and the absolute difference "atol" are added together
        to compare against the absolute difference between "a" and "b".
        """
        if refKernel == None:
            refKernel = kernel
        # strip garbage characters (whitespace and punctuation) to make a short description for saving files
        shortKernelDescr = kernelDescr.translate(NullTranslator, GarbageChars)

        doNormalize = convControl.getDoNormalize()
        doCopyEdge = convControl.getDoCopyEdge()
        maxInterpDist = convControl.getMaxInterpolationDistance()

        imMaskVar = self.maskedImage.getArrays()
        xy0 = self.maskedImage.getXY0()
        
        refCnvImMaskVarArr = refConvolve(imMaskVar, xy0, refKernel, doNormalize, doCopyEdge)
        refMaskedImage = afwImage.makeMaskedImageFromArrays(*refCnvImMaskVarArr)

        afwMath.convolve(self.cnvImage, self.maskedImage.getImage(), kernel, convControl)
        self.assertEqual(self.cnvImage.getXY0(), self.xy0)

        afwMath.convolve(self.cnvMaskedImage, self.maskedImage, kernel, convControl)

        if display and False:
            ds9.mtv(displayUtils.Mosaic().makeMosaic([
                self.maskedImage, refMaskedImage, self.cnvMaskedImage]), frame=0)
            if False:
                for (x, y) in ((0, 0), (1, 0), (0, 1), (50, 50)):
                    print "Mask(%d,%d) 0x%x 0x%x" % (x, y, refMaskedImage.getMask().get(x, y),
                    self.cnvMaskedImage.getMask().get(x, y))

        self.assertImagesNearlyEqual(self.cnvImage, refMaskedImage.getImage(), atol=atol, rtol=rtol)
        self.assertMaskedImagesNearlyEqual(self.cnvMaskedImage, refMaskedImage, atol=atol, rtol=rtol)

        if not sameMaskPlaneDicts(self.cnvMaskedImage, self.maskedImage):
            self.cnvMaskedImage.writeFits("act%s" % (shortKernelDescr,))
            refMaskedImage.writeFits("des%s" % (shortKernelDescr,))
            self.fail("convolve(MaskedImage, kernel=%s, doNormalize=%s, doCopyEdge=%s, maxInterpDist=%s) failed:\n%s" % \
                (kernelDescr, doNormalize, doCopyEdge, maxInterpDist, "convolved mask dictionary does not match input"))
    def _makeAndTestUncorrectedDiffim(self):
        """Create the (un-decorrelated) diffim, and verify that its variance is too low.
        """
        # Create the matching kernel. We used Gaussian PSFs for im1 and im2, so we can compute the "expected"
        # matching kernel sigma.
        psf1_sig = self.im1ex.getPsf().computeShape().getDeterminantRadius()
        psf2_sig = self.im2ex.getPsf().computeShape().getDeterminantRadius()
        sig_match = np.sqrt((psf1_sig**2. - psf2_sig**2.))
        # Sanity check - make sure PSFs are correct.
        self.assertFloatsAlmostEqual(sig_match, np.sqrt((self.psf1_sigma**2. - self.psf2_sigma**2.)),
                                     rtol=2e-5)
        # mKernel = measAlg.SingleGaussianPsf(31, 31, sig_match)
        x0 = np.arange(-16, 16, 1)
        y0 = x0.copy()
        x0im, y0im = np.meshgrid(x0, y0)
        matchingKernel = singleGaussian2d(x0im, y0im, -1., -1., sigma_x=sig_match, sigma_y=sig_match)
        kernelImg = afwImage.ImageD(matchingKernel.shape[0], matchingKernel.shape[1])
        kernelImg.getArray()[:, :] = matchingKernel
        mKernel = afwMath.FixedKernel(kernelImg)

        # Create the matched template by convolving the template with the matchingKernel
        matched_im2ex = self.im2ex.clone()
        convCntrl = afwMath.ConvolutionControl(False, True, 0)
        afwMath.convolve(matched_im2ex.getMaskedImage(), self.im2ex.getMaskedImage(), mKernel, convCntrl)

        # Expected (ideal) variance of difference image
        expected_var = self.svar + self.tvar
        if verbose:
            print('EXPECTED VARIANCE:', expected_var)

        # Create the diffim (uncorrected)
        # Uncorrected diffim exposure - variance plane is wrong (too low)
        tmp_diffExp = self.im1ex.getMaskedImage().clone()
        tmp_diffExp -= matched_im2ex.getMaskedImage()
        var = self._computeVarianceMean(tmp_diffExp)
        self.assertLess(var, expected_var)

        # Uncorrected diffim exposure - variance is wrong (too low) - same as above but on pixels
        diffExp = self.im1ex.clone()
        tmp = diffExp.getMaskedImage()
        tmp -= matched_im2ex.getMaskedImage()
        var = self._computePixelVariance(diffExp.getMaskedImage())
        self.assertLess(var, expected_var)

        # Uncorrected diffim exposure - variance plane is wrong (too low)
        mn = self._computeVarianceMean(diffExp.getMaskedImage())
        self.assertLess(mn, expected_var)
        if verbose:
            print('UNCORRECTED VARIANCE:', var, mn)

        return diffExp, mKernel, expected_var
Ejemplo n.º 37
0
def createImageAndKernel(sigma, psfSize, image):
    function = afwMath.GaussianFunction2D(sigma, sigma)
    kernel = afwMath.AnalyticKernel(psfSize, psfSize, function)
    psf = measAlg.KernelPsf(kernel)

    cim = afwImage.ImageF(image.getDimensions())
    afwMath.convolve(cim, image, kernel, True)

    # Trim off the border pixels
    bbox = kernel.shrinkBBox(cim.getBBox(afwImage.LOCAL))
    cim = afwImage.ImageF(cim, bbox, afwImage.LOCAL)
    cim.setXY0(0, 0)

    return cim, psf
Ejemplo n.º 38
0
def createImageAndKernel(sigma, psfSize, image):
    function = afwMath.GaussianFunction2D(sigma, sigma)
    kernel = afwMath.AnalyticKernel(psfSize, psfSize, function)
    psf = measAlg.KernelPsf(kernel)

    cim = afwImage.ImageF(image.getDimensions())
    afwMath.convolve(cim, image, kernel, True)

    # Trim off the border pixels
    bbox = kernel.shrinkBBox(cim.getBBox(afwImage.LOCAL))
    cim = afwImage.ImageF(cim, bbox, afwImage.LOCAL)
    cim.setXY0(0, 0)

    return cim, psf
Ejemplo n.º 39
0
def smoothExp(exp, fwhm, display=False):
    import lsst.afw.math as afwMath

    smoothedScienceExposure = exp.clone()
    gauss = afwMath.GaussianFunction1D(fwhm)
    kSize = int(2 * fwhm + 0.5) + 1
    kernel = afwMath.SeparableKernel(kSize, kSize, gauss, gauss)
    afwMath.convolve(smoothedScienceExposure.getMaskedImage(),
                     exp.getMaskedImage(), kernel)

    if display:
        import lsst.afw.display.ds9 as ds9
        ds9.mtv(exp, title="science", frame=1)
        ds9.mtv(smoothedScienceExposure, title="smoothed", frame=2)

    return smoothedScienceExposure
Ejemplo n.º 40
0
    def setUp(self):
        FWHM = 5
        psf = algorithms.DoubleGaussianPsf(15, 15, FWHM/(2*math.sqrt(2*math.log(2))))
        mi = afwImage.MaskedImageF(afwGeom.ExtentI(100, 100))

        self.xc, self.yc, self.flux = 45, 55, 1000.0
        mi.getImage().set(self.xc, self.yc, self.flux)

        cnvImage = mi.Factory(mi.getDimensions())
        afwMath.convolve(cnvImage, mi, psf.getKernel(), afwMath.ConvolutionControl())

        self.exp = afwImage.makeExposure(cnvImage)
        self.exp.setPsf(psf)

        if display and False:
            ds9.mtv(self.exp)
Ejemplo n.º 41
0
    def setUp(self):
        FWHM = 5
        psf = algorithms.DoubleGaussianPsf(15, 15, FWHM/(2*math.sqrt(2*math.log(2))))
        mi = afwImage.MaskedImageF(afwGeom.ExtentI(100, 100))

        self.xc, self.yc, self.flux = 45, 55, 1000.0
        mi.getImage().set(self.xc, self.yc, self.flux)

        cnvImage = mi.Factory(mi.getDimensions())
        afwMath.convolve(cnvImage, mi, psf.getKernel(), afwMath.ConvolutionControl())

        self.exp = afwImage.makeExposure(cnvImage)
        self.exp.setPsf(psf)

        if display and False:
            ds9.mtv(self.exp)
Ejemplo n.º 42
0
    def setUp(self):
        FWHM = 5
        psf = algorithms.DoubleGaussianPsf(15, 15, FWHM/(2*math.sqrt(2*math.log(2))))
        mi = afwImage.MaskedImageF(lsst.geom.ExtentI(100, 100))

        self.xc, self.yc, self.instFlux = 45, 55, 1000.0
        mi.image[self.xc, self.yc, afwImage.LOCAL] = self.instFlux

        cnvImage = mi.Factory(mi.getDimensions())
        afwMath.convolve(cnvImage, mi, psf.getKernel(), afwMath.ConvolutionControl())

        self.exp = afwImage.makeExposure(cnvImage)
        self.exp.setPsf(psf)

        if display and False:
            afwDisplay.Display(frame=0).mtv(self.exp, title=self._testMethodName + ": image")
Ejemplo n.º 43
0
    def testZeroWidthKernel(self):
        """Convolution by a 0x0 kernel should raise an exception.

        The only way to produce a 0x0 kernel is to use the default constructor
        (which exists only to support persistence; it does not produce a useful kernel).
        """
        kernelList = [
            afwMath.FixedKernel(),
            afwMath.AnalyticKernel(),
            afwMath.SeparableKernel(),
            #            afwMath.DeltaFunctionKernel(),  # DeltaFunctionKernel has no default constructor
            afwMath.LinearCombinationKernel(),
        ]
        convolutionControl = afwMath.ConvolutionControl()
        for kernel in kernelList:
            with self.assertRaises(Exception):
                afwMath.convolve(self.cnvMaskedImage, self.maskedImage, kernel, convolutionControl)
Ejemplo n.º 44
0
def smooth_gauss(masked_image, sigma=2.0, nsigma=7.0, 
                 inplace=False, use_scipy=False, **kwargs):
    """
    Smooth image with a Gaussian kernel. 

    Parameters
    ----------
    masked_image : lsst.afw.image.imageLib.MaskedImageF
        Masked image object to be smoothed
    sigma : float
        Standard deviation of Gaussian
    nsigma : float, optional
        Number of sigma for kernel width
    inplace : bool, optional
        If True, smooth the image inplace. Else, return a clone 
        of the masked image. 
    use_scipy : bool, optional
        If True, perform smoothing using scipy.ndimage.

    Returns
    -------
    convolved_image : lsst.afw.image.imageLib.MaskedImageF
        The convolved masked image
    """
    if use_scipy:
        img_arr = get_image_ndarray(masked_image)
        img_arr_smooth = ndi.gaussian_filter(
            img_arr, sigma, truncate=nsigma, **kwargs)
        if inplace:
            convolved_image = masked_image
        else:
            convolved_image = masked_image.Factory(masked_image.getBBox())
        convolved_image.getImage().getArray()[:] = img_arr_smooth
    else:
        width = (int(sigma*nsigma + 0.5) // 2)*2 + 1 # make sure it is odd
        gauss_func = afwMath.GaussianFunction1D(sigma)
        gauss_kern = afwMath.SeparableKernel(
            width, width, gauss_func, gauss_func)
        convolved_image = masked_image.Factory(masked_image.getBBox())
        afwMath.convolve(convolved_image, masked_image, gauss_kern,
                         afwMath.ConvolutionControl())
        if inplace:
            img_arr_smooth = convolved_image.getImage().getArray()
            masked_image.getImage().getArray()[:] = img_arr_smooth
    return convolved_image
    def setUp(self):
        self.config = ipDiffim.ImagePsfMatchTask.ConfigClass()
        self.subconfig = self.config.kernel.active
        self.policy = pexConfig.makePolicy(self.subconfig)
        self.kSize = self.policy.getInt('kernelSize')

        # gaussian reference kernel
        self.gSize = self.kSize
        self.gaussFunction = afwMath.GaussianFunction2D(2, 3)
        self.gaussKernel = afwMath.AnalyticKernel(self.gSize, self.gSize, self.gaussFunction)

        if defDataDir:
            defImagePath = os.path.join(defDataDir, "DC3a-Sim", "sci", "v5-e0",
                                        "v5-e0-c011-a00.sci.fits")
            self.templateImage = afwImage.MaskedImageF(defImagePath)
            self.scienceImage = self.templateImage.Factory(self.templateImage.getDimensions())

            afwMath.convolve(self.scienceImage, self.templateImage, self.gaussKernel, False)
Ejemplo n.º 46
0
    def testUnityConvolution(self):
        """Verify that convolution with a centered delta function reproduces the original.
        """
        # create a delta function kernel that has 1,1 in the center
        kFunc = afwMath.IntegerDeltaFunction2D(0.0, 0.0)
        kernel = afwMath.AnalyticKernel(3, 3, kFunc)
        doNormalize = False
        doCopyEdge = False

        afwMath.convolve(self.cnvImage, self.maskedImage.getImage(), kernel, doNormalize, doCopyEdge)
        
        afwMath.convolve(self.cnvMaskedImage, self.maskedImage, kernel, doNormalize, doCopyEdge)
        cnvImMaskVarArr = self.cnvMaskedImage.getArrays()
        
        skipMaskArr = numpy.array(numpy.isnan(cnvImMaskVarArr[0]), dtype=numpy.uint16)

        kernelDescr = "Centered DeltaFunctionKernel (testing unity convolution)"
        self.assertImagesNearlyEqual(self.cnvImage, self.maskedImage.getImage(), skipMask=skipMaskArr, msg=kernelDescr)
        self.assertMaskedImagesNearlyEqual(self.cnvMaskedImage, self.maskedImage, skipMask=skipMaskArr, msg=kernelDescr)
def timeConvolution(outImage, inImage, kernel, convControl):
    """Time convolution

    @param outImage: output image or masked image (must be the same size as inImage)
    @param inImage: input image or masked image
    @param kernel: convolution kernel
    @param convControl: convolution control parameters (afwMath.ConvolutionControl)

    @return (elapsed time in seconds, number of iterations)
    """
    startTime = time.time();
    for nIter in range(1, MaxIter + 1):
#        mathDetail.convolveWithInterpolation(outImage, inImage, kernel, convControl)
        afwMath.convolve(outImage, inImage, kernel, convControl)
        endTime = time.time()
        if endTime - startTime > MaxTime:
            break

    return (endTime - startTime, nIter)
Ejemplo n.º 48
0
    def _doConvolve(exposure, kernel):
        """! Convolve an Exposure with a decorrelation convolution kernel.
        @param exposure Input afw.image.Exposure to be convolved.
        @param kernel Input 2-d numpy.array to convolve the image with
        @return a new Exposure with the convolved pixels and the (possibly
        re-centered) kernel.

        @note We use afwMath.convolve() but keep scipy.convolve for debugging.
        @note We re-center the kernel if necessary and return the possibly re-centered kernel
        """
        kernelImg = afwImage.ImageD(kernel.shape[0], kernel.shape[1])
        kernelImg.getArray()[:, :] = kernel
        kern = afwMath.FixedKernel(kernelImg)
        maxloc = np.unravel_index(np.argmax(kernel), kernel.shape)
        kern.setCtrX(maxloc[0])
        kern.setCtrY(maxloc[1])
        outExp = exposure.clone()  # Do this to keep WCS, PSF, masks, etc.
        convCntrl = afwMath.ConvolutionControl(False, True, 0)
        afwMath.convolve(outExp.getMaskedImage(), exposure.getMaskedImage(), kern, convCntrl)

        return outExp, kern
Ejemplo n.º 49
0
    def setUp(self):
        self.min, self.range, self.Q = 0, 5, 20  # asinh

        width, height = 85, 75
        self.images = []
        self.images.append(afwImage.ImageF(lsst.geom.ExtentI(width, height)))
        self.images.append(afwImage.ImageF(lsst.geom.ExtentI(width, height)))
        self.images.append(afwImage.ImageF(lsst.geom.ExtentI(width, height)))

        for (x, y, A, g_r, r_i) in [(15, 15, 1000, 1.0, 2.0),
                                    (50, 45, 5500, -1.0, -0.5),
                                    (30, 30, 600, 1.0, 2.5),
                                    (45, 15, 20000, 1.0, 1.0),
                                    ]:
            for i in range(len(self.images)):
                if i == B:
                    amp = A
                elif i == G:
                    amp = A*math.pow(10, 0.4*g_r)
                elif i == R:
                    amp = A*math.pow(10, 0.4*r_i)

                self.images[i][x, y, afwImage.LOCAL] = amp

        psf = afwMath.AnalyticKernel(
            15, 15, afwMath.GaussianFunction2D(2.5, 1.5, 0.5))

        convolvedImage = type(self.images[0])(self.images[0].getDimensions())
        randomImage = type(self.images[0])(self.images[0].getDimensions())
        rand = afwMath.Random("MT19937", 666)
        for i in range(len(self.images)):
            afwMath.convolve(convolvedImage, self.images[i], psf, True, True)
            afwMath.randomGaussianImage(randomImage, rand)
            randomImage *= 2
            convolvedImage += randomImage
            self.images[i][:] = convolvedImage
        del convolvedImage
        del randomImage
    def testBad(self):
        ti = afwImage.MaskedImageF(afwGeom.Extent2I(100, 100))
        ti.getVariance().set(0.1)
        ti.set(50, 50, (1., 0x0, 1.))
        sKernel = self.makeSpatialKernel(2)
        si = afwImage.MaskedImageF(ti.getDimensions())
        afwMath.convolve(si, ti, sKernel, True)

        bbox = afwGeom.Box2I(afwGeom.Point2I(25, 25),
                             afwGeom.Point2I(75, 75))
        si   = afwImage.MaskedImageF(si, bbox, afwImage.LOCAL)
        ti   = afwImage.MaskedImageF(ti, bbox, afwImage.LOCAL)
        kc   = ipDiffim.KernelCandidateF(50., 50., ti, si, self.policy)

        badGaussian = afwMath.GaussianFunction2D(1., 1., 0.)
        badKernel   = afwMath.AnalyticKernel(self.ksize, self.ksize, badGaussian)
        basisList = afwMath.KernelList()
        basisList.append(badKernel)
        badSpatialKernelFunction = afwMath.PolynomialFunction2D(0)
        badSpatialKernel = afwMath.LinearCombinationKernel(basisList, badSpatialKernelFunction)
        badSpatialKernel.setSpatialParameters([[1,]])
        
        sBg      = afwMath.PolynomialFunction2D(1)
        bgCoeffs = [10., 10., 10.]
        sBg.setParameters(bgCoeffs)

        # must be initialized
        bskv = ipDiffim.BuildSingleKernelVisitorF(self.kList, self.policy)
        bskv.processCandidate(kc)
        self.assertEqual(kc.isInitialized(), True)
        
        askv = ipDiffim.AssessSpatialKernelVisitorF(badSpatialKernel, sBg, self.policy)
        askv.processCandidate(kc)
       
        self.assertEqual(askv.getNProcessed(), 1)
        self.assertEqual(askv.getNRejected(), 1)
        self.assertEqual(kc.getStatus(), afwMath.SpatialCellCandidate.BAD)
Ejemplo n.º 51
0
    def setUp(self):
        self.config    = ipDiffim.ImagePsfMatchTask.ConfigClass()
        self.config.kernel.name = "AL"
        self.subconfig = self.config.kernel.active
        self.kSize     = self.subconfig.kernelSize

        # gaussian reference kernel
        self.gSize         = self.kSize
        self.gaussFunction = afwMath.GaussianFunction2D(2, 3)
        self.gaussKernel   = afwMath.AnalyticKernel(self.gSize, self.gSize, self.gaussFunction)

        # known input images
        try:
            self.defDataDir = lsst.utils.getPackageDir('afwdata')
        except Exception:
            self.defDataDir = None

        if self.defDataDir:
            defImagePath = os.path.join(self.defDataDir, "DC3a-Sim", "sci", "v5-e0",
                                        "v5-e0-c011-a00.sci.fits")
            self.templateImage  = afwImage.MaskedImageF(defImagePath)
            self.scienceImage   = self.templateImage.Factory( self.templateImage.getDimensions() )
            
            afwMath.convolve(self.scienceImage, self.templateImage, self.gaussKernel, False)
Ejemplo n.º 52
0
    def matchMaskedImages(self, templateMaskedImage, scienceMaskedImage, candidateList,
                          templateFwhmPix=None, scienceFwhmPix=None):
        """PSF-match a MaskedImage (templateMaskedImage) to a reference MaskedImage (scienceMaskedImage).

        Do the following, in order:

        - Determine a PSF matching kernel and differential background model
            that matches templateMaskedImage to scienceMaskedImage
        - Convolve templateMaskedImage by the PSF matching kernel

        Parameters
        ----------
        templateMaskedImage : `lsst.afw.image.MaskedImage`
            masked image to PSF-match to the reference masked image;
            must be warped to match the reference masked image
        scienceMaskedImage : `lsst.afw.image.MaskedImage`
            maskedImage whose PSF is to be matched to
        templateFwhmPix : `float`
            FWHM (in pixels) of the Psf in the template image (image to convolve)
        scienceFwhmPix : `float`
            FWHM (in pixels) of the Psf in the science image
        candidateList : `list`, optional
            A list of footprints/maskedImages for kernel candidates;
            if `None` then source detection is run.

            - Currently supported: list of Footprints or measAlg.PsfCandidateF

        Returns
        -------
        result : `callable`
        An `lsst.pipe.base.Struct` containing these fields:

        - psfMatchedMaskedImage: the PSF-matched masked image =
            ``templateMaskedImage`` convolved with psfMatchingKernel.
            This has the same xy0, dimensions and wcs as ``scienceMaskedImage``.
        - psfMatchingKernel: the PSF matching kernel
        - backgroundModel: differential background model
        - kernelCellSet: SpatialCellSet used to solve for the PSF matching kernel

        Raises
        ------
        RuntimeError
            Raised if input images have different dimensions
        """
        import lsstDebug
        display = lsstDebug.Info(__name__).display
        displayTemplate = lsstDebug.Info(__name__).displayTemplate
        displaySciIm = lsstDebug.Info(__name__).displaySciIm
        displaySpatialCells = lsstDebug.Info(__name__).displaySpatialCells
        maskTransparency = lsstDebug.Info(__name__).maskTransparency
        if not maskTransparency:
            maskTransparency = 0
        if display:
            afwDisplay.setDefaultMaskTransparency(maskTransparency)

        if not candidateList:
            raise RuntimeError("Candidate list must be populated by makeCandidateList")

        if not self._validateSize(templateMaskedImage, scienceMaskedImage):
            self.log.error("ERROR: Input images different size")
            raise RuntimeError("Input images different size")

        if display and displayTemplate:
            disp = afwDisplay.Display(frame=lsstDebug.frame)
            disp.mtv(templateMaskedImage, title="Image to convolve")
            lsstDebug.frame += 1

        if display and displaySciIm:
            disp = afwDisplay.Display(frame=lsstDebug.frame)
            disp.mtv(scienceMaskedImage, title="Image to not convolve")
            lsstDebug.frame += 1

        kernelCellSet = self._buildCellSet(templateMaskedImage,
                                           scienceMaskedImage,
                                           candidateList)

        if display and displaySpatialCells:
            diffimUtils.showKernelSpatialCells(scienceMaskedImage, kernelCellSet,
                                               symb="o", ctype=afwDisplay.CYAN, ctypeUnused=afwDisplay.YELLOW,
                                               ctypeBad=afwDisplay.RED, size=4, frame=lsstDebug.frame,
                                               title="Image to not convolve")
            lsstDebug.frame += 1

        if templateFwhmPix and scienceFwhmPix:
            self.log.info("Matching Psf FWHM %.2f -> %.2f pix", templateFwhmPix, scienceFwhmPix)

        if self.kConfig.useBicForKernelBasis:
            tmpKernelCellSet = self._buildCellSet(templateMaskedImage,
                                                  scienceMaskedImage,
                                                  candidateList)
            nbe = diffimTools.NbasisEvaluator(self.kConfig, templateFwhmPix, scienceFwhmPix)
            bicDegrees = nbe(tmpKernelCellSet, self.log)
            basisList = makeKernelBasisList(self.kConfig, templateFwhmPix, scienceFwhmPix,
                                            alardDegGauss=bicDegrees[0], metadata=self.metadata)
            del tmpKernelCellSet
        else:
            basisList = makeKernelBasisList(self.kConfig, templateFwhmPix, scienceFwhmPix,
                                            metadata=self.metadata)

        spatialSolution, psfMatchingKernel, backgroundModel = self._solve(kernelCellSet, basisList)

        psfMatchedMaskedImage = afwImage.MaskedImageF(templateMaskedImage.getBBox())
        doNormalize = False
        afwMath.convolve(psfMatchedMaskedImage, templateMaskedImage, psfMatchingKernel, doNormalize)
        return pipeBase.Struct(
            matchedImage=psfMatchedMaskedImage,
            psfMatchingKernel=psfMatchingKernel,
            backgroundModel=backgroundModel,
            kernelCellSet=kernelCellSet,
        )
Ejemplo n.º 53
0
    def detectFootprints(self, exposure, doSmooth=True, sigma=None, clearMask=True):
        """!Detect footprints.

        \param exposure Exposure to process; DETECTED{,_NEGATIVE} mask plane will be set in-place.
        \param doSmooth if True, smooth the image before detection using a Gaussian of width sigma
        \param sigma    sigma of PSF (pixels); used for smoothing and to grow detections;
            if None then measure the sigma of the PSF of the exposure
        \param clearMask Clear both DETECTED and DETECTED_NEGATIVE planes before running detection

        \return a lsst.pipe.base.Struct with fields:
        - positive: lsst.afw.detection.FootprintSet with positive polarity footprints (may be None)
        - negative: lsst.afw.detection.FootprintSet with negative polarity footprints (may be None)
        - numPos: number of footprints in positive or 0 if detection polarity was negative
        - numNeg: number of footprints in negative or 0 if detection polarity was positive
        - background: re-estimated background.  None if reEstimateBackground==False

        \throws lsst.pipe.base.TaskError if sigma=None and the exposure has no PSF
        """
        try:
            import lsstDebug
            display = lsstDebug.Info(__name__).display
        except ImportError:
            try:
                display
            except NameError:
                display = False

        if exposure is None:
            raise RuntimeError("No exposure for detection")

        maskedImage = exposure.getMaskedImage()
        region = maskedImage.getBBox()

        if clearMask:
            mask = maskedImage.getMask()
            mask &= ~(mask.getPlaneBitMask("DETECTED") | mask.getPlaneBitMask("DETECTED_NEGATIVE"))
            del mask

        if self.config.doTempLocalBackground:
            tempBgRes = self.tempLocalBackground.run(maskedImage)
            tempLocalBkgdImage = tempBgRes.background.getImage()

        if sigma is None:
            psf = exposure.getPsf()
            if psf is None:
                raise pipeBase.TaskError("exposure has no PSF; must specify sigma")
            shape = psf.computeShape()
            sigma = shape.getDeterminantRadius()

        self.metadata.set("sigma", sigma)
        self.metadata.set("doSmooth", doSmooth)

        if not doSmooth:
            convolvedImage = maskedImage.Factory(maskedImage)
            middle = convolvedImage
        else:
            # smooth using a Gaussian (which is separate, hence fast) of width sigma
            # make a SingleGaussian (separable) kernel with the 'sigma'
            psf = exposure.getPsf()
            kWidth = (int(sigma * 7 + 0.5) // 2) * 2 + 1 # make sure it is odd
            self.metadata.set("smoothingKernelWidth", kWidth)
            gaussFunc = afwMath.GaussianFunction1D(sigma)
            gaussKernel = afwMath.SeparableKernel(kWidth, kWidth, gaussFunc, gaussFunc)

            convolvedImage = maskedImage.Factory(maskedImage.getBBox())

            afwMath.convolve(convolvedImage, maskedImage, gaussKernel, afwMath.ConvolutionControl())
            #
            # Only search psf-smooth part of frame
            #
            goodBBox = gaussKernel.shrinkBBox(convolvedImage.getBBox())
            middle = convolvedImage.Factory(convolvedImage, goodBBox, afwImage.PARENT, False)
            #
            # Mark the parts of the image outside goodBBox as EDGE
            #
            self.setEdgeBits(maskedImage, goodBBox, maskedImage.getMask().getPlaneBitMask("EDGE"))

        fpSets = pipeBase.Struct(positive=None, negative=None)

        if self.config.thresholdPolarity != "negative":
            fpSets.positive = self.thresholdImage(middle, "positive")
        if self.config.reEstimateBackground or self.config.thresholdPolarity != "positive":
            fpSets.negative = self.thresholdImage(middle, "negative")

        for polarity, maskName in (("positive", "DETECTED"), ("negative", "DETECTED_NEGATIVE")):
            fpSet = getattr(fpSets, polarity)
            if fpSet is None:
                continue
            fpSet.setRegion(region)
            if self.config.nSigmaToGrow > 0:
                nGrow = int((self.config.nSigmaToGrow * sigma) + 0.5)
                self.metadata.set("nGrow", nGrow)
                fpSet = afwDet.FootprintSet(fpSet, nGrow, self.config.isotropicGrow)
            fpSet.setMask(maskedImage.getMask(), maskName)
            if not self.config.returnOriginalFootprints:
                setattr(fpSets, polarity, fpSet)

        fpSets.numPos = len(fpSets.positive.getFootprints()) if fpSets.positive is not None else 0
        fpSets.numNeg = len(fpSets.negative.getFootprints()) if fpSets.negative is not None else 0

        if self.config.thresholdPolarity != "negative":
            self.log.log(self.log.INFO, "Detected %d positive sources to %g sigma." %
                         (fpSets.numPos, self.config.thresholdValue*self.config.includeThresholdMultiplier))

        if self.config.doTempLocalBackground:
            maskedImage += tempLocalBkgdImage

        fpSets.background = None
        if self.config.reEstimateBackground:
            mi = exposure.getMaskedImage()
            bkgd = self.background.fitBackground(mi)

            if self.config.adjustBackground:
                self.log.log(self.log.WARN, "Fiddling the background by %g" % self.config.adjustBackground)

                bkgd += self.config.adjustBackground
            fpSets.background = bkgd
            self.log.log(self.log.INFO, "Resubtracting the background after object detection")

            mi -= bkgd.getImageF()
            del mi

        if self.config.thresholdPolarity == "positive":
            if self.config.reEstimateBackground:
                mask = maskedImage.getMask()
                mask &= ~mask.getPlaneBitMask("DETECTED_NEGATIVE")
                del mask
            fpSets.negative = None
        else:
            self.log.log(self.log.INFO, "Detected %d negative sources to %g %s" %
                         (fpSets.numNeg, self.config.thresholdValue,
                          ("DN" if self.config.thresholdType == "value" else "sigma")))

        if display:
            ds9.mtv(exposure, frame=0, title="detection")
            x0, y0 = exposure.getXY0()
            def plotPeaks(fps, ctype):
                if fps is None:
                    return
                with ds9.Buffering():
                    for fp in fps.getFootprints():
                        for pp in fp.getPeaks():
                            ds9.dot("+", pp.getFx() - x0, pp.getFy() - y0, ctype=ctype)
            plotPeaks(fpSets.positive, "yellow")
            plotPeaks(fpSets.negative, "red")

            if convolvedImage and display and display > 1:
                ds9.mtv(convolvedImage, frame=1, title="PSF smoothed")

        return fpSets
Ejemplo n.º 54
0
def doit(args):
    dataId = args
    print "# Running", dataId
 
    # I need to create a separate instance in each thread
    mapper = Mapper(root = "/lsst7/stripe82/dr7/runs/", calibRoot = None, outputRoot = None)
    butler = dafPersist.ButlerFactory(mapper = mapper).create()

    # Grab science pixels
    im     = butler.get(datasetType="fpC", dataId = dataId).convertF()

    # Remove the 128 pixel duplicate overlap between fields
    # See python/lsst/obs/sdss/processCcdSdss.py for guidance
    bbox    = im.getBBox()
    begin   = bbox.getBegin()
    extent  = bbox.getDimensions()
    extent -= afwGeom.Extent2I(0, 128)
    tbbox   = afwGeom.BoxI(begin, extent)
    im      = afwImage.ImageF(im, tbbox, True)

    # Remove 1000 count pedestal
    im    -= 1000.0 

    # Create image variance from gain
    calib, gain = butler.get(datasetType="tsField", dataId = dataId)
    var    = afwImage.ImageF(im, True)
    var   /= gain

    # Note I need to do a bit extra for the mask; I actually need to call
    # convertfpM with allPlanes = True to get all the SDSS info
    #
    # mask   = butler.get(datasetType="fpM", dataId = dataId)
    fpMFile = butler.mapper.map_fpM(dataId = dataId).getLocations()[0]
    mask    = convertfpM(fpMFile, True)
    # Remove the 128 pixel duplicate overlap...
    mask    = afwImage.MaskU(mask, tbbox, True)

    # We need this for the background estimation
    exp = afwImage.ExposureF(afwImage.MaskedImageF(im, mask, var))

    # Subtract off background, and scale by stdev
    # This will turn the image into "sigma"
    if False:
        ctrl      = afwMath.StatisticsControl(5.0, 5)
        bitPlanes = mask.getMaskPlaneDict().values()
        bitMask   = 2**bitPlanes[0]
        for plane in bitPlanes[1:]:
            bitMask |= 2**bitPlanes[plane]
        ctrl.setAndMask(bitMask)
        stat    = afwMath.makeStatistics(im, mask, afwMath.STDEVCLIP | afwMath.MEDIAN | afwMath.NPOINT, ctrl)
        stdev   = stat.getValue(afwMath.STDEVCLIP)
        bg      = stat.getValue(afwMath.MEDIAN)
    elif False:
        # It should be that afwMath.NPOINT = len(idx[0])
        # Not the case, exactly, so go with what you know
        idx     = np.where(mask.getArray() == 0)
        gdata   = im.getArray()[idx] 
        bg      = np.median(gdata)
        stdev   = 0.741 * (np.percentile(gdata, 75) - np.percentile(gdata, 25))
    else:
        # Do full-on background subtraction
        bgctrl = measAlg.BackgroundConfig(binSize=512, statisticsProperty="MEANCLIP", ignoredPixelMask=mask.getMaskPlaneDict().keys())
        bg, bgsubexp = measAlg.estimateBackground(exp, bgctrl, subtract=True)
        im = bgsubexp.getMaskedImage().getImage()
        sctrl = afwMath.StatisticsControl()
        sctrl.setAndMask(reduce(lambda x, y, mask=mask: x | mask.getPlaneBitMask(y), bgctrl.ignoredPixelMask, 0x0))
        stdev = afwMath.makeStatistics(im, mask, afwMath.STDEVCLIP, sctrl).getValue(afwMath.STDEVCLIP)
        im /= stdev

    # Decision point: do I send the convolution a MaskedImage, in which
    # case the mask is also spread, or just an Image, and not spread
    # the mask...  
    # 
    # I think for now I will not spread the mask so that it represents the
    # condition of the underlying pixels, not the Psf-filtered ones

    psf    = butler.get(datasetType="psField", dataId = dataId)
    wcs    = butler.get(datasetType="asTrans", dataId = dataId)

    # Image convolved with the Psf, i.e. maximum point source likelihood image
    cim    = afwImage.ImageF(im, True)
    afwMath.convolve(cim, im, psf.getKernel(), True)
    # The pixels that are "good" in the image, i.e. ignore borders
    cBBox  = psf.getKernel().shrinkBBox(cim.getBBox())
    cim    = afwImage.ImageF(cim, cBBox)
    mask   = afwImage.MaskU(mask, cBBox)
 
    # Create an ra,decl map for the good pixels
    raIm   = afwImage.ImageF(cim.getDimensions())
    decIm  = afwImage.ImageF(cim.getDimensions())
    nx, ny = cim.getDimensions()
    # But note that the Wcs expects their coordinates in the non-shrunk image
    x0     = cBBox.getBeginX()
    y0     = cBBox.getBeginY()
    x1     = cBBox.getEndX()
    y1     = cBBox.getEndY()
    for y in range(ny):
        for x in range(nx):
            ra, decl = getRaDecl(wcs, x+x0, y+y0)
            raIm.set(x, y, ra)
            decIm.set(x, y, decl) 

    run = dataId["run"]
    camcol = dataId["camcol"]
    field = dataId["field"]
    filterName = dataId["filter"]
    if doWriteSql:
        # Make the table inputs
        xll, yll = getRaDecl(wcs, 0 +x0, 0+ y0)
        xlr, ylr = getRaDecl(wcs, x1+x0, 0+ y0)
        xur, yur = getRaDecl(wcs, x1+x0, y1+y0)
        xul, yul = getRaDecl(wcs, 0 +x0, y1+y0)
        tc       = calib.getMidTime()
        t0       = dafBase.DateTime(tc.nsecs() - int(0.5 * calib.getExptime() * 1e9), dafBase.DateTime.TAI)
        t1       = dafBase.DateTime(tc.nsecs() + int(0.5 * calib.getExptime() * 1e9), dafBase.DateTime.TAI)

        # Magic for the day; 2**63 because BIGINT is signed
        fieldId  = int(md5.new(" ".join(map(str, [run, filterName, camcol, field]))).hexdigest(), 16) % 2**63

        pfile = "pixel-%06d-%s%s-%04d.csv" % (run, filterName, camcol, field)
        ffile = "field-%06d-%s%s-%04d.pgsql" % (run, filterName, camcol, field)
        pbuff = open(pfile, "w")
        fbuff = open(ffile, "w")
        fbuff.write("INSERT INTO fields (fieldId, run, camcol, field, filter, bbox, tmid, trange) VALUES\n")
        fbuff.write("  (%d, %d, %d, %d, '%s', ST_GeomFromText('POLYGON((\n" % (fieldId, run, camcol, field, filterName))
        fbuff.write("        %.9f %.9f, %.9f %.9f,\n" % (xll, yll, xlr, ylr))
        fbuff.write("        %.9f %.9f, %.9f %.9f,\n" % (xur, yur, xul, yul))
        fbuff.write("        %.9f %.9f))',3786),\n" % (xll, yll))
        fbuff.write("         '%s',\n" % (re.sub("T", " ", tc.toString())))
        fbuff.write("         '[%s, %s]');\n" % (re.sub("T", " ", t0.toString()), re.sub("T", " ", t1.toString())))

        for y in range(ny):
            for x in range(nx):
                # Note the different orders of raIm,decIm and cim,mask
                pbuff.write("%d, %.9f, %.9f, %f, %d\n" % (fieldId, raIm.get(x,y), decIm.get(x,y), cim.get(x,y), mask.get(x,y)))
        pbuff.close()
        fbuff.close()

    if False:
        cim.writeFits("image-%06d-%s%s-%04d.fits" % (run, filterName, camcol, field))
        mask.writeFits("mask-%06d-%s%s-%04d.fits" % (run, filterName, camcol, field))
        raIm.writeFits("ra-%06d-%s%s-%04d.fits" % (run, filterName, camcol, field))
        decIm.writeFits("dec-%06d-%s%s-%04d.fits" % (run, filterName, camcol, field))
Ejemplo n.º 55
0
    t_start = time.time()
    image = makeImageFromArray(data)
    dt = time.time() - t0
    print "DM image made in = %.2f us" %(dt*1e6) 
    t_total += dt
    
    
    t0 = time.time()
    sigma = 0.75
#     kWidth = (int(sigma * 7 + 0.5) // 2) * 2 + 1 # make sure it is odd
    kWidth = 5

####### discrete method
    gaussFunc = math.GaussianFunction1D(sigma)
    gaussKernel = math.SeparableKernel(kWidth, kWidth, gaussFunc, gaussFunc)
    math.convolve(image, image, gaussKernel, math.ConvolutionControl())
       
####### analytical method
#     kernel = math.AnalyticKernel(kWidth, kWidth, math.GaussianFunction2D(sigma, sigma, 0))
#     math.convolve(image, image, kernel, True, True)
   
    dt = time.time() - t0
    print "image smoothed in = %.2f us" %(dt*1e6) 
    t_total += dt

    ds9.mtv(image)
    
    #calculate basic stats
    t0 = time.time()
    basic_mean = np.std(data)
    basic_stddev = np.mean(data)
Ejemplo n.º 56
0
def brighterFatterCorrection(exposure, kernel, maxIter, threshold, applyGain):
    """Apply brighter fatter correction in place for the image.

    Parameters
    ----------
    exposure : `lsst.afw.image.Exposure`
        Exposure to have brighter-fatter correction applied.  Modified
        by this method.
    kernel : `numpy.ndarray`
        Brighter-fatter kernel to apply.
    maxIter : scalar
        Number of correction iterations to run.
    threshold : scalar
        Convergence threshold in terms of the sum of absolute
        deviations between an iteration and the previous one.
    applyGain : `Bool`
        If True, then the exposure values are scaled by the gain prior
        to correction.

    Notes
    -----
    This correction takes a kernel that has been derived from flat
    field images to redistribute the charge.  The gradient of the
    kernel is the deflection field due to the accumulated charge.

    Given the original image I(x) and the kernel K(x) we can compute
    the corrected image Ic(x) using the following equation:

    Ic(x) = I(x) + 0.5*d/dx(I(x)*d/dx(int( dy*K(x-y)*I(y))))

    To evaluate the derivative term we expand it as follows:

    0.5 * ( d/dx(I(x))*d/dx(int(dy*K(x-y)*I(y))) + I(x)*d^2/dx^2(int(dy* K(x-y)*I(y))) )

    Because we use the measured counts instead of the incident counts
    we apply the correction iteratively to reconstruct the original
    counts and the correction.  We stop iterating when the summed
    difference between the current corrected image and the one from
    the previous iteration is below the threshold.  We do not require
    convergence because the number of iterations is too large a
    computational cost.  How we define the threshold still needs to be
    evaluated, the current default was shown to work reasonably well
    on a small set of images.  For more information on the method see
    DocuShare Document-19407.

    The edges as defined by the kernel are not corrected because they
    have spurious values due to the convolution.
    """
    image = exposure.getMaskedImage().getImage()

    # The image needs to be units of electrons/holes
    with gainContext(exposure, image, applyGain):

        kLx = numpy.shape(kernel)[0]
        kLy = numpy.shape(kernel)[1]
        kernelImage = afwImage.ImageD(kLx, kLy)
        kernelImage.getArray()[:, :] = kernel
        tempImage = image.clone()

        nanIndex = numpy.isnan(tempImage.getArray())
        tempImage.getArray()[nanIndex] = 0.

        outImage = afwImage.ImageF(image.getDimensions())
        corr = numpy.zeros_like(image.getArray())
        prev_image = numpy.zeros_like(image.getArray())
        convCntrl = afwMath.ConvolutionControl(False, True, 1)
        fixedKernel = afwMath.FixedKernel(kernelImage)

        # Define boundary by convolution region.  The region that the correction will be
        # calculated for is one fewer in each dimension because of the second derivative terms.
        # NOTE: these need to use integer math, as we're using start:end as numpy index ranges.
        startX = kLx//2
        endX = -kLx//2
        startY = kLy//2
        endY = -kLy//2

        for iteration in range(maxIter):

            afwMath.convolve(outImage, tempImage, fixedKernel, convCntrl)
            tmpArray = tempImage.getArray()
            outArray = outImage.getArray()

            with numpy.errstate(invalid="ignore", over="ignore"):
                # First derivative term
                gradTmp = numpy.gradient(tmpArray[startY:endY, startX:endX])
                gradOut = numpy.gradient(outArray[startY:endY, startX:endX])
                first = (gradTmp[0]*gradOut[0] + gradTmp[1]*gradOut[1])[1:-1, 1:-1]

                # Second derivative term
                diffOut20 = numpy.diff(outArray, 2, 0)[startY:endY, startX + 1:endX - 1]
                diffOut21 = numpy.diff(outArray, 2, 1)[startY + 1:endY - 1, startX:endX]
                second = tmpArray[startY + 1:endY - 1, startX + 1:endX - 1]*(diffOut20 + diffOut21)

                corr[startY + 1:endY - 1, startX + 1:endX - 1] = 0.5*(first + second)

                tmpArray[:, :] = image.getArray()[:, :]
                tmpArray[nanIndex] = 0.
                tmpArray[startY:endY, startX:endX] += corr[startY:endY, startX:endX]

            if iteration > 0:
                diff = numpy.sum(numpy.abs(prev_image - tmpArray))

                if diff < threshold:
                    break
                prev_image[:, :] = tmpArray[:, :]

                #        if iteration == maxIter - 1:
                #            self.log.warn("Brighter fatter correction did not converge,
                #                          final difference %f" % diff)

                #    self.log.info("Finished brighter fatter in %d iterations" % (iteration + 1))
        image.getArray()[startY + 1:endY - 1, startX + 1:endX - 1] += \
            corr[startY + 1:endY - 1, startX + 1:endX - 1]
    def testDetection(self):
        """Test object detection"""
        #
        # Fix defects
        #
        # Mask known bad pixels
        #
        measAlgorithmsDir = lsst.utils.getPackageDir('meas_algorithms')
        badPixels = defects.policyToBadRegionList(os.path.join(measAlgorithmsDir,
                                                               "policy/BadPixels.paf"))
        # did someone lie about the origin of the maskedImage?  If so, adjust bad pixel list
        if self.XY0.getX() != self.mi.getX0() or self.XY0.getY() != self.mi.getY0():
            dx = self.XY0.getX() - self.mi.getX0()
            dy = self.XY0.getY() - self.mi.getY0()
            for bp in badPixels:
                bp.shift(-dx, -dy)

        algorithms.interpolateOverDefects(self.mi, self.psf, badPixels)
        #
        # Subtract background
        #
        bgGridSize = 64  # was 256 ... but that gives only one region and the spline breaks
        bctrl = afwMath.BackgroundControl(afwMath.Interpolate.NATURAL_SPLINE)
        bctrl.setNxSample(int(self.mi.getWidth()/bgGridSize) + 1)
        bctrl.setNySample(int(self.mi.getHeight()/bgGridSize) + 1)
        backobj = afwMath.makeBackground(self.mi.getImage(), bctrl)

        self.mi.getImage()[:] -= backobj.getImageF()
        #
        # Remove CRs
        #
        crConfig = algorithms.FindCosmicRaysConfig()
        algorithms.findCosmicRays(self.mi, self.psf, 0, pexConfig.makePolicy(crConfig))
        #
        # We do a pretty good job of interpolating, so don't propagagate the convolved CR/INTRP bits
        # (we'll keep them for the original CR/INTRP pixels)
        #
        savedMask = self.mi.getMask().Factory(self.mi.getMask(), True)
        saveBits = savedMask.getPlaneBitMask("CR") | \
            savedMask.getPlaneBitMask("BAD") | \
            savedMask.getPlaneBitMask("INTRP")  # Bits to not convolve
        savedMask &= saveBits

        msk = self.mi.getMask()
        msk &= ~saveBits  # Clear the saved bits
        del msk
        #
        # Smooth image
        #
        psf = algorithms.DoubleGaussianPsf(15, 15, self.FWHM/(2*math.sqrt(2*math.log(2))))

        cnvImage = self.mi.Factory(self.mi.getBBox())
        kernel = psf.getKernel()
        afwMath.convolve(cnvImage, self.mi, kernel, afwMath.ConvolutionControl())

        msk = cnvImage.getMask()
        msk |= savedMask  # restore the saved bits
        del msk

        threshold = afwDetection.Threshold(3, afwDetection.Threshold.STDEV)
        #
        # Only search the part of the frame that was PSF-smoothed
        #
        llc = lsst.geom.PointI(psf.getKernel().getWidth()//2, psf.getKernel().getHeight()//2)
        urc = lsst.geom.PointI(cnvImage.getWidth() - llc[0] - 1, cnvImage.getHeight() - llc[1] - 1)
        middle = cnvImage.Factory(cnvImage, lsst.geom.BoxI(llc, urc), afwImage.LOCAL)
        ds = afwDetection.FootprintSet(middle, threshold, "DETECTED")
        del middle
        #
        # Reinstate the saved (e.g. BAD) (and also the DETECTED | EDGE) bits in the unsmoothed image
        #
        savedMask[:] = cnvImage.getMask()
        msk = self.mi.getMask()
        msk |= savedMask
        del msk
        del savedMask

        if display:
            disp = afwDisplay.Display(frame=2)
            disp.mtv(self.mi, title=self._testMethodName + ": image")
            afwDisplay.Display(frame=3).mtv(cnvImage, title=self._testMethodName + ": cnvImage")

        #
        # Time to actually measure
        #
        schema = afwTable.SourceTable.makeMinimalSchema()
        sfm_config = measBase.SingleFrameMeasurementConfig()
        sfm_config.plugins = ["base_SdssCentroid", "base_CircularApertureFlux", "base_PsfFlux",
                              "base_SdssShape", "base_GaussianFlux",
                              "base_PixelFlags"]
        sfm_config.slots.centroid = "base_SdssCentroid"
        sfm_config.slots.shape = "base_SdssShape"
        sfm_config.slots.psfFlux = "base_PsfFlux"
        sfm_config.slots.gaussianFlux = None
        sfm_config.slots.apFlux = "base_CircularApertureFlux_3_0"
        sfm_config.slots.modelFlux = "base_GaussianFlux"
        sfm_config.slots.calibFlux = None
        sfm_config.plugins["base_SdssShape"].maxShift = 10.0
        sfm_config.plugins["base_CircularApertureFlux"].radii = [3.0]
        task = measBase.SingleFrameMeasurementTask(schema, config=sfm_config)
        measCat = afwTable.SourceCatalog(schema)
        # detect the sources and run with the measurement task
        ds.makeSources(measCat)
        self.exposure.setPsf(self.psf)
        task.run(measCat, self.exposure)

        self.assertGreater(len(measCat), 0)
        for source in measCat:
            if source.get("base_PixelFlags_flag_edge"):
                continue

            if display:
                disp.dot("+", source.getX(), source.getY())