示例#1
0
    def testSubImage(self):
        """Test getImage on a subregion of the full background image

        Using real image data is a cheap way to get a variable background
        """
        mi = self.getCfhtImage()

        bctrl = afwMath.BackgroundControl(mi.getWidth() // 128,
                                          mi.getHeight() // 128)
        backobj = afwMath.makeBackground(mi.getImage(), bctrl)
        subBBox = afwGeom.Box2I(afwGeom.Point2I(1000, 3000),
                                afwGeom.Extent2I(100, 100))

        bgFullImage = backobj.getImageF()
        self.assertEqual(bgFullImage.getBBox(), mi.getBBox())

        subFullArr = afwImage.ImageF(bgFullImage, subBBox).getArray()

        bgSubImage = backobj.getImageF(subBBox, bctrl.getInterpStyle())
        subArr = bgSubImage.getArray()

        # the pixels happen to be identical but it is safer not to rely on
        # that; close is good enough
        self.assertFloatsEqual(subArr, subFullArr)
示例#2
0
def makeTestImage(xsize=200, ysize=100, nCR=15):

    randArr = numpy.random.poisson(1000., xsize*ysize)
    randArr = numpy.array(randArr.reshape(ysize, xsize), dtype=numpy.float32)  # force to ImageF
    factory = measAlg.GaussianPsfFactory()
    factory.addWing = False
    psf = factory.apply(4)  # FWHM in pixels

    img = afwImage.makeImageFromArray(randArr)
    var = afwImage.ImageF(img, True)  # copy constructor
    mask = afwImage.Mask(xsize, ysize)

    xind = numpy.random.randint(0, xsize, nCR)
    yind = numpy.random.randint(0, ysize, nCR)

    # set some CRs
    for xi, yi in zip(xind, yind):
        xi, yi = int(xi), int(yi)
        img.set(xi, yi, 1e6)

    mi = afwImage.makeMaskedImage(img, mask, var)
    exp = afwImage.makeExposure(mi)
    exp.setPsf(psf)
    return exp
    def testObjectPlacement(self):
        """
        Test that GalSim places objects on the correct pixel by drawing
        images containing single objects and no background, reading those
        images back in, and comparing the flux-averaged centroids of the
        images with the expected pixel positions of the input objects.
        """
        scratchDir = tempfile.mkdtemp(dir=ROOT, prefix='testLSSTObjectPlacement-')
        if os.path.exists(scratchDir):
            shutil.rmtree(scratchDir)
        os.mkdir(scratchDir)

        detector = lsst_camera()['R:0,3 S:2,2']
        det_name = 'R03_S22'

        magNorm = 19.0

        pixel_transformer = DMtoCameraPixelTransformer()

        for band in 'ugrizy':
            obs = self.obs_dict[band]

            catName = os.path.join(scratchDir, 'placementCatalog.dat')
            imageRoot = os.path.join(scratchDir, 'placementImage')
            dbFileName = os.path.join(scratchDir, 'placementInputCatalog.dat')


            imageName = '%s_%s_%s.fits' % (imageRoot, det_name, obs.bandpass)

            ra_c, dec_c = raDecFromPixelCoordsLSST(2000.0, 2000.0,
                                                   detector.getName(),
                                                   band=obs.bandpass,
                                                   obs_metadata=obs)

            nSamples = 30
            rng = np.random.RandomState(42)
            fwhm = 0.12

            for iteration in range(nSamples):
                if os.path.exists(dbFileName):
                    os.unlink(dbFileName)

                ra_obj = ra_c + rng.random_sample()*0.2 - 0.1
                dec_obj = dec_c + rng.random_sample()*0.2 - 0.1

                dmx_wrong, dmy_wrong = pixelCoordsFromRaDec(ra_obj, dec_obj,
                                                            chipName=detector.getName(),
                                                            obs_metadata=obs,
                                                            camera=lsst_camera())

                dmx_pix, dmy_pix = pixelCoordsFromRaDecLSST(ra_obj, dec_obj,
                                                            chipName=detector.getName(),
                                                            obs_metadata=obs,
                                                            band=obs.bandpass)

                x_pix, y_pix = pixel_transformer.cameraPixFromDMPix(dmx_pix, dmy_pix,
                                                                    detector.getName())

                x_pix_wrong, y_pix_wrong = pixel_transformer.cameraPixFromDMPix(dmx_wrong, dmy_wrong,
                                                                                detector.getName())

                d_ra = 360.0*(ra_obj - obs.pointingRA)  # in arcseconds
                d_dec = 360.0*(dec_obj - obs.pointingDec)

                create_text_catalog(obs, dbFileName,
                                    np.array([d_ra]), np.array([d_dec]),
                                    mag_norm=[magNorm])

                db = LSSTPlacementFileDBObj(dbFileName, runtable='test')
                cat = LSSTPlacementCatalog(db, obs_metadata=obs)
                cat.camera_wrapper = LSSTCameraWrapper()
                psf = SNRdocumentPSF(fwhm=fwhm)
                cat.setPSF(psf)

                cat.write_catalog(catName)
                cat.write_images(nameRoot=imageRoot)

                im = afwImage.ImageF(imageName).getArray()
                tot_flux = im.sum()
                self.assertGreater(tot_flux, 10.0)

                y_centroid = sum([ii*im[ii,:].sum() for ii in range(im.shape[0])])/tot_flux
                x_centroid = sum([ii*im[:,ii].sum() for ii in range(im.shape[1])])/tot_flux
                dd = np.sqrt((x_pix-x_centroid)**2 + (y_pix-y_centroid)**2)
                self.assertLess(dd, 0.5*fwhm)

                dd_wrong = np.sqrt((x_pix_wrong-x_centroid)**2 +
                                   (y_pix_wrong-y_centroid)**2)

                self.assertLess(dd, dd_wrong)

                if os.path.exists(dbFileName):
                    os.unlink(dbFileName)
                if os.path.exists(catName):
                    os.unlink(catName)
                if os.path.exists(imageName):
                    os.unlink(imageName)

        if os.path.exists(scratchDir):
            shutil.rmtree(scratchDir)
示例#4
0
   >>> import ds9
   >>> ds9.run()
"""
from __future__ import absolute_import, division, print_function
import unittest

import lsst.utils.tests
import lsst.afw.image as afwImage
try:
    import lsst.afw.display.ds9 as ds9
except Exception:
    ds9 = None

if ds9:
    try:
        ds9.mtv(afwImage.ImageF(1, 1))
    except Exception as e:
        print("Unable to use ds9: %s" % e)
        ds9 = None


class DisplayTestCase(unittest.TestCase):
    """A test case for Display"""
    def setUp(self):
        pass

    def tearDown(self):
        pass

    @unittest.skipUnless(ds9, "You must setup display.ds9 to run this test")
    def testMtv(self):
示例#5
0
    def testRamp(self):
        """tests Laher's afwdata/Statistics/*.fits images (doubles)"""
        # make a ramping image (spline should be exact for linear increasing
        # image
        nx = 512
        ny = 512
        x0, y0 = 9876, 54321
        box = lsst.geom.Box2I(lsst.geom.Point2I(x0, y0),
                              lsst.geom.Extent2I(nx, ny))
        rampimg = afwImage.ImageF(box)
        dzdx, dzdy, z0 = 0.1, 0.2, 10000.0
        for x in range(nx):
            for y in range(ny):
                rampimg[x, y, afwImage.LOCAL] = dzdx * x + dzdy * y + z0

        # check corner, edge, and center pixels
        bctrl = afwMath.BackgroundControl(10, 10)
        bctrl.setNxSample(6)
        bctrl.setNySample(6)
        # large enough to entirely avoid clipping
        bctrl.getStatisticsControl().setNumSigmaClip(20.0)
        bctrl.getStatisticsControl().setNumIter(1)
        backobj = afwMath.makeBackground(rampimg, bctrl)

        if debugMode:
            print(rampimg.getArray())

        frame = 1
        for interp in ("CONSTANT", "LINEAR", "NATURAL_SPLINE", "AKIMA_SPLINE"):
            diff = backobj.getImageF(interp)
            if debugMode:
                afwDisplay.Display(frame=frame).mtv(
                    diff, title=self._testMethodName + " diff")
                frame += 1
            diff -= rampimg
            if debugMode:
                print(interp, diff.getArray().mean(), diff.getArray().std())
            if debugMode:
                afwDisplay.Display(frame=frame).mtv(
                    diff, title=self._testMethodName + " diff-ramping")
                frame += 1
        if debugMode:
            afwDisplay.Display(frame=frame).mtv(rampimg,
                                                title=self._testMethodName +
                                                " ramping")
            frame += 1
            afwDisplay.Display(frame=frame).mtv(backobj.getStatsImage(),
                                                title=self._testMethodName +
                                                " bkgd StatsImage")
            frame += 1

        xpixels = [0, nx // 2, nx - 1]
        ypixels = [0, ny // 2, ny - 1]
        for xpix in xpixels:
            for ypix in ypixels:
                testval = backobj.getImageF(
                    afwMath.Interpolate.CUBIC_SPLINE)[xpix, ypix,
                                                      afwImage.LOCAL]
                self.assertAlmostEqual(
                    testval / rampimg[xpix, ypix, afwImage.LOCAL], 1, 6)

        # Test pickle
        new = pickle.loads(pickle.dumps(backobj))
        self.assertBackgroundEqual(backobj, new)

        # Check creation of sub-image
        box = lsst.geom.Box2I(lsst.geom.Point2I(123, 45),
                              lsst.geom.Extent2I(45, 123))
        box.shift(lsst.geom.Extent2I(x0, y0))
        bgImage = backobj.getImageF("AKIMA_SPLINE")
        bgSubImage = afwImage.ImageF(bgImage, box)
        testImage = backobj.getImageF(box, "AKIMA_SPLINE")
        self.assertEqual(testImage.getXY0(), bgSubImage.getXY0())
        self.assertEqual(testImage.getDimensions(), bgSubImage.getDimensions())
        self.assertImagesEqual(testImage, bgSubImage)
示例#6
0
def subtractCrosstalkYagi(mi,
                          coeffs1List,
                          coeffs2List,
                          gainsPreampSig,
                          minPixelToMask=45000,
                          crosstalkStr="CROSSTALK"):
    """Subtract the crosstalk from MaskedImage mi given a set of coefficients
       based on procedure presented in Yagi et al. 2012, PASP in publication; arXiv:1210.8212
       The pixels affected by signal over minPixelToMask have the crosstalkStr bit set
    """

    #
    # These are the pixels that are bright enough to cause crosstalk (more precisely,
    # the ones that we label as causing crosstalk; in reality all pixels cause crosstalk)
    #
    if True:
        tempStr = "TEMP"  # mask plane used to record the bright pixels that we need to mask
        mi.getMask().addMaskPlane(tempStr)
        fs = afwDetect.FootprintSet(mi, afwDetect.Threshold(minPixelToMask),
                                    tempStr)

        mi.getMask().addMaskPlane(crosstalkStr)
        afwDisplay.setMaskPlaneColor(crosstalkStr, afwDisplay.MAGENTA)
        fs.setMask(mi.getMask(),
                   crosstalkStr)  # the crosstalkStr bit will now be set
        # whenever we subtract crosstalk
        crosstalk = mi.getMask().getPlaneBitMask(crosstalkStr)

    if True:
        # This python implementation is fairly fast
        image = mi.getImage()
        xtalk = afwImage.ImageF(image.getDimensions())
        xtalk.set(0)
        for i in range(4):
            xAmp, xOff = getAmplifier(xtalk, i, i)
            for j in range(4):
                if i == j:
                    continue
                gainRatio = gainsPreampSig[j] / gainsPreampSig[i]
                jAmp, jOff = getAmplifier(image, j, i)
                xAmp.scaledPlus(gainRatio * coeffs1List[i][j], jAmp)
                xOff.scaledPlus(gainRatio * coeffs2List[i][j], jOff)

        image -= xtalk
    else:
        nAmp = 4
        subtractCrosstalk(mi, nAmp, coeffs1List, coeffs2List, gainsPreampSig)

    #
    # Clear the crosstalkStr bit in the original bright pixels, where tempStr is set
    #
    msk = mi.getMask()
    temp = msk.getPlaneBitMask(tempStr)
    xtalk_temp = crosstalk | temp
    np_msk = msk.getArray()
    np_msk[np.where(
        np.bitwise_and(np_msk, xtalk_temp) == xtalk_temp)] &= ~crosstalk

    try:
        msk.removeAndClearMaskPlane(tempStr, True)  # added in afw #1853
    except AttributeError:
        afwDisplay.setMaskPlaneColor(tempStr, color="ignore")
示例#7
0
    def testEllipticalGaussian(self):
        """Test measuring elliptical aperture mags for an elliptical Gaussian"""

        width, height = 200, 200
        xcen, ycen = 0.5 * width, 0.5 * height
        #
        # Make the object
        #
        gal = afwImage.ImageF(afwGeom.ExtentI(width, height))
        a, b, theta = float(10), float(5), 20
        flux = 1e4
        I0 = flux / (2 * math.pi * a * b)

        c, s = math.cos(math.radians(theta)), math.sin(math.radians(theta))
        for y in range(height):
            for x in range(width):
                dx, dy = x - xcen, y - ycen
                u = c * dx + s * dy
                v = -s * dx + c * dy
                val = I0 * math.exp(-0.5 * ((u / a)**2 + (v / b)**2))
                if val < 0:
                    val = 0
                gal.set(x, y, val)

        objImg = afwImage.makeExposure(afwImage.makeMaskedImage(gal))
        del gal

        if display:
            frame = 0
            ds9.mtv(objImg, frame=frame, title="Elliptical")

        self.assertAlmostEqual(
            1.0,
            afwMath.makeStatistics(objImg.getMaskedImage().getImage(),
                                   afwMath.SUM).getValue() / flux)
        #
        # Now measure some annuli
        #
        sincConfig = measAlgorithms.SincFluxConfig(radius1=0.0,
                                                   radius2=0.0,
                                                   angle=math.radians(theta),
                                                   ellipticity=(1 - b / a))
        for r1, r2 in [
            (0., 0.45 * a),
            (0.45 * a, 1.0 * a),
            (1.0 * a, 2.0 * a),
            (2.0 * a, 3.0 * a),
            (3.0 * a, 5.0 * a),
            (3.0 * a, 10.0 * a),
        ]:
            sincConfig.radius1 = r1
            sincConfig.radius2 = r2
            schema = afwTable.SourceTable.makeMinimalSchema()
            mp = measAlgorithms.MeasureSourcesBuilder().addAlgorithm(
                sincConfig.makeControl()).build(schema)

            if display:  # draw the inner and outer boundaries of the aperture
                Mxx = 1
                Myy = (b / a)**2

                mxx, mxy, myy = c**2 * Mxx + s**2 * Myy, c * s * (
                    Mxx - Myy), s**2 * Mxx + c**2 * Myy
                for r in (r1, r2):
                    ds9.dot("@:%g,%g,%g" %
                            (r**2 * mxx, r**2 * mxy, r**2 * myy),
                            xcen,
                            ycen,
                            frame=frame)

            table = afwTable.SourceTable.make(schema)
            source = table.makeRecord()
            center = afwGeom.Point2D(xcen, ycen)

            mp.apply(source, objImg, center)

            self.assertAlmostEqual(
                math.exp(-0.5 * (r1 / a)**2) - math.exp(-0.5 * (r2 / a)**2),
                source["flux.sinc"] / flux, 5)
示例#8
0
    def processImagesForInsertion(self, fakeCat, wcs, psf, photoCalib, band,
                                  pixelScale):
        """Process images from files into the format needed for insertion.

        Parameters
        ----------
        fakeCat : `pandas.core.frame.DataFrame`
                    The catalog of fake sources to be input
        wcs : `lsst.afw.geom.skyWcs.skyWcs.SkyWc`
                    WCS to use to add fake sources
        psf : `lsst.meas.algorithms.coaddPsf.coaddPsf.CoaddPsf` or
              `lsst.meas.extensions.psfex.psfexPsf.PsfexPsf`
                    The PSF information to use to make the PSF images
        photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
                    Photometric calibration to be used to calibrate the fake sources
        band : `str`
                    The filter band that the observation was taken in.
        pixelScale : `float`
                    The pixel scale of the image the sources are to be added to.

        Returns
        -------
        galImages : `list`
                    A list of tuples of `lsst.afw.image.exposure.exposure.ExposureF` and
                    `lsst.geom.Point2D` of their locations.
                    For sources labelled as galaxy.
        starImages : `list`
                    A list of tuples of `lsst.afw.image.exposure.exposure.ExposureF` and
                    `lsst.geom.Point2D` of their locations.
                    For sources labelled as star.

        Notes
        -----
        The input fakes catalog needs to contain the absolute path to the image in the
        band that is being used to add images to. It also needs to have the R.A. and
        declination of the fake source in radians and the sourceType of the object.
        """
        galImages = []
        starImages = []

        self.log.info("Processing %d fake images" % len(fakeCat))

        for (imFile, sourceType, mag, x,
             y) in zip(fakeCat[band + "imFilename"].array,
                       fakeCat["sourceType"].array,
                       fakeCat[self.config.magVar % band].array,
                       fakeCat["x"].array, fakeCat["y"].array):

            im = afwImage.ImageF.readFits(imFile)

            xy = geom.Point2D(x, y)

            # We put these two PSF calculations within this same try block so that we catch cases
            # where the object's position is outside of the image.
            try:
                correctedFlux = psf.computeApertureFlux(
                    self.config.calibFluxRadius, xy)
                psfKernel = psf.computeKernelImage(xy).getArray()
                psfKernel /= correctedFlux

            except InvalidParameterError:
                self.log.info("%s at %0.4f, %0.4f outside of image" %
                              (sourceType, x, y))
                continue

            psfIm = galsim.InterpolatedImage(galsim.Image(psfKernel),
                                             scale=pixelScale)
            galsimIm = galsim.InterpolatedImage(galsim.Image(im.array),
                                                scale=pixelScale)
            convIm = galsim.Convolve([galsimIm, psfIm])

            try:
                outIm = convIm.drawImage(scale=pixelScale,
                                         method="real_space").array
            except (galsim.errors.GalSimFFTSizeError, MemoryError):
                continue

            imSum = np.sum(outIm)
            divIm = outIm / imSum

            try:
                flux = photoCalib.magnitudeToInstFlux(mag, xy)
            except LogicError:
                flux = 0

            imWithFlux = flux * divIm

            if sourceType == b"galaxy":
                galImages.append((afwImage.ImageF(imWithFlux), xy))
            if sourceType == b"star":
                starImages.append((afwImage.ImageF(imWithFlux), xy))

        return galImages, starImages
示例#9
0
    def bypass_raw(self, datasetType, pythonType, location, dataId):
        """Magic method that is called automatically if it exists.
        """
        from lsst.ip.isr import AssembleCcdTask

        config = AssembleCcdTask.ConfigClass()
        config.doTrim = False

        assembleTask = AssembleCcdTask(config=config)
        logger = lsst.log.Log.getLogger("ZtfMapper")

        # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

        assert len(location.getLocations()
                   ) == 1  # KTL says that this is always true, but check
        relativeFileName = location.getLocations()[0]
        if location.storage.exists(relativeFileName):
            fileName = location.storage.locationWithRoot(relativeFileName)
            data = afwImage.ImageF(fileName, hdu=1)
            data = pythonType(afwImage.MaskedImageF(data))
        else:
            raise IOError(f"Unable to find {relativeFileName}")

        # Get the Detector
        detector = self.camera[self._extractDetectorName(dataId)]
        #
        # Read all the data
        #
        ampDict = {}
        for i, amp in enumerate(detector, 1):
            ampExp = pythonType(amp.getRawBBox())
            ampExp.setDetector(detector)
            ampDict[amp.getName()] = ampExp

            hdu = amp.get('hdu')
            if i == 1:
                assert i == hdu  # don't read twice
                data = data.image
            else:
                data = afwImage.ImageF(fileName, hdu=hdu)

            ampExp[amp.getRawDataBBox()].image = data

            bias = afwImage.ImageF(fileName, hdu=hdu + 4)
            ampExp[amp.getRawHorizontalOverscanBBox()].image = bias

        exposure = assembleTask.assembleCcd(ampDict)

        md = afwImage.readMetadata(fileName, hdu=0)
        fix_header(md, translator_class=self.translatorClass)
        exposure.setMetadata(md)

        visitInfo = ZtfMakeRawVisitInfo(logger)(md)
        exposure.getInfo().setVisitInfo(visitInfo)

        boresight = visitInfo.getBoresightRaDec()
        if boresight.isFinite():
            exposure.setWcs(
                getWcsFromDetector(exposure.getDetector(),
                                   boresight,
                                   180 * geom.degrees,
                                   flipX=True))
        else:
            logger.warn(
                f"Unable to set WCS for {dataId} from header as RA/Dec/Angle are unavailable"
            )

        return exposure
示例#10
0
    def __init__(self, image, nSamples=1000, contrast=0.25):
        if not hasattr(image, "getArray"):
            image = afwImage.ImageF(image)
        z1, z2 = getZScale(image, nSamples, contrast)

        LinearMapping.__init__(self, z1, z2, image)
示例#11
0
    def check_placement(self, imageName, raList, decList, fwhmList,
                        countList, gain,
                        detector, camera, obs, epoch=2000.0):
        """
        Read in a FITS image and a list of objects meant to be on that
        image.  Verify that the objects were placed at the correct pixel
        by counting up all of the flux within 2 fwhm of each object's
        expected location and verifying it with the counts expected for
        that object.

        @param [in] imageName is the name of the FITS file to be read in

        @param [in] raList is a numpy array of the RA coordinates of the objects
        in the image (in radians)

        @param [in] decList is a numpy array of the Dec coordinates of the objects
        in the image (in radians)

        @param [in] fwhmList is a list of the Full Width at Half Maximum of
        each object in arcseconds

        @param [in] countList is a list of the counts expected for each object

        @param [in] gain is the gain of the detector (electrons per ADU)

        @param [in] detector is an instantiation of the afw.cameraGeom Detector
        class characterizing the detector corresponding to this image

        @param [in] camera is an instantiation of the afw.cameraGeom Camera class
        characterizing the camera to which detector belongs

        @param [in] obs is an instantiation of ObservationMetaData characterizing
        the telescope pointing

        @param [in] epoch is the epoch in Julian years of the equinox against which
        RA and Dec are measured.

        Raises an exception of the counts detected for each object differs from
        the expected amount by more than 3 sigma.
        """

        im = afwImage.ImageF(imageName).getArray()
        activePixels = np.where(im > 1.0e-10)

        # I know this seems backwards, but the way numpy handles arrays,
        # the first index is the row (i.e. the y coordinate)
        imXList = activePixels[1]
        imYList = activePixels[0]

        nameList = [detector.getName()]*len(raList)
        xPixList, yPixList = _pixelCoordsFromRaDec(raList, decList,
                                                   chipName=nameList,
                                                   camera=camera,
                                                   obs_metadata=obs,
                                                   epoch=epoch)

        for rr, dd, xx, yy, fwhm, cc in \
        zip(raList, decList, xPixList, yPixList, fwhmList, countList):

            countSigma = np.sqrt(cc/gain)

            imNameList = [detector.getName()]*len(imXList)
            raImList, decImList = _raDecFromPixelCoords(imXList, imYList,
                                                        imNameList,
                                                        camera=camera,
                                                        obs_metadata=obs,
                                                        epoch=epoch)

            distanceList = arcsecFromRadians(haversine(raImList, decImList, rr, dd))

            fluxArray = np.array([im[imYList[ix]][imXList[ix]]
                                  for ix in range(len(distanceList))
                                  if distanceList[ix] < 2.0*fwhm])

            totalFlux = fluxArray.sum()
            msg = 'totalFlux %e should be %e diff/sigma %e' \
                  % (totalFlux, cc, np.abs(totalFlux-cc)/countSigma)

            self.assertLess(np.abs(totalFlux-cc), 3.0*countSigma, msg=msg)
示例#12
0
    def get_flux_in_half_light_radius(self,
                                      fileName,
                                      hlr,
                                      detector,
                                      camera,
                                      obs,
                                      epoch=2000.0):
        """
        Read in a FITS image.  Return the total flux in that image as well as the flux contained
        within a specified radius of the maximum pixel of the image.

        @param [in] fileName is the name of the FITS file to be read in

        @param [in] hlr is the half light radius to be tested (in arc seconds)

        @param [in] detector is an instantiation of the afw.cameraGeom Detector
        class characterizing the detector corresponding to this image

        @param [in] camera is an instantiation of the afw.cameraGeom Camera class
        characterizing the camera to which detector belongs

        @param [in] obs is an instantiation of ObservationMetaData characterizing
        the telescope pointing

        @param [in] epoch is the epoch in Julian years of the equinox against which
        RA and Dec are measured.

        @param [out] totalFlux is the total number of counts in the images

        @param [out] measuredHalfFlux is the measured flux within hlr of the maximum pixel
        """

        im = afwImage.ImageF(fileName).getArray()
        totalFlux = im.sum()

        _maxPixel = np.array(
            [im.argmax() / im.shape[1],
             im.argmax() % im.shape[1]])
        maxPixel = np.array([_maxPixel[1], _maxPixel[0]])

        raMax, decMax = _raDecFromPixelCoords(maxPixel[0:1],
                                              maxPixel[1:2],
                                              [detector.getName()],
                                              camera=camera,
                                              obs_metadata=obs,
                                              epoch=epoch)

        activePoints = np.where(im > 1.0e-10)
        self.assertGreater(len(activePoints), 0)

        xPixList = activePoints[
            1]  # this looks backwards, but remember: the way numpy handles
        yPixList = activePoints[
            0]  # arrays, the first index indicates what row it is in (the y coordinate)
        chipNameList = [detector.getName()] * len(xPixList)

        raList, decList = _raDecFromPixelCoords(xPixList,
                                                yPixList,
                                                chipNameList,
                                                camera=camera,
                                                obs_metadata=obs,
                                                epoch=epoch)

        distanceList = arcsecFromRadians(
            haversine(raList, decList, raMax[0], decMax[0]))

        dexContained = [ix for ix, dd in enumerate(distanceList) if dd <= hlr]
        measuredHalfFlux = np.array(
            [im[yPixList[dex]][xPixList[dex]] for dex in dexContained]).sum()
        return totalFlux, measuredHalfFlux
示例#13
0
 def setUp(self):
     np.random.seed(1)
     self.val = 10
     self.image = afwImage.ImageF(lsst.geom.Box2I(
         lsst.geom.Point2I(1000, 500), lsst.geom.Extent2I(100, 200)))
     self.image.set(self.val)
def main():
    '''
    Runs the deblender and creates plots for the "design document",
    doc/design.tex.  See the file NOTES for how to get set up to the
    point where you can actually run this on data.
    '''

    from optparse import OptionParser
    parser = OptionParser()
    parser.add_option('--root',
                      dest='root',
                      help='Root directory for Subaru data')
    parser.add_option('--outroot',
                      '-o',
                      dest='outroot',
                      help='Output root directory for Subaru data')
    parser.add_option('--sources', help='Read a FITS table of sources')
    parser.add_option('--calexp', help='Read a FITS calexp')
    parser.add_option('--psf', help='Read a FITS PSF')

    parser.add_option('--drill',
                      '-D',
                      dest='drill',
                      action='append',
                      type=str,
                      default=[],
                      help='Drill down on individual source IDs')
    parser.add_option(
        '--drillxy',
        dest='drillxy',
        action='append',
        type=str,
        default=[],
        help='Drill down on individual source positions, eg 132,46;54,67')
    parser.add_option('--visit',
                      dest='visit',
                      type=int,
                      default=108792,
                      help='Suprimecam visit id')
    parser.add_option('--ccd',
                      dest='ccd',
                      type=int,
                      default=5,
                      help='Suprimecam CCD number')
    parser.add_option('--prefix',
                      dest='prefix',
                      default='design-',
                      help='plot filename prefix')
    parser.add_option('--suffix',
                      dest='suffix',
                      default=None,
                      help='plot filename suffix (default: ".png")')
    parser.add_option(
        '--pat',
        dest='pat',
        help=
        'Plot filename pattern: eg, "design-%(pid)04i-%(name).png"; overrides --prefix and --suffix'
    )
    parser.add_option('--pdf',
                      dest='pdf',
                      action='store_true',
                      default=False,
                      help='save in PDF format?')
    parser.add_option('-v', dest='verbose', action='store_true')
    parser.add_option('--figw',
                      dest='figw',
                      type=float,
                      help='Figure window width (inches)',
                      default=4.)
    parser.add_option('--figh',
                      dest='figh',
                      type=float,
                      help='Figure window height (inches)',
                      default=4.)
    parser.add_option('--order',
                      dest='order',
                      type=str,
                      help='Child order: eg 3,0,1,2')

    parser.add_option('--sdss',
                      dest='sec',
                      action='store_const',
                      const='sdss',
                      help='Produce plots for the SDSS section.')
    parser.add_option('--mono',
                      dest='sec',
                      action='store_const',
                      const='mono',
                      help='Produce plots for the "monotonic" section.')
    parser.add_option('--median',
                      dest='sec',
                      action='store_const',
                      const='median',
                      help='Produce plots for the "median filter" section.')
    parser.add_option('--ramp',
                      dest='sec',
                      action='store_const',
                      const='ramp',
                      help='Produce plots for the "ramp edges" section.')
    parser.add_option(
        '--ramp2',
        dest='sec',
        action='store_const',
        const='ramp2',
        help='Produce plots for the "ramp edges + stray flux" section.')
    parser.add_option('--patch',
                      dest='sec',
                      action='store_const',
                      const='patch',
                      help='Produce plots for the "patch edges" section.')

    opt, args = parser.parse_args()

    # Logging
    if opt.verbose:
        lsst.log.setLevel('', lsst.log.DEBUG)
    else:
        lsst.log.setLevel('', lsst.log.INFO)

    if opt.sec is None:
        opt.sec = 'sdss'
    if opt.pdf:
        if opt.suffix is None:
            opt.suffix = ''
        opt.suffix += '.pdf'
    if not opt.suffix:
        opt.suffix = '.png'

    if opt.pat:
        plotpattern = opt.pat
    else:
        plotpattern = opt.prefix + '%(pid)04i-%(name)s' + opt.suffix

    if opt.order is not None:
        opt.order = [int(x) for x in opt.order.split(',')]
        invorder = np.zeros(len(opt.order))
        invorder[opt.order] = np.arange(len(opt.order))

    def mapchild(i):
        if opt.order is None:
            return i
        return invorder[i]

    def savefig(pid, figname):
        fn = plotpattern % dict(pid=pid, name=figname)
        plt.savefig(fn)

    # Load data using the butler, if desired
    dr = None
    if opt.sources is None or opt.calexp is None:
        print('Creating DataRef...')
        dr = getSuprimeDataref(opt.visit,
                               opt.ccd,
                               rootdir=opt.root,
                               outrootdir=opt.outroot)
        print('Got', dr)

    # Which parent ids / deblend families are we going to plot?
    keepids = None
    if len(opt.drill):
        keepids = []
        for d in opt.drill:
            for dd in d.split(','):
                keepids.append(int(dd))
        print('Keeping parent ids', keepids)

    keepxys = None
    if len(opt.drillxy):
        keepxys = []
        for d in opt.drillxy:
            for dd in d.split(';'):
                xy = dd.split(',')
                assert (len(xy) == 2)
                keepxys.append((int(xy[0]), int(xy[1])))
        print('Keeping parents at xy', keepxys)

    # Read from butler or local file
    cat = readCatalog(opt.sources,
                      None,
                      dataref=dr,
                      keepids=keepids,
                      keepxys=keepxys,
                      patargs=dict(visit=opt.visit, ccd=opt.ccd))
    print('Got', len(cat), 'sources')

    # Load data from butler or local files
    if opt.calexp is not None:
        print('Reading exposure from', opt.calexp)
        exposure = afwImage.ExposureF(opt.calexp)
    else:
        exposure = dr.get('calexp')
    print('Exposure', exposure)
    mi = exposure.getMaskedImage()

    if opt.psf is not None:
        print('Reading PSF from', opt.psf)
        psf = afwDet.Psf.readFits(opt.psf)
        print('Got', psf)
    elif dr:
        psf = dr.get('psf')
    else:
        psf = exposure.getPsf()

    sigma1 = get_sigma1(mi)

    fams = getFamilies(cat)
    print(len(fams), 'deblend families')

    if False:
        for j, (parent, children) in enumerate(fams):
            print('parent', parent)
            print('children', children)
            plotDeblendFamily(mi,
                              parent,
                              children,
                              cat,
                              sigma1,
                              ellipses=False)
            fn = '%04i.png' % parent.getId()
            plt.savefig(fn)
            print('wrote', fn)

    def nlmap(X):
        return np.arcsinh(X / (3. * sigma1))

    def myimshow(im, **kwargs):
        kwargs = kwargs.copy()
        mn = kwargs.get('vmin', -5 * sigma1)
        kwargs['vmin'] = nlmap(mn)
        mx = kwargs.get('vmax', 100 * sigma1)
        kwargs['vmax'] = nlmap(mx)
        plt.imshow(nlmap(im), **kwargs)

    plt.figure(figsize=(opt.figw, opt.figh))
    plt.subplot(1, 1, 1)
    plt.subplots_adjust(left=0.01,
                        right=0.99,
                        bottom=0.01,
                        top=0.99,
                        wspace=0.05,
                        hspace=0.1)

    # Make plots for each deblend family.

    for j, (parent, children) in enumerate(fams):
        print('parent', parent.getId())
        print('children', [ch.getId() for ch in children])
        print('parent x,y', parent.getX(), parent.getY())

        pid = parent.getId()
        fp = parent.getFootprint()
        bb = fp.getBBox()
        pim = footprintToImage(parent.getFootprint(), mi).getArray()
        pext = getExtent(bb)
        imargs = dict(interpolation='nearest',
                      origin='lower',
                      vmax=pim.max() * 0.95,
                      vmin=-3. * sigma1)
        pksty = dict(linestyle='None',
                     marker='+',
                     color='r',
                     mew=3,
                     ms=20,
                     alpha=0.6)

        plt.clf()
        myimshow(afwImage.ImageF(mi.getImage(), bb).getArray(), **imargs)
        plt.gray()
        plt.xticks([])
        plt.yticks([])
        savefig(pid, 'image')

        # Parent footprint
        plt.clf()
        myimshow(pim, extent=pext, **imargs)
        plt.gray()
        pks = fp.getPeaks()
        plt.plot([pk.getIx() for pk in pks], [pk.getIy() for pk in pks],
                 **pksty)
        plt.xticks([])
        plt.yticks([])
        plt.axis(pext)
        savefig(pid, 'parent')

        from lsst.meas.deblender.baseline import deblend

        xc = int((bb.getMinX() + bb.getMaxX()) / 2.)
        yc = int((bb.getMinY() + bb.getMaxY()) / 2.)
        if hasattr(psf, 'getFwhm'):
            psf_fwhm = psf.getFwhm(xc, yc)
        else:
            psf_fwhm = psf.computeShape().getDeterminantRadius() * 2.35

        # Each section of the design doc runs the deblender with different args.

        kwargs = dict(sigma1=sigma1, verbose=opt.verbose, getTemplateSum=True)

        basic = kwargs.copy()
        basic.update(fit_psfs=False,
                     median_smooth_template=False,
                     monotonic_template=False,
                     lstsq_weight_templates=False,
                     assignStrayFlux=False,
                     rampFluxAtEdge=False,
                     patchEdges=False)

        if opt.sec == 'sdss':
            # SDSS intro
            kwargs = basic
            kwargs.update(lstsq_weight_templates=True)

        elif opt.sec == 'mono':
            kwargs = basic
            kwargs.update(lstsq_weight_templates=True, monotonic_template=True)
        elif opt.sec == 'median':
            kwargs = basic
            kwargs.update(lstsq_weight_templates=True,
                          median_smooth_template=True,
                          monotonic_template=True)
        elif opt.sec == 'ramp':
            kwargs = basic
            kwargs.update(median_smooth_template=True,
                          monotonic_template=True,
                          rampFluxAtEdge=True)

        elif opt.sec == 'ramp2':
            kwargs = basic
            kwargs.update(median_smooth_template=True,
                          monotonic_template=True,
                          rampFluxAtEdge=True,
                          assignStrayFlux=True)

        elif opt.sec == 'patch':
            kwargs = basic
            kwargs.update(median_smooth_template=True,
                          monotonic_template=True,
                          patchEdges=True)

        else:
            raise 'Unknown section: "%s"' % opt.sec

        print('Running deblender with kwargs:', kwargs)
        res = deblend(fp, mi, psf, psf_fwhm, **kwargs)
        # print('got result with', [x for x in dir(res) if not x.startswith('__')])
        # for pk in res.peaks:
        #     print('got peak with', [x for x in dir(pk) if not x.startswith('__')])
        #     print('  deblend as psf?', pk.deblend_as_psf)

        # Find bounding-box of all templates.
        tbb = fp.getBBox()
        for pkres, pk in zip(res.peaks, pks):
            tbb.include(pkres.template_foot.getBBox())
        print('Bounding-box of all templates:', tbb)

        # Sum-of-templates plot
        tsum = np.zeros((tbb.getHeight(), tbb.getWidth()))
        tx0, ty0 = tbb.getMinX(), tbb.getMinY()

        # Sum-of-deblended children plot(s)
        # "heavy" bbox == template bbox.
        hsum = np.zeros((tbb.getHeight(), tbb.getWidth()))
        hsum2 = np.zeros((tbb.getHeight(), tbb.getWidth()))

        # Sum of templates from the deblender itself
        plt.clf()
        t = res.templateSum
        myimshow(t.getArray(), extent=getExtent(t.getBBox()), **imargs)
        plt.gray()
        plt.xticks([])
        plt.yticks([])
        savefig(pid, 'tsum1')

        # Make plots for each deblended child (peak)

        k = 0
        for pkres, pk in zip(res.peaks, pks):

            heavy = pkres.get_flux_portion()
            if heavy is None:
                print('Child has no HeavyFootprint -- skipping')
                continue

            kk = mapchild(k)

            w = pkres.template_weight

            cfp = pkres.template_foot
            cbb = cfp.getBBox()
            cext = getExtent(cbb)

            # Template image
            tim = pkres.template_mimg.getImage()
            timext = cext
            tim = tim.getArray()

            (x0, x1, y0, y1) = timext
            print('tim ext', timext)
            tsum[y0 - ty0:y1 - ty0, x0 - tx0:x1 - tx0] += tim

            # "Heavy" image -- flux assigned to child
            him = footprintToImage(heavy).getArray()
            hext = getExtent(heavy.getBBox())

            (x0, x1, y0, y1) = hext
            hsum[y0 - ty0:y1 - ty0, x0 - tx0:x1 - tx0] += him

            # "Heavy" without stray flux
            h2 = pkres.get_flux_portion(strayFlux=False)
            him2 = footprintToImage(h2).getArray()
            hext2 = getExtent(h2.getBBox())
            (x0, x1, y0, y1) = hext2
            hsum2[y0 - ty0:y1 - ty0, x0 - tx0:x1 - tx0] += him2

            if opt.sec == 'median':
                try:
                    med = pkres.median_filtered_template
                except Exception:
                    med = pkres.orig_template

                for im, nm in [(pkres.orig_template, 'symm'), (med, 'med')]:
                    # print('im:', im)
                    plt.clf()
                    myimshow(im.getArray(), extent=cext, **imargs)
                    plt.gray()
                    plt.xticks([])
                    plt.yticks([])
                    plt.plot([pk.getIx()], [pk.getIy()], **pksty)
                    plt.axis(pext)
                    savefig(pid, nm + '%i' % (kk))

            # Template
            plt.clf()
            myimshow(pkres.template_mimg.getImage().getArray() / w,
                     extent=cext,
                     **imargs)
            plt.gray()
            plt.xticks([])
            plt.yticks([])
            plt.plot([pk.getIx()], [pk.getIy()], **pksty)
            plt.axis(pext)
            savefig(pid, 't%i' % (kk))

            # Weighted template
            plt.clf()
            myimshow(tim, extent=cext, **imargs)
            plt.gray()
            plt.xticks([])
            plt.yticks([])
            plt.plot([pk.getIx()], [pk.getIy()], **pksty)
            plt.axis(pext)
            savefig(pid, 'tw%i' % (kk))

            # "Heavy"
            plt.clf()
            myimshow(him, extent=hext, **imargs)
            plt.gray()
            plt.xticks([])
            plt.yticks([])
            plt.plot([pk.getIx()], [pk.getIy()], **pksty)
            plt.axis(pext)
            savefig(pid, 'h%i' % (kk))

            # Original symmetric template
            plt.clf()
            t = pkres.orig_template
            foot = pkres.orig_foot
            myimshow(t.getArray(), extent=getExtent(foot.getBBox()), **imargs)
            plt.gray()
            plt.xticks([])
            plt.yticks([])
            plt.plot([pk.getIx()], [pk.getIy()], **pksty)
            plt.axis(pext)
            savefig(pid, 'o%i' % (kk))

            if opt.sec == 'patch' and pkres.patched:
                pass

            if opt.sec in ['ramp', 'ramp2'] and pkres.has_ramped_template:

                # Ramped template
                plt.clf()
                t = pkres.ramped_template
                myimshow(t.getArray(), extent=getExtent(t.getBBox()), **imargs)
                plt.gray()
                plt.xticks([])
                plt.yticks([])
                plt.plot([pk.getIx()], [pk.getIy()], **pksty)
                plt.axis(pext)
                savefig(pid, 'r%i' % (kk))

                # Median-filtered template
                plt.clf()
                t = pkres.median_filtered_template
                myimshow(t.getArray(), extent=getExtent(t.getBBox()), **imargs)
                plt.gray()
                plt.xticks([])
                plt.yticks([])
                plt.plot([pk.getIx()], [pk.getIy()], **pksty)
                plt.axis(pext)
                savefig(pid, 'med%i' % (kk))

                # Assigned flux
                plt.clf()
                t = pkres.portion_mimg.getImage()
                myimshow(t.getArray(), extent=getExtent(t.getBBox()), **imargs)
                plt.gray()
                plt.xticks([])
                plt.yticks([])
                plt.plot([pk.getIx()], [pk.getIy()], **pksty)
                plt.axis(pext)
                savefig(pid, 'p%i' % (kk))

            if opt.sec == 'ramp2':
                # stray flux
                if pkres.stray_flux is not None:
                    s = pkres.stray_flux
                    strayim = footprintToImage(s).getArray()
                    strayext = getExtent(s.getBBox())

                    plt.clf()
                    myimshow(strayim, extent=strayext, **imargs)
                    plt.gray()
                    plt.xticks([])
                    plt.yticks([])
                    plt.plot([pk.getIx()], [pk.getIy()], **pksty)
                    plt.axis(pext)
                    savefig(pid, 's%i' % (kk))

                    # Assigned flux, omitting stray flux.
                    plt.clf()
                    myimshow(him2, extent=hext2, **imargs)
                    plt.gray()
                    plt.xticks([])
                    plt.yticks([])
                    plt.plot([pk.getIx()], [pk.getIy()], **pksty)
                    plt.axis(pext)
                    savefig(pid, 'hb%i' % (kk))

            k += 1

        # sum of templates
        plt.clf()
        myimshow(tsum, extent=getExtent(tbb), **imargs)
        plt.gray()
        plt.xticks([])
        plt.yticks([])
        plt.plot([pk.getIx() for pk in pks], [pk.getIy() for pk in pks],
                 **pksty)
        plt.axis(pext)
        savefig(pid, 'tsum')

        # sum of assigned flux
        plt.clf()
        myimshow(hsum, extent=getExtent(tbb), **imargs)
        plt.gray()
        plt.xticks([])
        plt.yticks([])
        plt.plot([pk.getIx() for pk in pks], [pk.getIy() for pk in pks],
                 **pksty)
        plt.axis(pext)
        savefig(pid, 'hsum')

        plt.clf()
        myimshow(hsum2, extent=getExtent(tbb), **imargs)
        plt.gray()
        plt.xticks([])
        plt.yticks([])
        plt.plot([pk.getIx() for pk in pks], [pk.getIy() for pk in pks],
                 **pksty)
        plt.axis(pext)
        savefig(pid, 'hsum2')

        k = 0
        for pkres, pk in zip(res.peaks, pks):
            heavy = pkres.get_flux_portion()
            if heavy is None:
                continue

            print('Template footprint:', pkres.template_foot.getBBox())
            print('Template img:', pkres.template_mimg.getBBox())
            print('Heavy footprint:', heavy.getBBox())

            cfp = pkres.template_foot
            cbb = cfp.getBBox()
            cext = getExtent(cbb)
            tim = pkres.template_mimg.getImage().getArray()
            (x0, x1, y0, y1) = cext

            frac = tim / tsum[y0 - ty0:y1 - ty0, x0 - tx0:x1 - tx0]

            msk = afwImage.ImageF(cbb.getWidth(), cbb.getHeight())
            msk.setXY0(cbb.getMinX(), cbb.getMinY())
            afwDet.setImageFromFootprint(msk, cfp, 1.)
            msk = msk.getArray()
            frac[msk == 0.] = np.nan

            # Fraction of flux assigned to this child.
            plt.clf()
            plt.imshow(frac,
                       extent=cext,
                       interpolation='nearest',
                       origin='lower',
                       vmin=0,
                       vmax=1)
            # plt.plot([x0,x0,x1,x1,x0], [y0,y1,y1,y0,y0], 'k-')
            plt.gray()
            plt.xticks([])
            plt.yticks([])
            plt.plot([pk.getIx()], [pk.getIy()], **pksty)
            plt.gca().set_axis_bgcolor((0.9, 0.9, 0.5))
            plt.axis(pext)
            savefig(pid, 'f%i' % (mapchild(k)))

            k += 1
示例#15
0
 def getRandomImage(self, bb):
     # Create an Image and fill it with Gaussian noise.
     rim = afwImage.ImageF(bb.getWidth(), bb.getHeight())
     rim.setXY0(bb.getMinX(), bb.getMinY())
     afwMath.randomGaussianImage(rim, self.rand)
     return rim
示例#16
0
    def get_position_angle(self, imageName, afwCamera, afwDetector,
                           obs_metadata, epoch):
        """
        Read in a FITS image containing one extended object.

        Determine its north and east axes by examining how RA and Dec change
        with pixel position.

        Determine the semi-major axis of the object by treating the distribution
        of flux as a covariance matrix and finding its eigen vectors.

        Return the angle between the semi-major axis and the north axis of
        the image

        @param [in] imageName is the name of the FITS image to be read

        @param [in] afwCamera is an afw.cameraGeom.Camera

        @param [in] afwDetector is an afw.cameraGeom.Detector

        @param [in] obs_metadata is an ObservationMetaData describing the
        pointing of the telescope

        @param [in] epoch is the epoch in Julian years of the equinox against
        which RA and Dec are measured

        @param [out] the position angle of the object in the image in degrees
        """

        im = afwImage.ImageF(imageName).getArray()
        activePixels = np.where(im > 1.0e-10)
        self.assertGreater(len(activePixels), 0)
        xPixList = activePixels[1]
        yPixList = activePixels[0]

        xCenterPix = np.array([im.shape[1] / 2])
        yCenterPix = np.array([im.shape[0] / 2])

        raCenter, decCenter = _raDecFromPixelCoords(xCenterPix,
                                                    yCenterPix,
                                                    [afwDetector.getName()],
                                                    camera=afwCamera,
                                                    obs_metadata=obs_metadata,
                                                    epoch=epoch)

        xCenterP1 = xCenterPix + 1
        yCenterP1 = yCenterPix + 1
        raCenterP1, decCenterP1 = _raDecFromPixelCoords(
            xCenterP1,
            yCenterP1, [afwDetector.getName()],
            camera=afwCamera,
            obs_metadata=obs_metadata,
            epoch=epoch)

        # find the angle between the (1,1) vector in pixel space and the
        # north axis of the image
        theta = np.arctan2((raCenterP1[0] - raCenter[0]),
                           decCenterP1[0] - decCenter[0])

        # rotate the (1,1) vector in pixel space so that it is pointing
        # along the north axis
        north = np.array(
            [np.cos(theta) - np.sin(theta),
             np.cos(theta) + np.sin(theta)])
        north = north / np.sqrt(north[0] * north[0] + north[1] * north[1])

        # find the east axis of the image
        east = np.array([north[1], -1.0 * north[0]])

        # now find the covariance matrix of the x, y  pixel space distribution
        # of flux on the image
        maxPixel = np.array(
            [im.argmax() % im.shape[1],
             im.argmax() / im.shape[1]])

        xx = np.array([
            im[iy][ix] * np.power(ix - maxPixel[0], 2)
            for ix, iy in zip(xPixList, yPixList)
        ]).sum()

        xy = np.array([
            im[iy][ix] * (ix - maxPixel[0]) * (iy - maxPixel[1])
            for ix, iy in zip(xPixList, yPixList)
        ]).sum()

        yy = np.array([
            im[iy][ix] * (iy - maxPixel[1]) * (iy - maxPixel[1])
            for ix, iy in zip(xPixList, yPixList)
        ]).sum()

        covar = np.array([[xx, xy], [xy, yy]])

        # find the eigen vectors of this covarinace matrix;
        # treat the one with the largest eigen value as the
        # semi-major axis of the object
        eigenVals, eigenVecs = np.linalg.eig(covar)

        iMax = eigenVals.argmax()
        majorAxis = eigenVecs[:, iMax]

        majorAxis = majorAxis / np.sqrt(majorAxis[0] * majorAxis[0] +
                                        majorAxis[1] * majorAxis[1])

        # return the angle between the north axis of the image
        # and the semi-major axis of the object
        cosTheta = np.dot(majorAxis, north)
        sinTheta = np.dot(majorAxis, east)

        theta = np.arctan2(sinTheta, cosTheta)

        return np.degrees(theta)
示例#17
0
    def testMergeHeavyFootprints(self):
        mi = afwImage.MaskedImageF(20, 10)
        objectPixelVal = (42, 0x9, 400)
        
        foot = afwDetect.Footprint()
        for y, x0, x1 in [(1, 9, 12),
                          (2, 12, 13),
                          (3, 11, 15)]:
            foot.addSpan(y, x0, x1)
            for x in range(x0, x1 + 1):
                mi.set(x, y, objectPixelVal)

        hfoot1 = afwDetect.makeHeavyFootprint(self.foot, self.mi)
        hfoot2 = afwDetect.makeHeavyFootprint(foot, mi)

        hfoot1.normalize()
        hfoot2.normalize()
        hsum = afwDetect.mergeHeavyFootprintsF(hfoot1, hfoot2)
        
        bb = hsum.getBBox()
        self.assertEquals(bb.getMinX(), 9)
        self.assertEquals(bb.getMaxX(), 15)
        self.assertEquals(bb.getMinY(), 1)
        self.assertEquals(bb.getMaxY(), 3)

        msum = afwImage.MaskedImageF(20,10)
        hsum.insert(msum)

        sa = msum.getImage().getArray()

        self.assertTrue(np.all(sa[1, 9:13] == objectPixelVal[0]))
        self.assertTrue(np.all(sa[2, 12:14] == objectPixelVal[0] + self.objectPixelVal[0]))
        self.assertTrue(np.all(sa[2, 10:12] == self.objectPixelVal[0]))

        sv = msum.getVariance().getArray()

        self.assertTrue(np.all(sv[1, 9:13] == objectPixelVal[2]))
        self.assertTrue(np.all(sv[2, 12:14] == objectPixelVal[2] + self.objectPixelVal[2]))
        self.assertTrue(np.all(sv[2, 10:12] == self.objectPixelVal[2]))

        sm = msum.getMask().getArray()

        self.assertTrue(np.all(sm[1, 9:13] == objectPixelVal[1]))
        self.assertTrue(np.all(sm[2, 12:14] == objectPixelVal[1] | self.objectPixelVal[1]))
        self.assertTrue(np.all(sm[2, 10:12] == self.objectPixelVal[1]))


        if False:
            import matplotlib
            matplotlib.use('Agg')
            import pylab as plt
            im1 = afwImage.ImageF(bb)
            hfoot1.insert(im1)
            im2 = afwImage.ImageF(bb)
            hfoot2.insert(im2)
            im3 = afwImage.ImageF(bb)
            hsum.insert(im3)
            plt.clf()
            plt.subplot(1,3,1)
            plt.imshow(im1.getArray(), interpolation='nearest', origin='lower')
            plt.subplot(1,3,2)
            plt.imshow(im2.getArray(), interpolation='nearest', origin='lower')
            plt.subplot(1,3,3)
            plt.imshow(im3.getArray(), interpolation='nearest', origin='lower')
            plt.savefig('merge.png')
    def getClumps(self, sigma=1.0, display=False):
        if self._num <= 0:
            raise RuntimeError("No candidate PSF sources")

        psfImage = self.getImage()
        #
        # Embed psfImage into a larger image so we can smooth when measuring it
        #
        width, height = psfImage.getWidth(), psfImage.getHeight()
        largeImg = psfImage.Factory(afwGeom.ExtentI(2 * width, 2 * height))
        largeImg.set(0)

        bbox = afwGeom.BoxI(afwGeom.PointI(width, height),
                            afwGeom.ExtentI(width, height))
        largeImg.assign(psfImage, bbox, afwImage.LOCAL)
        #
        # Now measure that image, looking for the highest peak.  Start by building an Exposure
        #
        msk = afwImage.MaskU(largeImg.getDimensions())
        msk.set(0)
        var = afwImage.ImageF(largeImg.getDimensions())
        var.set(1)
        mpsfImage = afwImage.MaskedImageF(largeImg, msk, var)
        mpsfImage.setXY0(afwGeom.PointI(-width, -height))
        del msk
        del var
        exposure = afwImage.makeExposure(mpsfImage)

        #
        # Next run an object detector
        #
        maxVal = afwMath.makeStatistics(psfImage, afwMath.MAX).getValue()
        threshold = maxVal - sigma * math.sqrt(maxVal)
        if threshold <= 0.0:
            threshold = maxVal

        threshold = afwDetection.Threshold(threshold)

        ds = afwDetection.FootprintSet(mpsfImage, threshold, "DETECTED")
        #
        # And measure it.  This policy isn't the one we use to measure
        # Sources, it's only used to characterize this PSF histogram
        #
        schema = SourceTable.makeMinimalSchema()
        psfImageConfig = SingleFrameMeasurementConfig()
        psfImageConfig.slots.centroid = "base_SdssCentroid"
        psfImageConfig.plugins["base_SdssCentroid"].doFootprintCheck = False
        psfImageConfig.slots.psfFlux = None  # "base_PsfFlux"
        psfImageConfig.slots.apFlux = "base_CircularApertureFlux_3_0"
        psfImageConfig.slots.modelFlux = None
        psfImageConfig.slots.instFlux = None
        psfImageConfig.slots.calibFlux = None
        psfImageConfig.slots.shape = "base_SdssShape"
        #   Formerly, this code had centroid.sdss, flux.psf, flux.naive,
        #   flags.pixel, and shape.sdss
        psfImageConfig.algorithms.names = [
            "base_SdssCentroid", "base_CircularApertureFlux", "base_SdssShape"
        ]
        psfImageConfig.algorithms["base_CircularApertureFlux"].radii = [3.0]
        psfImageConfig.validate()
        task = SingleFrameMeasurementTask(schema, config=psfImageConfig)

        sourceCat = SourceCatalog(schema)

        gaussianWidth = 1.5  # Gaussian sigma for detection convolution
        exposure.setPsf(algorithmsLib.DoubleGaussianPsf(11, 11, gaussianWidth))

        ds.makeSources(sourceCat)
        #
        # Show us the Histogram
        #
        if display:
            frame = 1
            dispImage = mpsfImage.Factory(
                mpsfImage,
                afwGeom.BoxI(afwGeom.PointI(width, height),
                             afwGeom.ExtentI(width, height)), afwImage.LOCAL)
            ds9.mtv(dispImage, title="PSF Selection Image", frame=frame)

        clumps = list()  # List of clumps, to return
        e = None  # thrown exception
        IzzMin = 1.0  # Minimum value for second moments
        IzzMax = (
            self._xSize /
            8.0)**2  # Max value ... clump radius should be < clumpImgSize/8
        apFluxes = []
        task.run(
            sourceCat,
            exposure)  # notes that this is backwards for the new framework
        for i, source in enumerate(sourceCat):
            if source.getCentroidFlag():
                continue
            x, y = source.getX(), source.getY()

            apFluxes.append(source.getApFlux())

            val = mpsfImage.getImage().get(int(x) + width, int(y) + height)

            psfClumpIxx = source.getIxx()
            psfClumpIxy = source.getIxy()
            psfClumpIyy = source.getIyy()

            if display:
                if i == 0:
                    ds9.pan(x, y, frame=frame)

                ds9.dot("+", x, y, ctype=ds9.YELLOW, frame=frame)
                ds9.dot("@:%g,%g,%g" % (psfClumpIxx, psfClumpIxy, psfClumpIyy),
                        x,
                        y,
                        ctype=ds9.YELLOW,
                        frame=frame)

            if psfClumpIxx < IzzMin or psfClumpIyy < IzzMin:
                psfClumpIxx = max(psfClumpIxx, IzzMin)
                psfClumpIyy = max(psfClumpIyy, IzzMin)
                if display:
                    ds9.dot("@:%g,%g,%g" %
                            (psfClumpIxx, psfClumpIxy, psfClumpIyy),
                            x,
                            y,
                            ctype=ds9.RED,
                            frame=frame)

            det = psfClumpIxx * psfClumpIyy - psfClumpIxy * psfClumpIxy
            try:
                a, b, c = psfClumpIyy / det, -psfClumpIxy / det, psfClumpIxx / det
            except ZeroDivisionError:
                a, b, c = 1e4, 0, 1e4

            clumps.append(
                Clump(peak=val,
                      x=x,
                      y=y,
                      a=a,
                      b=b,
                      c=c,
                      ixx=psfClumpIxx,
                      ixy=psfClumpIxy,
                      iyy=psfClumpIyy))

        if len(clumps) == 0:
            msg = "Failed to determine center of PSF clump"
            if e:
                msg += ": %s" % e
            raise RuntimeError(msg)

        # if it's all we got return it
        if len(clumps) == 1:
            return clumps

        # which clump is the best?
        # if we've undistorted the moments, stars should only have 1 clump
        # use the apFlux from the clump measurement, and take the highest
        # ... this clump has more psf star candidate neighbours than the others.

        # get rid of any that are huge, and thus poorly defined
        goodClumps = []
        for clump in clumps:
            if clump.ixx < IzzMax and clump.iyy < IzzMax:
                goodClumps.append(clump)

        # if culling > IzzMax cost us all clumps, we'll have to take what we have
        if len(goodClumps) == 0:
            goodClumps = clumps

        # use the 'brightest' clump
        iBestClump = numpy.argsort(apFluxes)[0]
        clumps = [clumps[iBestClump]]
        return clumps
示例#19
0
    def mkFakeGalsimGalaxies(self, fakeCat, band, photoCalib, pixelScale, psf,
                             image):
        """Make images of fake galaxies using GalSim.

        Parameters
        ----------
        band : `str`
        pixelScale : `float`
        psf : `lsst.meas.extensions.psfex.psfexPsf.PsfexPsf`
                    The PSF information to use to make the PSF images
        fakeCat : `pandas.core.frame.DataFrame`
                    The catalog of fake sources to be input
        photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
                    Photometric calibration to be used to calibrate the fake sources

        Yields
        -------
        galImages : `generator`
                    A generator of tuples of `lsst.afw.image.exposure.exposure.ExposureF` and
                    `lsst.geom.Point2D` of their locations.

        Notes
        -----

        Fake galaxies are made by combining two sersic profiles, one for the bulge and one for the disk. Each
        component has an individual sersic index (n), a, b and position angle (PA). The combined profile is
        then convolved with the PSF at the specified x, y position on the image.

        The names of the columns in the ``fakeCat`` are configurable and are the column names from the
        University of Washington simulations database as default. For more information see the doc strings
        attached to the config options.

        See mkFakeStars doc string for an explanation of calibration to instrumental flux.
        """

        self.log.info("Making %d fake galaxy images" % len(fakeCat))

        for (index, row) in fakeCat.iterrows():
            xy = geom.Point2D(row["x"], row["y"])

            # We put these two PSF calculations within this same try block so that we catch cases
            # where the object's position is outside of the image.
            try:
                correctedFlux = psf.computeApertureFlux(
                    self.config.calibFluxRadius, xy)
                psfKernel = psf.computeKernelImage(xy).getArray()
                psfKernel /= correctedFlux

            except InvalidParameterError:
                self.log.info("Galaxy at %0.4f, %0.4f outside of image" %
                              (row["x"], row["y"]))
                continue

            try:
                flux = photoCalib.magnitudeToInstFlux(
                    row[self.config.magVar % band], xy)
            except LogicError:
                flux = 0

            bulge = galsim.Sersic(row[self.config.nBulge],
                                  half_light_radius=row[self.config.bulgeHLR])
            axisRatioBulge = row[self.config.bBulge] / row[self.config.aBulge]
            bulge = bulge.shear(q=axisRatioBulge,
                                beta=((90 - row[self.config.paBulge]) *
                                      galsim.degrees))

            disk = galsim.Sersic(row[self.config.nDisk],
                                 half_light_radius=row[self.config.diskHLR])
            axisRatioDisk = row[self.config.bDisk] / row[self.config.aDisk]
            disk = disk.shear(q=axisRatioDisk,
                              beta=((90 - row[self.config.paDisk]) *
                                    galsim.degrees))

            gal = disk + bulge
            gal = gal.withFlux(flux)

            psfIm = galsim.InterpolatedImage(galsim.Image(psfKernel),
                                             scale=pixelScale)
            gal = galsim.Convolve([gal, psfIm])
            try:
                galIm = gal.drawImage(scale=pixelScale,
                                      method="real_space").array
            except (galsim.errors.GalSimFFTSizeError, MemoryError):
                continue

            yield (afwImage.ImageF(galIm), xy)
示例#20
0
    def testClipToNonzero(self):
        # create a circular footprint
        ellipse = afwGeomEllipses.Ellipse(afwGeomEllipses.Axes(6, 6, 0),
                                          afwGeom.Point2D(9, 15))
        bb = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(20, 30))
        foot = afwDetect.Footprint(ellipse, bb)

        a0 = foot.getArea()

        plots = False
        if plots:
            import matplotlib
            matplotlib.use('Agg')
            import pylab as plt

            plt.clf()
            img = afwImage.ImageU(bb)
            foot.insertIntoImage(img, 1)
            ima = dict(interpolation='nearest', origin='lower', cmap='gray')
            plt.imshow(img.getArray(), **ima)
            plt.savefig('clipnz1.png')

        source = afwImage.ImageF(bb)
        source.getArray()[:, :] = 1.
        source.getArray()[:, 0:10] = 0.

        foot.clipToNonzero(source)
        foot.normalize()
        a1 = foot.getArea()
        self.assertLess(a1, a0)

        img = afwImage.ImageU(bb)
        foot.insertIntoImage(img, 1)
        self.assertTrue(np.all(img.getArray()[source.getArray() == 0] == 0))

        if plots:
            plt.clf()
            plt.subplot(1, 2, 1)
            plt.imshow(source.getArray(), **ima)
            plt.subplot(1, 2, 2)
            plt.imshow(img.getArray(), **ima)
            plt.savefig('clipnz2.png')

        source.getArray()[:12, :] = 0.
        foot.clipToNonzero(source)
        foot.normalize()

        a2 = foot.getArea()
        self.assertLess(a2, a1)

        img = afwImage.ImageU(bb)
        foot.insertIntoImage(img, 1)
        self.assertTrue(np.all(img.getArray()[source.getArray() == 0] == 0))

        if plots:
            plt.clf()
            plt.subplot(1, 2, 1)
            plt.imshow(source.getArray(), **ima)
            plt.subplot(1, 2, 2)
            img = afwImage.ImageU(bb)
            foot.insertIntoImage(img, 1)
            plt.imshow(img.getArray(), **ima)
            plt.savefig('clipnz3.png')
示例#21
0
    def getExposure(self):
        """Construct a test exposure.

        The test exposure has a simple WCS set, as well as a list of
        unlikely header keywords that can be removed during ISR
        processing to exercise that code.

        Returns
        -------
        exposure : `lsst.afw.exposure.Exposure`
            Construct exposure containing masked image of the
            appropriate size.
        """
        camera = self.getCamera()
        detector = camera[self.config.detectorIndex]
        image = afwUtils.makeImageFromCcd(detector,
                                          isTrimmed=self.config.isTrimmed,
                                          showAmpGain=False,
                                          rcMarkSize=0,
                                          binSize=1,
                                          imageFactory=afwImage.ImageF)

        var = afwImage.ImageF(image.getDimensions())
        mask = afwImage.Mask(image.getDimensions())
        image.assign(0.0)

        maskedImage = afwImage.makeMaskedImage(image, mask, var)
        exposure = afwImage.makeExposure(maskedImage)
        exposure.setDetector(detector)
        exposure.setWcs(self.getWcs())

        visitInfo = afwImage.VisitInfo(exposureTime=self.config.expTime,
                                       darkTime=self.config.darkTime)
        exposure.getInfo().setVisitInfo(visitInfo)

        metadata = exposure.getMetadata()
        metadata.add("SHEEP", 7.3, "number of sheep on farm")
        metadata.add("MONKEYS", 155, "monkeys per tree")
        metadata.add("VAMPIRES", 4, "How scary are vampires.")

        ccd = exposure.getDetector()
        newCcd = ccd.rebuild()
        newCcd.clear()
        for amp in ccd:
            newAmp = amp.rebuild()
            newAmp.setLinearityCoeffs((0., 1., 0., 0.))
            newAmp.setLinearityType("Polynomial")
            newAmp.setGain(self.config.gain)
            newAmp.setSuspectLevel(25000.0)
            newAmp.setSaturation(32000.0)
            newCcd.append(newAmp)
        exposure.setDetector(newCcd.finish())

        exposure.image.array[:] = np.zeros(
            exposure.getImage().getDimensions()).transpose()
        exposure.mask.array[:] = np.zeros(
            exposure.getMask().getDimensions()).transpose()
        exposure.variance.array[:] = np.zeros(
            exposure.getVariance().getDimensions()).transpose()

        return exposure
示例#22
0
    def testGrow(self):
        """Test growing a footprint"""
        x0, y0 = 20, 20
        width, height = 20, 30
        foot1 = afwDetect.Footprint(
            afwGeom.Box2I(afwGeom.Point2I(x0, y0),
                          afwGeom.Extent2I(width, height)),
            afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(100, 100)))

        # Add some peaks and check that they get copied into the new grown footprint
        foot1.addPeak(20, 20, 1)
        foot1.addPeak(30, 35, 2)
        foot1.addPeak(25, 45, 3)
        self.assertEqual(len(foot1.getPeaks()), 3)

        bbox1 = foot1.getBBox()

        self.assertEqual(bbox1.getMinX(), x0)
        self.assertEqual(bbox1.getMaxX(), x0 + width - 1)
        self.assertEqual(bbox1.getWidth(), width)

        self.assertEqual(bbox1.getMinY(), y0)
        self.assertEqual(bbox1.getMaxY(), y0 + height - 1)
        self.assertEqual(bbox1.getHeight(), height)

        ngrow = 5
        for isotropic in (True, False):
            foot2 = afwDetect.growFootprint(foot1, ngrow, isotropic)

            # Check that the grown footprint is normalized
            self.assertTrue(foot2.isNormalized())

            # Check that the grown footprint is bigger than the original
            self.assertGreater(foot2.getArea(), foot1.getArea())

            # Check that peaks got copied into grown footprint
            self.assertEqual(len(foot2.getPeaks()), 3)
            for peak in foot2.getPeaks():
                self.assertIn((peak.getIx(), peak.getIy()),
                              [(20, 20), (30, 35), (25, 45)])

            bbox2 = foot2.getBBox()

            if False and display:
                idImage = afwImage.ImageU(width, height)
                idImage.set(0)

                i = 1
                for foot in [foot1, foot2]:
                    foot.insertIntoImage(idImage, i)
                    i += 1

                metricImage = afwImage.ImageF("foo.fits")
                ds9.mtv(metricImage, frame=1)
                ds9.mtv(idImage)

            # check bbox2
            self.assertEqual(bbox2.getMinX(), x0 - ngrow)
            self.assertEqual(bbox2.getWidth(), width + 2 * ngrow)

            self.assertEqual(bbox2.getMinY(), y0 - ngrow)
            self.assertEqual(bbox2.getHeight(), height + 2 * ngrow)
            # Check that region was preserved
            self.assertEqual(foot1.getRegion(), foot2.getRegion())
示例#23
0
def plantSources(x0, y0, nx, ny, sky, nObj, wid, detector, useRandom=False):

    tanSys = detector.makeCameraSys(cameraGeom.TAN_PIXELS)
    pixToTanXYTransform = detector.getTransformMap()[tanSys]

    img0 = afwImage.ImageF(afwGeom.ExtentI(nx, ny))
    img = afwImage.ImageF(afwGeom.ExtentI(nx, ny))

    ixx0, iyy0, ixy0 = wid*wid, wid*wid, 0.0

    edgeBuffer = 40.0*wid

    flux = 1.0e4
    nkx, nky = int(10*wid) + 1, int(10*wid) + 1
    xhwid,yhwid = nkx/2, nky/2

    nRow = int(math.sqrt(nObj))
    xstep = (nx - 1 - 0.0*edgeBuffer)/(nRow+1)
    ystep = (ny - 1 - 0.0*edgeBuffer)/(nRow+1)

    if useRandom:
        nObj = nRow*nRow

    goodAdded0 = []
    goodAdded = []

    for i in range(nObj):

        # get our position
        if useRandom:
            xcen0, ycen0 = numpy.random.uniform(nx), numpy.random.uniform(ny)
        else:
            xcen0, ycen0 = xstep*((i%nRow) + 1), ystep*(int(i/nRow) + 1)
        ixcen0, iycen0 = int(xcen0), int(ycen0)

        # distort position and shape
        pTan = afwGeom.Point2D(xcen0, ycen0)
        linTransform = pixToTanXYTransform.linearizeReverseTransform(pTan).getLinear()
        m = geomEllip.Quadrupole(ixx0, iyy0, ixy0)
        m.transform(linTransform)

        p = pixToTanXYTransform.reverseTransform(pTan)
        xcen, ycen = xcen0, ycen0 #p.getX(), p.getY()
        if (xcen < 1.0*edgeBuffer or (nx - xcen) < 1.0*edgeBuffer or
            ycen < 1.0*edgeBuffer or (ny - ycen) < 1.0*edgeBuffer):
            continue
        ixcen, iycen = int(xcen), int(ycen)
        ixx, iyy, ixy = m.getIxx(), m.getIyy(), m.getIxy()

        # plant the object
        tmp = 0.25*(ixx-iyy)**2 + ixy**2
        a2 = 0.5*(ixx+iyy) + numpy.sqrt(tmp)
        b2 = 0.5*(ixx+iyy) - numpy.sqrt(tmp)
        #ellip = 1.0 - numpy.sqrt(b2/a2)
        theta = 0.5*numpy.arctan2(2.0*ixy, ixx-iyy)
        a = numpy.sqrt(a2)
        b = numpy.sqrt(b2)

        c, s = math.cos(theta), math.sin(theta)
        good0, good = True, True
        for y in range(nky):
            iy = iycen + y - yhwid
            iy0 = iycen0 + y - yhwid

            for x in range(nkx):
                ix = ixcen + x - xhwid
                ix0 = ixcen0 + x - xhwid

                if ix >= 0 and ix < nx and iy >= 0 and iy < ny:
                    dx, dy = ix - xcen, iy - ycen
                    u =  c*dx + s*dy
                    v = -s*dx + c*dy
                    I0 = flux/(2*math.pi*a*b)
                    val = I0*math.exp(-0.5*((u/a)**2 + (v/b)**2))
                    if val < 0:
                        val = 0
                    prevVal = img.get(ix, iy)
                    img.set(ix, iy, val+prevVal)
                else:
                    good = False

                if ix0 >=0 and ix0 < nx and iy0 >= 0 and iy0 < ny:
                    dx, dy = ix - xcen, iy - ycen
                    I0 = flux/(2*math.pi*wid*wid)
                    val = I0*math.exp(-0.5*((dx/wid)**2 + (dy/wid)**2))
                    if val < 0:
                        val = 0
                    prevVal = img0.get(ix0, iy0)
                    img0.set(ix0, iy0, val+prevVal)
                else:
                    good0 = False

        if good0:
            goodAdded0.append([xcen,ycen])
        if good:
            goodAdded.append([xcen,ycen])

    # add sky and noise
    img += sky
    img0 += sky
    noise = afwImage.ImageF(afwGeom.ExtentI(nx, ny))
    noise0 = afwImage.ImageF(afwGeom.ExtentI(nx, ny))
    for i in range(nx):
        for j in range(ny):
            noise.set(i, j, numpy.random.poisson(img.get(i,j) ))
            noise0.set(i, j, numpy.random.poisson(img0.get(i,j) ))


    edgeWidth = int(0.5*edgeBuffer)
    mask = afwImage.MaskU(afwGeom.ExtentI(nx, ny))
    left   = afwGeom.Box2I(afwGeom.Point2I(0,0), afwGeom.ExtentI(edgeWidth, ny))
    right  = afwGeom.Box2I(afwGeom.Point2I(nx - edgeWidth,0), afwGeom.ExtentI(edgeWidth, ny))
    top    = afwGeom.Box2I(afwGeom.Point2I(0,ny - edgeWidth), afwGeom.ExtentI(nx, edgeWidth))
    bottom = afwGeom.Box2I(afwGeom.Point2I(0,0), afwGeom.ExtentI(nx, edgeWidth))

    for pos in [left, right, top, bottom]:
        msk = afwImage.MaskU(mask, pos, False)
        msk.set(msk.getPlaneBitMask('EDGE'))

    expos = afwImage.makeExposure(afwImage.makeMaskedImage(noise, mask, afwImage.ImageF(noise, True)))
    expos0 = afwImage.makeExposure(afwImage.makeMaskedImage(noise0, mask, afwImage.ImageF(noise0, True)))

    im = expos.getMaskedImage().getImage()
    im0 = expos0.getMaskedImage().getImage()
    im -= sky
    im0 -= sky


    return expos, goodAdded, expos0, goodAdded0
示例#24
0
def makeLsstFile(imfile, expfile, lsstfile, interpolateNans=False, debug=True):
    import lsst.afw.image as afwImage
    from astropy.io import fits
    import numpy as np
    from lsst.ip.isr.isrFunctions import saturationCorrection

    if debug:
        print("Generating:\n%s\n  from\n%s\n%s" % (lsstfile, imfile, expfile))

    gain = 3.4  # WIYN WHIRC Data Reduction Guide

    imdir, imbasename = os.path.dirname(imfile), os.path.basename(imfile)
    tmp_imfile = os.path.join(imdir, "tmp_" + imbasename)
    os.system("cp {} {}".format(imfile, tmp_imfile))
    #    os.system("sethead EXPID=0 {}".format(tmp_imfile))
    with fits.open(tmp_imfile, mode='update') as hdu:
        # Some DTTITLE keywords were written with trailing quotes:
        # 'Type Ia Supernovae in the Near-Infrared: A Three-Year Survey toward''
        # AST chokes on these presumably invalid entries.
        dttitle = hdu[0].header['DTTITLE']
        hdu[0].header['DTTITLE'] = dttitle.rstrip("'")

        hdu[0].header['EXPID'] = 0
        hdu.flush()
    #Exposures should keep your header keys
    exp = afwImage.ExposureF(tmp_imfile)
    im = exp.getMaskedImage().getImage()
    imArr = im.getArray()
    var = exp.getMaskedImage().getVariance()
    varArr = var.getArray()
    mask = exp.getMaskedImage().getMask()
    maskArr = mask.getArray()

    os.system("rm {}".format(tmp_imfile))
    # Calculate the variance based on the background level / second
    # stored in the coadd, which is the background level of
    # the first individual images included in the coadd
    # The coadd was created as an average
    #   so is noramlized to the count level of one input image.
    expTimeArr = afwImage.ImageF(expfile).getArray()
    exphead = fits.getheader(expfile)
    exptime_per_image = exphead[
        "EXPTIME"]  # EXPTIME is not in the afwImage info (why not?) so we fall back on astropy.io.fits
    background_per_image = exphead["BGLEVEL"]
    # print "BGLEVEL: ", background_per_image
    # print "EXPTIME: ", exptime

    background_per_second = background_per_image / exptime_per_image

    fullexptime = np.percentile(expTimeArr, 99)
    if debug:
        print("(Background counts/sec, fullexptime, exptime_per_image)")
        print(background_per_second, fullexptime, exptime_per_image)
    idx = range(int(0.2 * len(maskArr[0, :])), int(0.8 * len(maskArr[0, :])))

    photonArr = gain * \
      (imArr+background_per_image) * (expTimeArr/exptime_per_image)
    ## Variance in ADU for the accumulated counts
    ##  (i.e., that has not been re-scaled to have the same normalization across the image)
    varArr[:, :] = photonArr / gain**2
    ## Variance in ADU for the normalized image
    varArr /= (expTimeArr / exptime_per_image)**2
    varArr[np.logical_not(np.isfinite(imArr))] = np.inf

    # Reject all of the locations with less than 20% of the effective exposure time
    idxs = np.where(expTimeArr < 0.2 * fullexptime)
    badmask = mask.getPlaneBitMask('BAD')
    maskArr[idxs] |= badmask
    intrpmask = mask.getPlaneBitMask('INTRP')
    maskArr[idxs] |= intrpmask

    if interpolateNans:
        SAT_LEVEL = 100000
        imArr[np.logical_not(np.isfinite(imArr))] = 2 * SAT_LEVEL
        saturationCorrection(exp.getMaskedImage(),
                             saturation=SAT_LEVEL,
                             fwhm=2,
                             growFootprints=False)


#    import lsst.afw.display.ds9 as ds9
#    ds9.mtv(exp, title="Foo")

# If set, then boost the variance of low-exposure regions to 10x higher.
# This is a bit of a hack that I'm unhappy about, but there's no
# way to tell the current (2015-03-19) DM stack software to ignore a region.
    boostBadPixelVariance = False
    if boostBadPixelVariance:
        varArr[idxs] *= 10

    exp.writeFits(lsstfile)
示例#25
0
        fratio = np.mean(imarr1 / imarr2)
        imarr2 *= fratio
        # Calculate the mean value of the flat field images.
        fmean = (np.mean(imarr1) + np.mean(imarr2)) / 2.
        # Calculate the variance of the flat difference image.
        fvar = np.var(imarr1 - imarr2) / 2.
        gains.append(fvar / fmean)
    gain = 1. / np.median(gains)  # gain in Ne/DN
    return gain, im1, im2


if __name__ == '__main__':
    import os
    from .sim_tools import simulateFlat

    file1 = 'test_flat1.fits'
    file2 = 'test_flat2.fits'

    hdus = 2
    simulateFlat(file1, 4000, 5, hdus=hdus)
    simulateFlat(file2, 4000, 5, hdus=hdus)

    for amp in range(1, hdus + 1):
        image1 = afwImage.ImageF(file1, imutils.dm_hdu(amp))
        image2 = afwImage.ImageF(file2, imutils.dm_hdu(amp))
        gain, im1, im2 = flat_gain(image1, image2, count=1000)
        print(amp, gain)

    os.remove(file1)
    os.remove(file2)
示例#26
0
    for x in (0, width // 2, width):
        for y in (0, height // 2, height):
            im = afwImage.ImageD(spatialKernel.getDimensions())
            ksum = spatialKernel.computeImage(im, False,
                                              afwImage.indexToPosition(x),
                                              afwImage.indexToPosition(y))
            mos.append(im, "x=%d y=%d kSum=%.2f" % (x, y, ksum))

    mosaic = mos.makeMosaic()
    frame += 1
    ds9.mtv(mosaic, frame=frame, title="Spatial Kernels")
    mos.drawLabels(frame=frame)

    # Background
    backgroundIm = afwImage.ImageF(
        afwGeom.Extent2I(templateExposure.getWidth(),
                         templateExposure.getHeight()), 0)
    backgroundIm += spatialBg
    frame += 1
    ds9.mtv(backgroundIm, frame=frame, title="Background model")

    # Diffim!
    diffIm = ipDiffim.convolveAndSubtract(templateExposure.getMaskedImage(),
                                          scienceExposure.getMaskedImage(),
                                          spatialKernel, spatialBg)
    frame += 1
    ds9.mtv(diffIm, frame=frame, title="Diffim")

# examples/runSpatialModel.py $AFWDATA_DIR/DC3a-Sim/sci/v5-e0/v5-e0-c011-a00.sci
# ... $AFWDATA_DIR/DC3a-Sim/sci/v26-e0/v26-e0-c011-a00.sci
示例#27
0
 def testMtv(self):
     """Test basic image display"""
     exp = afwImage.ImageF(10, 20)
     ds9.mtv(exp, title="parent")
示例#28
0
    def compareToSwarp(self,
                       kernelName,
                       useWarpExposure=True,
                       useSubregion=False,
                       useDeepCopy=False,
                       interpLength=10,
                       cacheSize=100000,
                       rtol=4e-05,
                       atol=1e-2):
        """Compare warpExposure to swarp for given warping kernel.

        Note that swarp only warps the image plane, so only test that plane.

        Inputs:
        - kernelName: name of kernel in the form used by afwImage.makeKernel
        - useWarpExposure: if True, call warpExposure to warp an ExposureF,
            else call warpImage to warp an ImageF and also call the Transform version
        - useSubregion: if True then the original source exposure (from which the usual
            test exposure was extracted) is read and the correct subregion extracted
        - useDeepCopy: if True then the copy of the subimage is a deep copy,
            else it is a shallow copy; ignored if useSubregion is False
        - interpLength: interpLength argument for lsst.afw.math.WarpingControl
        - cacheSize: cacheSize argument for lsst.afw.math.WarpingControl;
            0 disables the cache
            10000 gives some speed improvement but less accurate results (atol must be increased)
            100000 gives better accuracy but no speed improvement in this test
        - rtol: relative tolerance as used by np.allclose
        - atol: absolute tolerance as used by np.allclose
        """
        warpingControl = afwMath.WarpingControl(
            kernelName,
            "",  # there is no point to a separate mask kernel since we aren't testing the mask plane
            cacheSize,
            interpLength,
        )
        if useSubregion:
            originalFullExposure = afwImage.ExposureF(originalExposurePath)
            # "medsub" is a subregion of med starting at 0-indexed pixel (40, 150) of size 145 x 200
            bbox = lsst.geom.Box2I(lsst.geom.Point2I(40, 150),
                                   lsst.geom.Extent2I(145, 200))
            originalExposure = afwImage.ExposureF(originalFullExposure, bbox,
                                                  afwImage.LOCAL, useDeepCopy)
            swarpedImageName = f"medsubswarp1{kernelName}.fits"
        else:
            originalExposure = afwImage.ExposureF(originalExposurePath)
            swarpedImageName = f"medswarp1{kernelName}.fits"

        swarpedImagePath = os.path.join(dataDir, swarpedImageName)
        swarpedDecoratedImage = afwImage.DecoratedImageF(swarpedImagePath)
        swarpedImage = swarpedDecoratedImage.getImage()
        swarpedMetadata = swarpedDecoratedImage.getMetadata()
        warpedWcs = afwGeom.makeSkyWcs(swarpedMetadata)

        if useWarpExposure:
            # path for saved afw-warped image
            afwWarpedImagePath = f"afwWarpedExposure1{kernelName}.fits"

            afwWarpedMaskedImage = afwImage.MaskedImageF(
                swarpedImage.getDimensions())
            afwWarpedExposure = afwImage.ExposureF(afwWarpedMaskedImage,
                                                   warpedWcs)
            afwMath.warpExposure(afwWarpedExposure, originalExposure,
                                 warpingControl)
            afwWarpedMask = afwWarpedMaskedImage.getMask()
            if SAVE_FITS_FILES:
                afwWarpedExposure.writeFits(afwWarpedImagePath)
            if display:
                afwDisplay.Display(frame=1).mtv(afwWarpedExposure,
                                                title="Warped")

            swarpedMaskedImage = afwImage.MaskedImageF(swarpedImage)

            if display:
                afwDisplay.Display(frame=2).mtv(swarpedMaskedImage,
                                                title="SWarped")

            msg = f"afw and swarp {kernelName}-warped differ (ignoring bad pixels)"
            try:
                self.assertMaskedImagesAlmostEqual(afwWarpedMaskedImage,
                                                   swarpedMaskedImage,
                                                   doImage=True,
                                                   doMask=False,
                                                   doVariance=False,
                                                   skipMask=afwWarpedMask,
                                                   rtol=rtol,
                                                   atol=atol,
                                                   msg=msg)
            except Exception:
                if SAVE_FAILED_FITS_FILES:
                    afwWarpedExposure.writeFits(afwWarpedImagePath)
                    print(
                        f"Saved failed afw-warped exposure as: {afwWarpedImagePath}"
                    )
                raise
        else:
            # path for saved afw-warped image
            afwWarpedImagePath = f"afwWarpedImage1{kernelName}.fits"
            afwWarpedImage2Path = f"afwWarpedImage1{kernelName}_xyTransform.fits"

            afwWarpedImage = afwImage.ImageF(swarpedImage.getDimensions())
            originalImage = originalExposure.getMaskedImage().getImage()
            originalWcs = originalExposure.getWcs()
            afwMath.warpImage(afwWarpedImage, warpedWcs, originalImage,
                              originalWcs, warpingControl)
            if display:
                afwDisplay.Display(frame=1).mtv(afwWarpedImage, title="Warped")
                afwDisplay.Display(frame=2).mtv(swarpedImage, title="SWarped")
                diff = swarpedImage.Factory(swarpedImage, True)
                diff -= afwWarpedImage
                afwDisplay.Display(frame=3).mtv(diff, title="swarp - afw")
            if SAVE_FITS_FILES:
                afwWarpedImage.writeFits(afwWarpedImagePath)

            afwWarpedImageArr = afwWarpedImage.getArray()
            noDataMaskArr = np.isnan(afwWarpedImageArr)
            msg = f"afw and swarp {kernelName}-warped images do not match (ignoring NaN pixels)"
            try:
                self.assertImagesAlmostEqual(afwWarpedImage,
                                             swarpedImage,
                                             skipMask=noDataMaskArr,
                                             rtol=rtol,
                                             atol=atol,
                                             msg=msg)
            except Exception:
                if SAVE_FAILED_FITS_FILES:
                    # save the image anyway
                    afwWarpedImage.writeFits(afwWarpedImagePath)
                    print(
                        f"Saved failed afw-warped image as: {afwWarpedImagePath}"
                    )
                raise

            afwWarpedImage2 = afwImage.ImageF(swarpedImage.getDimensions())
            srcToDest = afwGeom.makeWcsPairTransform(originalWcs, warpedWcs)
            afwMath.warpImage(afwWarpedImage2, originalImage, srcToDest,
                              warpingControl)
            msg = f"afw transform-based and WCS-based {kernelName}-warped images do not match"
            try:
                self.assertImagesAlmostEqual(afwWarpedImage2,
                                             afwWarpedImage,
                                             rtol=rtol,
                                             atol=atol,
                                             msg=msg)
            except Exception:
                if SAVE_FAILED_FITS_FILES:
                    # save the image anyway
                    afwWarpedImage.writeFits(afwWarpedImage2)
                    print(
                        f"Saved failed afw-warped image as: {afwWarpedImage2Path}"
                    )
                raise
示例#29
0
    # We need to fit for a TAN-SIP
    x = np.arange(0, 1489 + stepSize, stepSize)
    y = np.arange(0, 2048 + stepSize, stepSize)
    coords = np.meshgrid(x, y)
    xs = np.ravel(coords[0]).astype(np.float)
    ys = np.ravel(coords[1]).astype(np.float)
    mapper = CoordinateMapper(node_rad, incl_rad, dRow0, dRow1, dRow2, dRow3,
                              dCol0, dCol1, dCol2, dCol3, a, b, c, d, e, f)
    wcs = createWcs(xs, ys, mapper)

    if doValidate:
        validate(xs, ys, mapper, wcs)

    return wcs


if __name__ == '__main__':
    infile = sys.argv[1]
    filt = sys.argv[2]
    camcol = int(sys.argv[3])
    field = int(sys.argv[4])

    wcs = convertasTrans(infile, filt, camcol, field, doValidate=True)

    if len(sys.argv) > 5:
        fpC = sys.argv[5]
        image = afwImage.ImageF(fpC)
        mi = afwImage.MaskedImageF(image)
        exp = afwImage.ExposureF(mi, wcs)
        exp.writeFits("/tmp/exp.fits")
示例#30
0
 def setUp(self):
     self.binsizes = range(1, 10)
     imsize = lcm(*self.binsizes)
     self.input_image = afwImage.ImageF(imsize, imsize)
     self.input_image += 1