예제 #1
0
    def makeSourceCat(self, distortedWcs):
        """Make a source catalog by reading the position reference stars and distorting the positions
        """
        loadRes = self.refObjLoader.loadPixelBox(bbox=self.bbox,
                                                 wcs=distortedWcs,
                                                 filterName="r")
        refCat = loadRes.refCat
        refCentroidKey = afwTable.Point2DKey(refCat.schema["centroid"])
        refFluxRKey = refCat.schema["r_flux"].asKey()

        sourceSchema = afwTable.SourceTable.makeMinimalSchema()
        measBase.SingleFrameMeasurementTask(
            schema=sourceSchema)  # expand the schema
        sourceCat = afwTable.SourceCatalog(sourceSchema)
        sourceCentroidKey = afwTable.Point2DKey(sourceSchema["slot_Centroid"])
        sourceInstFluxKey = sourceSchema["slot_ApFlux_instFlux"].asKey()
        sourceInstFluxErrKey = sourceSchema["slot_ApFlux_instFluxErr"].asKey()

        sourceCat.reserve(len(refCat))
        for refObj in refCat:
            src = sourceCat.addNew()
            src.set(sourceCentroidKey, refObj.get(refCentroidKey))
            src.set(sourceInstFluxKey, refObj.get(refFluxRKey))
            src.set(sourceInstFluxErrKey, refObj.get(refFluxRKey) / 100)
        return sourceCat
예제 #2
0
def doDetection(exp,
                threshold=5.0,
                thresholdType='pixel_stdev',
                thresholdPolarity='positive',
                doSmooth=True,
                doMeasure=True,
                asDF=False):
    # Modeled from meas_algorithms/tests/testMeasure.py
    schema = afwTable.SourceTable.makeMinimalSchema()
    config = measAlg.SourceDetectionTask.ConfigClass()
    config.thresholdPolarity = thresholdPolarity
    config.reEstimateBackground = False
    config.thresholdValue = threshold
    config.thresholdType = thresholdType
    detectionTask = measAlg.SourceDetectionTask(config=config, schema=schema)
    detectionTask.log.setLevel(log_level)

    # Do measurement too, so we can get x- and y-coord centroids

    config = measBase.SingleFrameMeasurementTask.ConfigClass()
    # Use the minimum set of plugins required.
    config.plugins = [
        "base_CircularApertureFlux",
        "base_PixelFlags",
        "base_SkyCoord",
        "base_PsfFlux",
        "base_GaussianCentroid",
        "base_GaussianFlux",
        "base_PeakLikelihoodFlux",
        "base_PeakCentroid",
        "base_SdssCentroid",
        "base_SdssShape",
        "base_NaiveCentroid",
        #"ip_diffim_NaiveDipoleCentroid",
        #"ip_diffim_NaiveDipoleFlux",
        "ip_diffim_PsfDipoleFlux",
        "ip_diffim_ClassificationDipole",
    ]
    config.slots.centroid = "base_GaussianCentroid"  #"ip_diffim_NaiveDipoleCentroid"
    #config.plugins["base_CircularApertureFlux"].radii = [3.0, 7.0, 15.0, 25.0]
    #config.slots.psfFlux = "base_CircularApertureFlux_7_0" # Use of the PSF flux is hardcoded in secondMomentStarSelector
    config.slots.calibFlux = None
    config.slots.modelFlux = None
    config.slots.instFlux = None
    config.slots.shape = "base_SdssShape"
    config.doReplaceWithNoise = False
    measureTask = measBase.SingleFrameMeasurementTask(schema, config=config)
    measureTask.log.setLevel(log_level)

    table = afwTable.SourceTable.make(schema)
    sources = detectionTask.run(table, exp, doSmooth=doSmooth).sources

    measureTask.measure(sources, exposure=exp)

    if asDF:
        sources = catalogToDF(
            sources
        )  #pd.DataFrame({col: sources.columns[col] for col in sources.schema.getNames()})

    return sources
예제 #3
0
    def testUsedFlag(self):
        """Test that the solver will record number of sources used to table
           if it is passed a schema on initialization.
        """
        self.exposure.setWcs(self.tanWcs)
        config = AstrometryTask.ConfigClass()
        config.wcsFitter.order = 2
        config.wcsFitter.numRejIter = 0

        sourceSchema = afwTable.SourceTable.makeMinimalSchema()
        measBase.SingleFrameMeasurementTask(
            schema=sourceSchema)  # expand the schema
        # schema must be passed to the solver task constructor
        solver = AstrometryTask(config=config,
                                refObjLoader=self.refObjLoader,
                                schema=sourceSchema)
        sourceCat = self.makeSourceCat(self.tanWcs, sourceSchema=sourceSchema)

        results = solver.run(
            sourceCat=sourceCat,
            exposure=self.exposure,
        )
        # check that the used flag is set the right number of times
        count = 0
        for source in sourceCat:
            if source.get('calib_astrometry_used'):
                count += 1
        self.assertEqual(count, len(results.matches))
    def testEMPlugin(self):
        msConfig = self.makeConfig()
        msConfig.plugins[self.algName].nGauss = 2
        schema = afwTable.SourceTable.makeMinimalSchema()
        task = measBase.SingleFrameMeasurementTask(schema=schema,
                                                   config=msConfig)
        exposure = afwImage.ExposureF(os.path.join(self.dataDir, "exp.fits"))

        #   this is a double gaussian with a .7/.3 ratio of inner to outer
        #   we expect ixx = iyy = sigma*sigma
        psf = makePsf(67, 4.0, .7, sigma2=10.0, mult2=.3)
        exposure.setPsf(psf)
        source = runMeasure(task, schema, exposure)

        #   Be sure there were no failures
        self.assertEqual(source.get(self.algName + "_flag"), False)
        self.assertEqual(source.get(self.algName + "_flag_rangeError"), False)
        self.assertEqual(source.get(self.algName + "_flag_maxIters"), False)
        self.assertEqual(source.get(self.algName + "_flag_noPsf"), False)

        self.msfKey = lsst.shapelet.MultiShapeletFunctionKey(
            schema[self.algName], lsst.shapelet.HERMITE)

        #   check the two component result to be sure it is close to the input PSF
        #   we don't control the order of EmPsfApprox, so order by size.
        msf = source.get(self.msfKey)
        components = msf.getComponents()
        self.assertEqual(len(components), 2)
        comp0 = components[0]
        comp1 = components[1]
        flux0 = comp0.getCoefficients()[0]
        flux1 = comp1.getCoefficients()[0]
        if flux0 < flux1:
            temp = comp1
            comp1 = comp0
            comp0 = temp
        #  We are not looking for really close matches in this unit test, which is why
        #  the tolerances are set rather large.  Really just a check that we are getting
        #  some kind of reasonable value for the fit.  A more quantitative test may be needed.
        self.assertFloatsAlmostEqual(flux0 / flux1, 7.0 / 3.0, rtol=.05)
        self.assertFloatsAlmostEqual(comp0.getEllipse().getCore().getIxx(),
                                     16.0,
                                     rtol=.05)
        self.assertFloatsAlmostEqual(comp0.getEllipse().getCore().getIyy(),
                                     16.0,
                                     rtol=.05)
        self.assertFloatsAlmostEqual(comp0.getEllipse().getCore().getIxy(),
                                     0.0,
                                     atol=.1)
        self.assertFloatsAlmostEqual(comp1.getEllipse().getCore().getIxx(),
                                     100.0,
                                     rtol=.05)
        self.assertFloatsAlmostEqual(comp1.getEllipse().getCore().getIyy(),
                                     100.0,
                                     rtol=.05)
        self.assertFloatsAlmostEqual(comp1.getEllipse().getCore().getIxy(),
                                     0.0,
                                     atol=.1)
예제 #5
0
 def testSingleFrameMeasurementTransform(self):
     """Test applying a transform task to the results of single frame measurement."""
     schema = afwTable.SourceTable.makeMinimalSchema()
     sfmConfig = measBase.SingleFrameMeasurementConfig(plugins=[PLUGIN_NAME])
     # We don't use slots in this test
     for key in sfmConfig.slots:
         setattr(sfmConfig.slots, key, None)
     sfmTask = measBase.SingleFrameMeasurementTask(schema, config=sfmConfig)
     transformTask = TransformTask(measConfig=sfmConfig,
                                   inputSchema=sfmTask.schema, outputDataset="src")
     self._transformAndCheck(sfmConfig, sfmTask.schema, transformTask)
예제 #6
0
    def testFootprintsMeasure(self):
        """Check that we can measure the objects in a detectionSet"""

        xcentroid = [10.0, 14.0, 9.0]
        ycentroid = [8.0, 11.5061728, 14.0]
        flux = [51.0, 101.0, 20.0]

        ds = afwDetection.FootprintSet(self.mi, afwDetection.Threshold(10), "DETECTED")

        if display:
            ds9.mtv(self.mi, frame=0)
            ds9.mtv(self.mi.getVariance(), frame=1)

        measureSourcesConfig = measBase.SingleFrameMeasurementConfig()
        measureSourcesConfig.algorithms["base_CircularApertureFlux"].radii = [3.0]
        measureSourcesConfig.algorithms.names = ["base_NaiveCentroid", "base_SdssShape", "base_PsfFlux",
                                                 "base_CircularApertureFlux"]
        measureSourcesConfig.slots.centroid = "base_NaiveCentroid"
        measureSourcesConfig.slots.psfFlux = "base_PsfFlux"
        measureSourcesConfig.slots.apFlux = "base_CircularApertureFlux_3_0"
        measureSourcesConfig.slots.modelFlux = None
        measureSourcesConfig.slots.instFlux = None
        measureSourcesConfig.slots.calibFlux = None

        schema = afwTable.SourceTable.makeMinimalSchema()
        task = measBase.SingleFrameMeasurementTask(schema, config=measureSourcesConfig)
        measCat = afwTable.SourceCatalog(schema)
        # now run the SFM task with the test plugin
        sigma = 1e-10
        psf = algorithms.DoubleGaussianPsf(11, 11, sigma)  # i.e. a single pixel
        self.exposure.setPsf(psf)
        task.run(measCat, self.exposure)

        for i, source in enumerate(measCat):

            xc, yc = source.getX() - self.mi.getX0(), source.getY() - self.mi.getY0()
            if display:
                ds9.dot("+", xc, yc)

            self.assertAlmostEqual(source.getX(), xcentroid[i], 6)
            self.assertAlmostEqual(source.getY(), ycentroid[i], 6)
            self.assertEqual(source.getApFlux(), flux[i])
            # 29 pixels in 3pixel circular ap.
            self.assertAlmostEqual(source.getApFluxErr(), math.sqrt(29), 6)
            # We're using a delta-function PSF, so the psfFlux should be the pixel under the centroid,
            # iff the object's centred in the pixel
            if xc == int(xc) and yc == int(yc):
                self.assertAlmostEqual(source.getPsfFlux(),
                                       self.exposure.getMaskedImage().getImage().get(int(xc + 0.5),
                                                                                     int(yc + 0.5)))
                self.assertAlmostEqual(source.getPsfFluxErr(),
                                       self.exposure.getMaskedImage().getVariance().get(int(xc + 0.5),
                                                                                        int(yc + 0.5)))
 def testMissingPsf(self):
     msConfig = self.makeConfig()
     schema = afwTable.SourceTable.makeMinimalSchema()
     task = measBase.SingleFrameMeasurementTask(schema=schema,
                                                config=msConfig)
     exposure = afwImage.ExposureF(os.path.join(self.dataDir, "exp.fits"))
     #   Strip the psf
     exposure.setPsf(None)
     source = runMeasure(task, schema, exposure)
     self.assertEqual(source.get(self.algName + "_flag"), True)
     self.assertEqual(source.get(self.algName + "_flag_rangeError"), False)
     self.assertEqual(source.get(self.algName + "_flag_maxIters"), False)
     self.assertEqual(source.get(self.algName + "_flag_noPsf"), True)
예제 #8
0
    def setUp(self):
        im = afwImage.ImageF(self.monetFile("small.fits"))
        self.mi = afwImage.MaskedImageF(im, afwImage.Mask(im.getDimensions()),
                                        afwImage.ImageF(im.getDimensions()))
        self.ds = afwDetection.FootprintSet(self.mi,
                                            afwDetection.Threshold(100))

        if display:
            ds9.mtv(self.mi.getImage())
            ds9.erase()

        for foot in self.ds.getFootprints():
            bbox = foot.getBBox()
            x0, y0 = bbox.getMinX(), bbox.getMinY()
            x1, y1 = bbox.getMaxX(), bbox.getMaxY()
            xc = (x0 + x1) / 2.0
            yc = (y0 + y1) / 2.0

            if display:
                ds9.dot("+", xc, yc, ctype=ds9.BLUE)

                if False:
                    x0 -= 0.5
                    y0 -= 0.5
                    x1 += 0.5
                    y1 += 0.5

                    ds9.line([(x0, y0), (x1, y0), (x1, y1), (x0, y1),
                              (x0, y0)],
                             ctype=ds9.RED)
        msConfig = measBase.SingleFrameMeasurementConfig()
        msConfig.algorithms.names = ["base_GaussianCentroid"]
        msConfig.plugins["base_GaussianCentroid"].doFootprintCheck = False
        msConfig.slots.centroid = "base_GaussianCentroid"
        msConfig.slots.shape = None
        msConfig.slots.apFlux = None
        msConfig.slots.modelFlux = None
        msConfig.slots.psfFlux = None
        msConfig.slots.instFlux = None
        msConfig.slots.calibFlux = None
        schema = afwTable.SourceTable.makeMinimalSchema()
        self.task = measBase.SingleFrameMeasurementTask(schema,
                                                        config=msConfig)
        self.ssMeasured = afwTable.SourceCatalog(schema)
        self.ssMeasured.table.defineCentroid("base_GaussianCentroid")
        self.ssTruth = afwTable.SourceCatalog(schema)
        self.ssTruth.table.defineCentroid("base_GaussianCentroid")

        self.readTruth(self.monetFile("positions.dat-original"))
 def testUnexpectedError(self):
     msConfig = self.makeConfig()
     msConfig.plugins[self.algName].nGauss = 2
     #   This generates an unexpected exception in Erin's code
     msConfig.plugins[self.algName].nTries = 0
     schema = afwTable.SourceTable.makeMinimalSchema()
     task = measBase.SingleFrameMeasurementTask(schema=schema,
                                                config=msConfig)
     exposure = afwImage.ExposureF(os.path.join(self.dataDir, "exp.fits"))
     psf = makePsf(67, 4.0, .7, 12.0, .3)
     exposure.setPsf(psf)
     source = runMeasure(task, schema, exposure)
     self.assertEqual(source.get(self.algName + "_flag"), True)
     self.assertEqual(source.get(self.algName + "_flag_rangeError"), False)
     self.assertEqual(source.get(self.algName + "_flag_maxIters"), False)
     self.assertEqual(source.get(self.algName + "_flag_noPsf"), False)
예제 #10
0
def measureFree(exposure, center, msConfig):
    """Unforced measurement"""
    schema = afwTable.SourceTable.makeMinimalSchema()
    algMeta = PropertyList()
    task = measBase.SingleFrameMeasurementTask(schema,
                                               config=msConfig,
                                               algMetadata=algMeta)
    measCat = afwTable.SourceCatalog(schema)
    source = measCat.addNew()
    source.getTable().setMetadata(algMeta)
    ss = afwDetection.FootprintSet(exposure.getMaskedImage(),
                                   afwDetection.Threshold(0.1))
    fp = ss.getFootprints()[0]
    source.setFootprint(fp)
    task.run(measCat, exposure)
    return source
 def testMaxIter(self):
     msConfig = self.makeConfig()
     msConfig.plugins[self.algName].nGauss = 2
     msConfig.plugins[self.algName].tolerance = 1e-10
     #   we know the code can't fit this in one iteration
     msConfig.plugins[self.algName].maxIters = 1
     schema = afwTable.SourceTable.makeMinimalSchema()
     task = measBase.SingleFrameMeasurementTask(schema=schema,
                                                config=msConfig)
     exposure = afwImage.ExposureF(os.path.join(self.dataDir, "exp.fits"))
     psf = makePsf(67, 4.0, .7, 12.0, .3)
     exposure.setPsf(psf)
     source = runMeasure(task, schema, exposure)
     self.assertEqual(source.get(self.algName + "_flag"), True)
     self.assertEqual(source.get(self.algName + "_flag_rangeError"), False)
     self.assertEqual(source.get(self.algName + "_flag_maxIters"), True)
     self.assertEqual(source.get(self.algName + "_flag_noPsf"), False)
    def testUsedFlag(self):
        """Test that the solver will record number of sources used to table
           if it is passed a schema on initialization.
        """
        distortedWcs = afwImage.DistortedTanWcs(self.tanWcs,
                                                afwGeom.IdentityXYTransform())
        self.exposure.setWcs(distortedWcs)
        loadRes = self.refObjLoader.loadPixelBox(bbox=self.bbox,
                                                 wcs=distortedWcs,
                                                 filterName="r")
        refCat = loadRes.refCat
        refCentroidKey = afwTable.Point2DKey(refCat.schema["centroid"])
        refFluxRKey = refCat.schema["r_flux"].asKey()

        sourceSchema = afwTable.SourceTable.makeMinimalSchema()
        measBase.SingleFrameMeasurementTask(
            schema=sourceSchema)  # expand the schema
        config = AstrometryTask.ConfigClass()
        config.wcsFitter.order = 2
        config.wcsFitter.numRejIter = 0
        # schema must be passed to the solver task constructor
        solver = AstrometryTask(config=config,
                                refObjLoader=self.refObjLoader,
                                schema=sourceSchema)
        sourceCat = afwTable.SourceCatalog(sourceSchema)
        sourceCentroidKey = afwTable.Point2DKey(sourceSchema["slot_Centroid"])
        sourceFluxKey = sourceSchema["slot_ApFlux_flux"].asKey()
        sourceFluxSigmaKey = sourceSchema["slot_ApFlux_fluxSigma"].asKey()

        for refObj in refCat:
            src = sourceCat.addNew()
            src.set(sourceCentroidKey, refObj.get(refCentroidKey))
            src.set(sourceFluxKey, refObj.get(refFluxRKey))
            src.set(sourceFluxSigmaKey, refObj.get(refFluxRKey) / 100)

        results = solver.run(
            sourceCat=sourceCat,
            exposure=self.exposure,
        )
        # check that the used flag is set the right number of times
        count = 0
        for source in sourceCat:
            if source.get('calib_astrometryUsed'):
                count += 1
        self.assertEqual(count, len(results.matches))
예제 #13
0
    def testPsfFlux(self):
        """Test that fluxes are measured correctly."""
        #
        # Total flux in image
        #
        flux = afwMath.makeStatistics(self.exp.getMaskedImage(),
                                      afwMath.SUM).getValue()
        self.assertAlmostEqual(flux / self.instFlux, 1.0)

        #
        # Various algorithms
        #
        rad = 10.0

        schema = afwTable.SourceTable.makeMinimalSchema()
        schema.addField("centroid_x", type=float)
        schema.addField("centroid_y", type=float)
        schema.addField("centroid_flag", type='Flag')
        sfm_config = measBase.SingleFrameMeasurementConfig()
        sfm_config.doReplaceWithNoise = False
        sfm_config.plugins = ["base_CircularApertureFlux", "base_PsfFlux"]
        sfm_config.slots.centroid = "centroid"
        sfm_config.slots.shape = None
        sfm_config.slots.psfFlux = None
        sfm_config.slots.gaussianFlux = None
        sfm_config.slots.apFlux = None
        sfm_config.slots.modelFlux = None
        sfm_config.slots.calibFlux = None
        sfm_config.plugins["base_SdssShape"].maxShift = 10.0
        sfm_config.plugins["base_CircularApertureFlux"].radii = [rad]
        task = measBase.SingleFrameMeasurementTask(schema, config=sfm_config)
        measCat = afwTable.SourceCatalog(schema)
        source = measCat.addNew()
        source.set("centroid_x", self.xc)
        source.set("centroid_y", self.yc)
        task.run(measCat, self.exp)
        for algName in ["base_CircularApertureFlux_10_0", "base_PsfFlux"]:
            instFlux = source.get(algName + "_instFlux")
            flag = source.get(algName + "_flag")
            self.assertEqual(flag, False)
            self.assertAlmostEqual(
                instFlux / self.instFlux, 1.0, 4,
                "Measuring with %s: %g v. %g" %
                (algName, instFlux, self.instFlux))
예제 #14
0
    def mySetup(self):
        msConfig = measBase.SingleFrameMeasurementConfig()
        msConfig.algorithms.names = ["base_SdssCentroid"]
        msConfig.slots.centroid = "base_SdssCentroid"
        msConfig.slots.shape = None
        msConfig.slots.apFlux = None
        msConfig.slots.modelFlux = None
        msConfig.slots.psfFlux = None
        msConfig.slots.instFlux = None
        msConfig.slots.calibFlux = None
        schema = afwTable.SourceTable.makeMinimalSchema()
        task = measBase.SingleFrameMeasurementTask(schema, config=msConfig)
        measCat = afwTable.SourceCatalog(schema)

        source = measCat.addNew()
        fp = afwDetection.Footprint(self.exp.getBBox(afwImage.LOCAL))
        fp.addPeak(50, 50, 1000.0)
        source.setFootprint(fp)
        # Then run the default SFM task.  Results not checked
        task.run(measCat, self.exp)
        return source
예제 #15
0
    def makeSourceCat(self, wcs, sourceSchema=None, doScatterCentroids=False):
        """Make a source catalog by reading the position reference stars using
        the proviced WCS.

        Optionally provide a schema for the source catalog (to allow
        AstrometryTask in the test methods to update it with the
        "calib_astrometry_used" flag).  Otherwise, a minimal SourceTable
        schema will be created.

        Optionally, via doScatterCentroids, add some scatter to the centroids
        assiged to the source catalog (otherwise they will be identical to
        those of the reference catalog).
        """
        loadRes = self.refObjLoader.loadPixelBox(bbox=self.bbox,
                                                 wcs=wcs,
                                                 filterName="r")
        refCat = loadRes.refCat

        if sourceSchema is None:
            sourceSchema = afwTable.SourceTable.makeMinimalSchema()
            measBase.SingleFrameMeasurementTask(
                schema=sourceSchema)  # expand the schema
        sourceCat = afwTable.SourceCatalog(sourceSchema)

        sourceCat.resize(len(refCat))
        scatterFactor = 1.0
        if doScatterCentroids:
            np.random.seed(12345)
            scatterFactor = np.random.uniform(0.999, 1.001, len(sourceCat))
        sourceCat["slot_Centroid_x"] = scatterFactor * refCat["centroid_x"]
        sourceCat["slot_Centroid_y"] = scatterFactor * refCat["centroid_y"]
        sourceCat["slot_ApFlux_instFlux"] = refCat["r_flux"]
        sourceCat["slot_ApFlux_instFluxErr"] = refCat["r_flux"] / 100

        # Deliberately add some outliers to check that the magnitude
        # outlier rejection code is being run.
        sourceCat["slot_ApFlux_instFlux"][0:4] *= 1000.0

        return sourceCat
    def testRejectBlends(self):
        """Test the PcaPsfDeterminerTask blend removal."""
        """
        We give it a single blended source, asking it to remove blends,
        and check that it barfs in the expected way.
        """

        psfDeterminerClass = measAlg.psfDeterminerRegistry["pca"]
        config = psfDeterminerClass.ConfigClass()
        config.doRejectBlends = True
        psfDeterminer = psfDeterminerClass(config=config)

        schema = afwTable.SourceTable.makeMinimalSchema()
        # Use The single frame measurement task to populate the schema with standard keys
        measBase.SingleFrameMeasurementTask(schema)
        catalog = afwTable.SourceCatalog(schema)
        source = catalog.addNew()

        # Make the source blended, with necessary information to calculate pca
        spanShift = afwGeom.Point2I(54, 123)
        spans = afwGeom.SpanSet.fromShape(6, offset=spanShift)
        foot = afwDetection.Footprint(spans, self.exposure.getBBox())
        foot.addPeak(45, 123, 6)
        foot.addPeak(47, 126, 5)
        source.setFootprint(foot)
        centerKey = afwTable.Point2DKey(source.schema['slot_Centroid'])
        shapeKey = afwTable.QuadrupoleKey(schema['slot_Shape'])
        source.set(centerKey, afwGeom.Point2D(46, 124))
        source.set(shapeKey, afwGeom.Quadrupole(1.1, 2.2, 1))

        candidates = [measAlg.makePsfCandidate(source, self.exposure)]
        metadata = dafBase.PropertyList()

        with self.assertRaises(RuntimeError) as cm:
            psfDeterminer.determinePsf(self.exposure, candidates, metadata)
        self.assertEqual(str(cm.exception),
                         "All PSF candidates removed as blends")
예제 #17
0
def showPsfCandidates(exposure, psfCellSet, psf=None, display=None, normalize=True, showBadCandidates=True,
                      fitBasisComponents=False, variance=None, chi=None):
    """Display the PSF candidates.

    If psf is provided include PSF model and residuals;  if normalize is true normalize the PSFs
    (and residuals)

    If chi is True, generate a plot of residuals/sqrt(variance), i.e. chi

    If fitBasisComponents is true, also find the best linear combination of the PSF's components
    (if they exist)
    """
    if not display:
        display = afwDisplay.Display()

    if chi is None:
        if variance is not None:        # old name for chi
            chi = variance
    #
    # Show us the ccandidates
    #
    mos = displayUtils.Mosaic()
    #
    candidateCenters = []
    candidateCentersBad = []
    candidateIndex = 0

    for cell in psfCellSet.getCellList():
        for cand in cell.begin(False):  # include bad candidates
            rchi2 = cand.getChi2()
            if rchi2 > 1e100:
                rchi2 = numpy.nan

            if not showBadCandidates and cand.isBad():
                continue

            if psf:
                im_resid = displayUtils.Mosaic(gutter=0, background=-5, mode="x")

                try:
                    im = cand.getMaskedImage()  # copy of this object's image
                    xc, yc = cand.getXCenter(), cand.getYCenter()

                    margin = 0 if True else 5
                    w, h = im.getDimensions()
                    bbox = lsst.geom.BoxI(lsst.geom.PointI(margin, margin), im.getDimensions())

                    if margin > 0:
                        bim = im.Factory(w + 2*margin, h + 2*margin)

                        stdev = numpy.sqrt(afwMath.makeStatistics(im.getVariance(), afwMath.MEAN).getValue())
                        afwMath.randomGaussianImage(bim.getImage(), afwMath.Random())
                        bim.getVariance().set(stdev**2)

                        bim.assign(im, bbox)
                        im = bim
                        xc += margin
                        yc += margin

                    im = im.Factory(im, True)
                    im.setXY0(cand.getMaskedImage().getXY0())
                except Exception:
                    continue

                if not variance:
                    im_resid.append(im.Factory(im, True))

                if True:                # tweak up centroids
                    mi = im
                    psfIm = mi.getImage()
                    config = measBase.SingleFrameMeasurementTask.ConfigClass()
                    config.slots.centroid = "base_SdssCentroid"

                    schema = afwTable.SourceTable.makeMinimalSchema()
                    measureSources = measBase.SingleFrameMeasurementTask(schema, config=config)
                    catalog = afwTable.SourceCatalog(schema)

                    extra = 10          # enough margin to run the sdss centroider
                    miBig = mi.Factory(im.getWidth() + 2*extra, im.getHeight() + 2*extra)
                    miBig[extra:-extra, extra:-extra, afwImage.LOCAL] = mi
                    miBig.setXY0(mi.getX0() - extra, mi.getY0() - extra)
                    mi = miBig
                    del miBig

                    exp = afwImage.makeExposure(mi)
                    exp.setPsf(psf)

                    footprintSet = afwDet.FootprintSet(mi,
                                                       afwDet.Threshold(0.5*numpy.max(psfIm.getArray())),
                                                       "DETECTED")
                    footprintSet.makeSources(catalog)

                    if len(catalog) == 0:
                        raise RuntimeError("Failed to detect any objects")

                    measureSources.run(catalog, exp)
                    if len(catalog) == 1:
                        source = catalog[0]
                    else:               # more than one source; find the once closest to (xc, yc)
                        dmin = None  # an invalid value to catch logic errors
                        for i, s in enumerate(catalog):
                            d = numpy.hypot(xc - s.getX(), yc - s.getY())
                            if i == 0 or d < dmin:
                                source, dmin = s, d
                    xc, yc = source.getCentroid()

                # residuals using spatial model
                try:
                    subtractPsf(psf, im, xc, yc)
                except Exception:
                    continue

                resid = im
                if variance:
                    resid = resid.getImage()
                    var = im.getVariance()
                    var = var.Factory(var, True)
                    numpy.sqrt(var.getArray(), var.getArray())  # inplace sqrt
                    resid /= var

                im_resid.append(resid)

                # Fit the PSF components directly to the data (i.e. ignoring the spatial model)
                if fitBasisComponents:
                    im = cand.getMaskedImage()

                    im = im.Factory(im, True)
                    im.setXY0(cand.getMaskedImage().getXY0())

                    try:
                        noSpatialKernel = psf.getKernel()
                    except Exception:
                        noSpatialKernel = None

                    if noSpatialKernel:
                        candCenter = lsst.geom.PointD(cand.getXCenter(), cand.getYCenter())
                        fit = fitKernelParamsToImage(noSpatialKernel, im, candCenter)
                        params = fit[0]
                        kernels = afwMath.KernelList(fit[1])
                        outputKernel = afwMath.LinearCombinationKernel(kernels, params)

                        outImage = afwImage.ImageD(outputKernel.getDimensions())
                        outputKernel.computeImage(outImage, False)

                        im -= outImage.convertF()
                        resid = im

                        if margin > 0:
                            bim = im.Factory(w + 2*margin, h + 2*margin)
                            afwMath.randomGaussianImage(bim.getImage(), afwMath.Random())
                            bim *= stdev

                            bim.assign(resid, bbox)
                            resid = bim

                        if variance:
                            resid = resid.getImage()
                            resid /= var

                        im_resid.append(resid)

                im = im_resid.makeMosaic()
            else:
                im = cand.getMaskedImage()

            if normalize:
                im /= afwMath.makeStatistics(im, afwMath.MAX).getValue()

            objId = splitId(cand.getSource().getId(), True)["objId"]
            if psf:
                lab = "%d chi^2 %.1f" % (objId, rchi2)
                ctype = afwDisplay.RED if cand.isBad() else afwDisplay.GREEN
            else:
                lab = "%d flux %8.3g" % (objId, cand.getSource().getPsfInstFlux())
                ctype = afwDisplay.GREEN

            mos.append(im, lab, ctype)

            if False and numpy.isnan(rchi2):
                display.mtv(cand.getMaskedImage().getImage(), title="showPsfCandidates: candidate")
                print("amp", cand.getAmplitude())

            im = cand.getMaskedImage()
            center = (candidateIndex, xc - im.getX0(), yc - im.getY0())
            candidateIndex += 1
            if cand.isBad():
                candidateCentersBad.append(center)
            else:
                candidateCenters.append(center)

    if variance:
        title = "chi(Psf fit)"
    else:
        title = "Stars & residuals"
    mosaicImage = mos.makeMosaic(display=display, title=title)

    with display.Buffering():
        for centers, color in ((candidateCenters, afwDisplay.GREEN), (candidateCentersBad, afwDisplay.RED)):
            for cen in centers:
                bbox = mos.getBBox(cen[0])
                display.dot("+", cen[1] + bbox.getMinX(), cen[2] + bbox.getMinY(), ctype=color)

    return mosaicImage
예제 #18
0
    def run(self, dataRef, selectDataList=[]):
        """Draw randoms for a given patch
        """

        # first test if the forced-src file exists
        # do not process if the patch doesn't exist
        try:
            dataRef.get(self.config.coaddName + "Coadd_forced_src")
        except:
            self.log.info("No forced_src file found for %s. Skipping..." % (dataRef.dataId))
            return

        # verbose
        self.log.info("Processing %s" % (dataRef.dataId))


        # create a seed that depends on patch id
        # so it is consistent among filters
        if self.config.seed == -1:
            p = [int(d) for d in dataRef.dataId["patch"].split(",") ]
            numpy.random.seed(seed=dataRef.dataId["tract"]*10000+p[0]*10+ p[1])
        else:
            numpy.random.seed(seed=self.config.seed)

        # compute sky mean and sky std_dev for this patch
        # in 2" diameter apertures (~12 pixels x 0.17"/pixel)
        # import source list for getting sky objects
        sources = dataRef.get(self.config.coaddName + "Coadd_meas")
        if True:
            sky_apertures = sources['base_CircularApertureFlux_12_0_flux'][sources['merge_peak_sky']]
            select = numpy.isfinite(sky_apertures)
            sky_mean = numpy.mean(sky_apertures[select])
            sky_std  = numpy.std(sky_apertures[select])
            # NOTE: to get 5-sigma limiting magnitudes:
            # print -2.5*numpy.log10(5.0*sky_std/coadd.getCalib().getFluxMag0()[0])
        else:
            sky_mean = 0.0
            sky_std  = 0.0

        # get coadd, coadd info and coadd psf object
        coadd = dataRef.get(self.config.coaddName + "Coadd_calexp")
        psf = coadd.getPsf()
        var = coadd.getMaskedImage().getVariance().getArray()
        skyInfo = self.getSkyInfo(dataRef)

        # wcs and reference point (wrt tract)
        # See http://hsca.ipmu.jp/hscsphinx_test/scripts/print_coord.html
        # for coordinate routines.
        wcs = coadd.getWcs()
        xy0 = coadd.getXY0()

        # dimension in pixels
        dim = coadd.getDimensions()

        # define measurement algorithms
        # mostly copied from /data1a/ana/hscPipe5/Linux64/meas_base/5.3-hsc/tests/testInputCount.py
        measureSourcesConfig = measBase.SingleFrameMeasurementConfig()
        measureSourcesConfig.plugins.names = ['base_PixelFlags', 'base_PeakCentroid', 'base_InputCount', 'base_SdssShape']
        measureSourcesConfig.slots.centroid = "base_PeakCentroid"
        measureSourcesConfig.slots.psfFlux = None
        measureSourcesConfig.slots.apFlux = None
        measureSourcesConfig.slots.modelFlux = None
        measureSourcesConfig.slots.instFlux = None
        measureSourcesConfig.slots.calibFlux = None
        measureSourcesConfig.slots.shape =  None

        # it seems it is still necessary to manually add the
        # bright-star mask flag by hand
        measureSourcesConfig.plugins['base_PixelFlags'].masksFpCenter.append("BRIGHT_OBJECT")
        measureSourcesConfig.plugins['base_PixelFlags'].masksFpAnywhere.append("BRIGHT_OBJECT")

        measureSourcesConfig.validate()

        # add PSF shape
        # sdssShape_psf = self.schema.addField("shape_sdss_psf", type="MomentsD", doc="PSF xx from SDSS algorithm", units="pixel")
        # shape_sdss_psf = self.schema.addField("shape_sdss_psf", type="MomentsD", doc="PSF yy from SDSS algorithm", units="pixel")
        # shape_sdss_psf = self.schema.addField("shape_sdss_psf", type="MomentsD", doc="PSF xy from SDSS algorithm", units="pixel")

        # additional columns

        # random number to adjust sky density
        adjust_density = self.schema.addField("adjust_density", type=float, doc="Random number between [0:1] to adjust sky density", units='')

        # sky mean and variance for the entire patch
        sky_mean_key = self.schema.addField("sky_mean", type=float, doc="Mean of sky value in 2\" diamter apertures", units='count')
        sky_std_key  = self.schema.addField("sky_std", type=float, doc="Standard deviation of sky value in 2\" diamter apertures", units='count')

        # pixel variance at random point position
        pix_variance = self.schema.addField("pix_variance", type=float, doc="Pixel variance at random point position", units="flx^2")

        # add healpix map value (if healpix map is given)
        if self.depthMap.map is not None:
            depth_key = self.schema.addField("isFullDepthColor", type="Flag", doc="True if full depth and full colors at point position", units='')

        # task and output catalog
        task = measBase.SingleFrameMeasurementTask(self.schema, config=measureSourcesConfig)
        table = afwTable.SourceTable.make(self.schema, self.makeIdFactory(dataRef))
        catalog = afwTable.SourceCatalog(table)

        if self.config.N == -1:
            # to output a constant random
            # number density, first compute
            # the area in degree
            pixel_area = coadd.getWcs().getPixelScale().asDegrees()**2
            area = pixel_area * dim[0] * dim[1]
            N = self.iround(area*self.config.Nden*60.0*60.0)
        else:
            # fixed number if random points
            N = self.config.N

        # verbose
        self.log.info("Drawing %d random points" % (N))

        # loop over N random points
        for i in range(N):
        # for i in range(100):

            # draw one random point
            x = numpy.random.random()*(dim[0]-1)
            y = numpy.random.random()*(dim[1]-1)

            # get coordinates
            radec = wcs.pixelToSky(afwGeom.Point2D(x + xy0.getX(), y + xy0.getY()))
            xy = wcs.skyToPixel(radec)

            # new record in table
            record = catalog.addNew()
            record.setCoord(radec)

            # get PSF moments and evaluate size
            #size_psf = 1.0
            #try:
            #    shape_sdss_psf_val = psf.computeShape(afwGeom.Point2D(xy))
            #except:
            #    pass
            #else:
             #   record.set(shape_sdss_psf, shape_sdss_psf_val)
             #   size_psf = shape_sdss_psf_val.getDeterminantRadius()

            # object has no footprint
            radius = 0
            spanset1 = SpanSet.fromShape(radius, stencil=Stencil.CIRCLE, offset=afwGeom.Point2I(xy))
            foot = Footprint(spanset1)
            foot.addPeak(xy[0], xy[1], 0.0)
            record.setFootprint(foot)

            # draw a number between 0 and 1 to adjust sky density
            record.set(adjust_density, numpy.random.random())

            # add sky properties
            record.set(sky_mean_key, sky_mean)
            record.set(sky_std_key, sky_std)

            # add local (pixel) variance
            record.set(pix_variance, float(var[self.iround(y), self.iround(x)]))

            # required for setPrimaryFlags
            record.set(catalog.getCentroidKey(), afwGeom.Point2D(xy))

            # add healpix map value
            if self.depthMap.map is not None:
                mapIndex = healpy.pixelfunc.ang2pix(self.depthMap.nside, numpy.pi/2.0 - radec[1].asRadians(), radec[0].asRadians(), nest=self.depthMap.nest)
                record.setFlag(depth_key, self.depthMap.map[mapIndex])

        # run measurements
        task.run(catalog, coadd)

        self.setPrimaryFlags.run(catalog, skyInfo.skyMap, skyInfo.tractInfo, skyInfo.patchInfo, includeDeblend=False)

        # write catalog
        if self.config.fileOutName == "":
            if self.config.dirOutName == "" :
                fileOutName = dataRef.get(self.config.coaddName + "Coadd_forced_src_filename")[0].replace('forced_src', 'ran')
                self.log.info("WARNING: the output file will be written in {0:s}.".format(fileOutName))
            else:
                fileOutName = "{0}/{1}/{2}/{3}/ran-{1}-{2}-{3}.fits".format(self.config.dirOutName,dataRef.dataId["filter"],dataRef.dataId["tract"],dataRef.dataId["patch"])
        else:
            fileOutName = self.config.fileOutName

        self.mkdir_p(os.path.dirname(fileOutName))
        catalog.writeFits(fileOutName)

        # to do. Define output name in init (not in paf) and
        # allow parallel processing
        # write sources
        # if self.config.doWriteSources:
        #   dataRef.put(result.sources, self.dataPrefix + 'src')

        return
    def testUndeblendedMeasurement(self):
        """Check undeblended measurement and aperture correction"""
        width, height = 100, 100  # Dimensions of image
        x0, y0 = 1234, 5678  # Offset of image
        radius = 3.0  # Aperture radius
        xCenter, yCenter = width//2, height//2  # Position of first source; integer values, for convenience
        xOffset, yOffset = 1, 1  # Offset from first source to second source
        flux1, flux2 = 1000, 1  # Flux of sources
        apCorrValue = 3.21  # Aperture correction value to apply

        image = afwImage.MaskedImageF(afwGeom.ExtentI(width, height))
        image.setXY0(x0, y0)
        image.getVariance().set(1.0)

        schema = afwTable.SourceTable.makeMinimalSchema()
        schema.addField("centroid_x", type=np.float64)
        schema.addField("centroid_y", type=np.float64)
        schema.addField("centroid_flag", type='Flag')
        schema.getAliasMap().set("slot_Centroid", "centroid")

        sfmConfig = measBase.SingleFrameMeasurementConfig()
        algName = "base_CircularApertureFlux"

        for subConfig in (sfmConfig.plugins, sfmConfig.undeblended):
            subConfig.names = [algName]
            subConfig[algName].radii = [radius]
            subConfig[algName].maxSincRadius = 0  # Disable sinc photometry because we're undersampled
        slots = sfmConfig.slots
        slots.centroid = "centroid"
        slots.shape = None
        slots.psfShape = None
        slots.apFlux = None
        slots.modelFlux = None
        slots.psfFlux = None
        slots.instFlux = None
        slots.calibFlux = None

        fieldName = lsst.meas.base.CircularApertureFluxAlgorithm.makeFieldPrefix(algName, radius)
        measBase.addApCorrName(fieldName)

        apCorrConfig = measBase.ApplyApCorrConfig()
        apCorrConfig.proxies = {"undeblended_" + fieldName: fieldName}

        sfm = measBase.SingleFrameMeasurementTask(config=sfmConfig, schema=schema)
        apCorr = measBase.ApplyApCorrTask(config=apCorrConfig, schema=schema)

        cat = afwTable.SourceCatalog(schema)
        parent = cat.addNew()
        parent.set("centroid_x", x0 + xCenter)
        parent.set("centroid_y", y0 + yCenter)
        spanSetParent = afwGeom.SpanSet.fromShape(int(radius))
        spanSetParent = spanSetParent.shiftedBy(x0 + xCenter, y0 + yCenter)
        parent.setFootprint(afwDetection.Footprint(spanSetParent))

        # First child is bright, dominating the blend
        child1 = cat.addNew()
        child1.set("centroid_x", parent.get("centroid_x"))
        child1.set("centroid_y", parent.get("centroid_y"))
        child1.setParent(parent.getId())
        image.set(xCenter, yCenter, (flux1, 0, 0))
        spanSetChild1 = afwGeom.SpanSet.fromShape(1)
        spanSetChild1 = spanSetChild1.shiftedBy(x0 + xCenter, y0 + yCenter)
        foot1 = afwDetection.Footprint(spanSetChild1)
        child1.setFootprint(afwDetection.HeavyFootprintF(foot1, image))

        # Second child is fainter, but we want to be able to measure it!
        child2 = cat.addNew()
        child2.set("centroid_x", parent.get("centroid_x") + xOffset)
        child2.set("centroid_y", parent.get("centroid_y") + yOffset)
        child2.setParent(parent.getId())
        image.set(xCenter + xOffset, yCenter + yOffset, (flux2, 0, 0))
        spanSetChild2 = afwGeom.SpanSet.fromShape(1)
        tmpPoint = (x0 + xCenter + xOffset, y0 + yCenter + yOffset)
        spanSetChild2 = spanSetChild2.shiftedBy(*tmpPoint)
        foot2 = afwDetection.Footprint(spanSetChild2)
        child2.setFootprint(afwDetection.HeavyFootprintF(foot2, image))

        spans = foot1.spans.union(foot2.spans)
        bbox = afwGeom.Box2I()
        bbox.include(foot1.getBBox())
        bbox.include(foot2.getBBox())
        parent.setFootprint(afwDetection.Footprint(spans, bbox))

        exposure = afwImage.makeExposure(image)

        sfm.run(cat, exposure)

        def checkSource(source, baseName, expectedFlux):
            """Check that we get the expected results"""
            self.assertEqual(source.get(baseName + "_flux"), expectedFlux)
            self.assertGreater(source.get(baseName + "_fluxSigma"), 0)
            self.assertFalse(source.get(baseName + "_flag"))

        # Deblended
        checkSource(child1, fieldName, flux1)
        checkSource(child2, fieldName, flux2)

        # Undeblended
        checkSource(child1, "undeblended_" + fieldName, flux1 + flux2)
        checkSource(child2, "undeblended_" + fieldName, flux1 + flux2)

        # Apply aperture correction
        apCorrMap = afwImage.ApCorrMap()
        apCorrMap[fieldName + "_flux"] = afwMath.ChebyshevBoundedField(
            image.getBBox(),
            apCorrValue*np.ones((1, 1), dtype=np.float64)
        )
        apCorrMap[fieldName + "_fluxSigma"] = afwMath.ChebyshevBoundedField(
            image.getBBox(),
            apCorrValue*np.zeros((1, 1), dtype=np.float64)
        )

        apCorr.run(cat, apCorrMap)

        # Deblended
        checkSource(child1, fieldName, flux1*apCorrValue)
        checkSource(child2, fieldName, flux2*apCorrValue)

        # Undeblended
        checkSource(child1, "undeblended_" + fieldName, (flux1 + flux2)*apCorrValue)
        checkSource(child2, "undeblended_" + fieldName, (flux1 + flux2)*apCorrValue)

        self.assertIn(fieldName + "_apCorr", schema)
        self.assertIn(fieldName + "_apCorrSigma", schema)
        self.assertIn("undeblended_" + fieldName + "_apCorr", schema)
        self.assertIn("undeblended_" + fieldName + "_apCorrSigma", schema)
예제 #20
0
    def testInputCounts(self, showPlot=False):
        # Generate a simulated coadd of four overlapping-but-offset CCDs.
        # Populate it with three sources.
        # Demonstrate that we can correctly recover the number of images which
        # contribute to each source.

        size = 20  # Size of images (pixels)
        value = 100.0  # Source flux

        ccdPositions = [
            lsst.geom.Point2D(8, 0),
            lsst.geom.Point2D(10, 10),
            lsst.geom.Point2D(-8, -8),
            lsst.geom.Point2D(-8, 8)
        ]

        # Represent sources by a tuple of position and expected number of
        # contributing CCDs (based on the size/positions given above).
        Source = namedtuple("Source", ["pos", "count"])
        sources = [
            Source(pos=lsst.geom.Point2D(6, 6), count=2),
            Source(pos=lsst.geom.Point2D(10, 10), count=3),
            Source(pos=lsst.geom.Point2D(14, 14), count=1)
        ]

        # These lines are used in the creation of WCS information
        scale = 1.0e-5 * lsst.geom.degrees
        cdMatrix = afwGeom.makeCdMatrix(scale=scale)
        crval = lsst.geom.SpherePoint(0.0, 0.0, lsst.geom.degrees)

        # Construct the info needed to set the exposure object
        imageBox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0),
                                   lsst.geom.Extent2I(size, size))
        wcsRef = afwGeom.makeSkyWcs(crpix=lsst.geom.Point2D(0, 0),
                                    crval=crval,
                                    cdMatrix=cdMatrix)

        # Create the exposure object, and set it up to be the output of a coadd
        exp = afwImage.ExposureF(size, size)
        exp.setWcs(wcsRef)
        exp.getInfo().setCoaddInputs(
            afwImage.CoaddInputs(afwTable.ExposureTable.makeMinimalSchema(),
                                 afwTable.ExposureTable.makeMinimalSchema()))

        # Set the fake CCDs that "went into" making this coadd, using the
        # differing wcs objects created above.
        ccds = exp.getInfo().getCoaddInputs().ccds
        for pos in ccdPositions:
            record = ccds.addNew()
            record.setWcs(
                afwGeom.makeSkyWcs(crpix=pos, crval=crval, cdMatrix=cdMatrix))
            record.setBBox(imageBox)
            record.setValidPolygon(afwGeom.Polygon(lsst.geom.Box2D(imageBox)))

        # Configure a SingleFrameMeasurementTask to run InputCounts.
        measureSourcesConfig = measBase.SingleFrameMeasurementConfig()
        measureSourcesConfig.plugins.names = [
            "base_PeakCentroid", "base_InputCount"
        ]
        measureSourcesConfig.slots.centroid = "base_PeakCentroid"
        measureSourcesConfig.slots.psfFlux = None
        measureSourcesConfig.slots.apFlux = None
        measureSourcesConfig.slots.modelFlux = None
        measureSourcesConfig.slots.gaussianFlux = None
        measureSourcesConfig.slots.calibFlux = None
        measureSourcesConfig.slots.shape = None
        measureSourcesConfig.validate()
        schema = afwTable.SourceTable.makeMinimalSchema()
        task = measBase.SingleFrameMeasurementTask(schema,
                                                   config=measureSourcesConfig)
        catalog = afwTable.SourceCatalog(schema)

        # Add simulated sources to the measurement catalog.
        for src in sources:
            spans = afwGeom.SpanSet.fromShape(1)
            spans = spans.shiftedBy(int(src.pos.getX()), int(src.pos.getY()))
            foot = afwDetection.Footprint(spans)
            peak = foot.getPeaks().addNew()
            peak.setFx(src.pos[0])
            peak.setFy(src.pos[1])
            peak.setPeakValue(value)
            catalog.addNew().setFootprint(foot)

        task.run(catalog, exp)

        for src, rec in zip(sources, catalog):
            self.assertEqual(rec.get("base_InputCount_value"), src.count)

        if display:
            ccdVennDiagram(exp)
예제 #21
0
    def setUp(self):
        width, height = 100, 300
        self.mi = afwImage.MaskedImageF(afwGeom.ExtentI(width, height))
        self.mi.set(0)
        self.mi.getVariance().set(10)
        self.mi.getMask().addMaskPlane("DETECTED")

        self.FWHM = 5
        self.ksize = 25  # size of desired kernel

        self.exposure = afwImage.makeExposure(self.mi)

        psf = roundTripPsf(
            2,
            algorithms.DoubleGaussianPsf(
                self.ksize, self.ksize,
                self.FWHM / (2 * math.sqrt(2 * math.log(2))), 1, 0.1))
        self.exposure.setPsf(psf)

        for x, y in [
            (20, 20),
                #(30, 35), (50, 50),
            (60, 20),
            (60, 210),
            (20, 210)
        ]:

            flux = 10000 - 0 * x - 10 * y

            sigma = 3 + 0.01 * (y - self.mi.getHeight() / 2)
            psf = roundTripPsf(
                3,
                algorithms.DoubleGaussianPsf(self.ksize, self.ksize, sigma, 1,
                                             0.1))
            im = psf.computeImage().convertF()
            im *= flux
            x0y0 = afwGeom.PointI(x - self.ksize // 2, y - self.ksize // 2)
            smi = self.mi.getImage().Factory(
                self.mi.getImage(),
                afwGeom.BoxI(x0y0, afwGeom.ExtentI(self.ksize)),
                afwImage.LOCAL)

            if False:  # Test subtraction with non-centered psfs
                im = afwMath.offsetImage(im, 0.5, 0.5)

            smi += im
            del psf
            del im
            del smi

        roundTripPsf(
            4,
            algorithms.DoubleGaussianPsf(
                self.ksize, self.ksize,
                self.FWHM / (2 * math.sqrt(2 * math.log(2))), 1, 0.1))

        self.cellSet = afwMath.SpatialCellSet(
            afwGeom.BoxI(afwGeom.PointI(0, 0), afwGeom.ExtentI(width, height)),
            100)
        ds = afwDetection.FootprintSet(self.mi, afwDetection.Threshold(10),
                                       "DETECTED")
        #
        # Prepare to measure
        #
        schema = afwTable.SourceTable.makeMinimalSchema()
        sfm_config = measBase.SingleFrameMeasurementConfig()
        sfm_config.plugins = [
            "base_SdssCentroid", "base_CircularApertureFlux", "base_PsfFlux",
            "base_SdssShape", "base_GaussianFlux", "base_PixelFlags"
        ]
        sfm_config.slots.centroid = "base_SdssCentroid"
        sfm_config.slots.shape = "base_SdssShape"
        sfm_config.slots.psfFlux = "base_PsfFlux"
        sfm_config.slots.instFlux = None
        sfm_config.slots.apFlux = "base_CircularApertureFlux_3_0"
        sfm_config.slots.modelFlux = "base_GaussianFlux"
        sfm_config.slots.calibFlux = None
        sfm_config.plugins["base_SdssShape"].maxShift = 10.0
        sfm_config.plugins["base_CircularApertureFlux"].radii = [3.0]
        task = measBase.SingleFrameMeasurementTask(schema, config=sfm_config)
        measCat = afwTable.SourceCatalog(schema)
        # detect the sources and run with the measurement task
        ds.makeSources(measCat)
        task.run(measCat, self.exposure)
        for source in measCat:
            self.cellSet.insertCandidate(
                algorithms.makePsfCandidate(source, self.exposure))
예제 #22
0
    def testDetection(self):
        """Test object detection"""
        #
        # Fix defects
        #
        # Mask known bad pixels
        #
        measAlgorithmsDir = lsst.utils.getPackageDir('meas_algorithms')
        badPixels = defects.policyToBadRegionList(os.path.join(measAlgorithmsDir,
                                                               "policy/BadPixels.paf"))
        # did someone lie about the origin of the maskedImage?  If so, adjust bad pixel list
        if self.XY0.getX() != self.mi.getX0() or self.XY0.getY() != self.mi.getY0():
            dx = self.XY0.getX() - self.mi.getX0()
            dy = self.XY0.getY() - self.mi.getY0()
            for bp in badPixels:
                bp.shift(-dx, -dy)

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

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

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

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

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

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

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

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

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

            if display:
                disp.dot("+", source.getX(), source.getY())
예제 #23
0
    def testFootprintsMeasure(self):
        """Check that we can measure the objects in a detectionSet"""

        xcentroid = [10.0, 14.0, 9.0]
        ycentroid = [8.0, 11.5061728, 14.0]
        flux = [51.0, 101.0, 20.0]
        # sqrt of num pixels in aperture; note the second source is offset
        # from the pixel grid.
        fluxErr = [math.sqrt(29), math.sqrt(27), math.sqrt(29)]

        footprints = afwDetection.FootprintSet(self.mi, afwDetection.Threshold(10), "DETECTED")

        if display:
            disp = afwDisplay.Display(frame=0)
            disp.mtv(self.mi, title=self._testMethodName + ": image")
            afwDisplay.Display(frame=1).mtv(self.mi.getVariance(), title=self._testMethodName + ": variance")

        measureSourcesConfig = measBase.SingleFrameMeasurementConfig()
        measureSourcesConfig.algorithms["base_CircularApertureFlux"].radii = [3.0]
        # Numerical tests below assumes that we are not using sinc fluxes.
        measureSourcesConfig.algorithms["base_CircularApertureFlux"].maxSincRadius = 0.0
        measureSourcesConfig.algorithms.names = ["base_NaiveCentroid", "base_SdssShape", "base_PsfFlux",
                                                 "base_CircularApertureFlux"]
        measureSourcesConfig.slots.centroid = "base_NaiveCentroid"
        measureSourcesConfig.slots.psfFlux = "base_PsfFlux"
        measureSourcesConfig.slots.apFlux = "base_CircularApertureFlux_3_0"
        measureSourcesConfig.slots.modelFlux = None
        measureSourcesConfig.slots.gaussianFlux = None
        measureSourcesConfig.slots.calibFlux = None

        schema = afwTable.SourceTable.makeMinimalSchema()
        task = measBase.SingleFrameMeasurementTask(schema, config=measureSourcesConfig)
        measCat = afwTable.SourceCatalog(schema)
        footprints.makeSources(measCat)
        # now run the SFM task with the test plugin
        sigma = 1e-10
        psf = algorithms.DoubleGaussianPsf(11, 11, sigma)  # i.e. a single pixel
        self.exposure.setPsf(psf)
        task.run(measCat, self.exposure)

        self.assertEqual(len(measCat), len(flux))
        for i, source in enumerate(measCat):

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

            self.assertAlmostEqual(source.getX(), xcentroid[i], 6)
            self.assertAlmostEqual(source.getY(), ycentroid[i], 6)
            self.assertEqual(source.getApInstFlux(), flux[i])
            self.assertAlmostEqual(source.getApInstFluxErr(), fluxErr[i], 6)

            # We're using a delta-function PSF, so the psfFlux should be the
            # pixel under the centroid, iff the object's centred in the pixel
            if xc == int(xc) and yc == int(yc):
                self.assertAlmostEqual(source.getPsfInstFlux(),
                                       self.exposure.getMaskedImage().getImage()[int(xc + 0.5),
                                                                                 int(yc + 0.5)])
                self.assertAlmostEqual(source.getPsfInstFluxErr(),
                                       self.exposure.getMaskedImage().getVariance()[int(xc + 0.5),
                                                                                    int(yc + 0.5)])
예제 #24
0
    def setUp(self):
        size = 128  # size of image (pixels)
        center = afwGeom.Point2D(size // 2, size // 2)  # object center
        width = 2  # PSF width
        flux = 10.0  # Flux of object
        variance = 1.0  # Mean variance value
        varianceStd = 0.1  # Standard deviation of the variance value

        # Set a seed for predictable randomness
        np.random.seed(300)

        # Create a random image to be used as variance plane
        variancePlane = np.random.normal(variance, varianceStd,
                                         size * size).reshape(size, size)

        # Initial setup of an image
        exp = afwImage.ExposureF(size, size)
        image = exp.getMaskedImage().getImage()
        mask = exp.getMaskedImage().getMask()
        var = exp.getMaskedImage().getVariance()
        image.set(0.0)
        mask.set(0)
        var.getArray()[:, :] = variancePlane

        # Put down a PSF
        psfSize = int(6 * width + 1)  # Size of PSF image; must be odd
        psf = afwDetection.GaussianPsf(psfSize, psfSize, width)
        exp.setPsf(psf)
        psfImage = psf.computeImage(center).convertF()
        psfImage *= flux
        image.Factory(image,
                      psfImage.getBBox(afwImage.PARENT)).__iadd__(psfImage)
        var.Factory(var, psfImage.getBBox(afwImage.PARENT)).__iadd__(psfImage)

        # Put in some bad pixels to ensure they're ignored
        for i in range(-5, 6):
            bad = size // 2 + i * width
            var.getArray()[bad, :] = float("nan")
            mask.getArray()[bad, :] = mask.getPlaneBitMask("BAD")
            var.getArray()[:, bad] = float("nan")
            mask.getArray()[:, bad] = mask.getPlaneBitMask("BAD")

        # Put in some unmasked bad pixels outside the expected aperture, to ensure the aperture is working
        var.getArray()[0, 0] = float("nan")
        var.getArray()[0, -1] = float("nan")
        var.getArray()[-1, 0] = float("nan")
        var.getArray()[-1, -1] = float("nan")

        if display:
            import lsst.afw.display as afwDisplay
            afwDisplay.getDisplay(1).mtv(image)
            afwDisplay.getDisplay(2).mtv(mask)
            afwDisplay.getDisplay(3).mtv(var)

        config = measBase.SingleFrameMeasurementConfig()
        config.plugins.names = [
            "base_NaiveCentroid", "base_SdssShape", "base_Variance"
        ]
        config.slots.centroid = "base_NaiveCentroid"
        config.slots.psfFlux = None
        config.slots.apFlux = None
        config.slots.modelFlux = None
        config.slots.instFlux = None
        config.slots.calibFlux = None
        config.slots.shape = "base_SdssShape"
        config.slots.psfShape = None
        config.plugins["base_Variance"].mask = ["BAD", "SAT"]

        config.validate()
        schema = afwTable.SourceTable.makeMinimalSchema()

        task = measBase.SingleFrameMeasurementTask(schema, config=config)
        catalog = afwTable.SourceCatalog(schema)

        spans = afwGeom.SpanSet.fromShape(int(width))
        spans = spans.shiftedBy(int(center.getX()), int(center.getY()))
        foot = afwDetection.Footprint(spans)
        peak = foot.getPeaks().addNew()
        peak.setIx(int(center.getX()))
        peak.setIy(int(center.getY()))
        peak.setFx(center.getX())
        peak.setFy(center.getY())
        peak.setPeakValue(flux)

        source = catalog.addNew()
        source.setFootprint(foot)

        self.variance = variance
        self.varianceStd = varianceStd
        self.mask = mask
        self.catalog = catalog
        self.exp = exp
        self.task = task
        self.source = source
    def setUp(self):

        self.schema = afwTable.SourceTable.makeMinimalSchema()
        config = measBase.SingleFrameMeasurementConfig()
        config.algorithms.names = [
            "base_PixelFlags",
            "base_SdssCentroid",
            "base_GaussianFlux",
            "base_SdssShape",
            "base_CircularApertureFlux",
            "base_PsfFlux",
        ]
        config.algorithms["base_CircularApertureFlux"].radii = [3.0]
        config.slots.centroid = "base_SdssCentroid"
        config.slots.psfFlux = "base_PsfFlux"
        config.slots.apFlux = "base_CircularApertureFlux_3_0"
        config.slots.modelFlux = None
        config.slots.instFlux = None
        config.slots.calibFlux = None
        config.slots.shape = "base_SdssShape"

        self.measureTask = measBase.SingleFrameMeasurementTask(self.schema,
                                                               config=config)

        width, height = 110, 301

        self.mi = afwImage.MaskedImageF(afwGeom.ExtentI(width, height))
        self.mi.set(0)
        sd = 3  # standard deviation of image
        self.mi.getVariance().set(sd * sd)
        self.mi.getMask().addMaskPlane("DETECTED")

        self.FWHM = 5
        self.ksize = 31  # size of desired kernel

        sigma1 = 1.75
        sigma2 = 2 * sigma1

        self.exposure = afwImage.makeExposure(self.mi)
        self.exposure.setPsf(
            measAlg.DoubleGaussianPsf(self.ksize, self.ksize, 1.5 * sigma1, 1,
                                      0.1))
        self.exposure.setDetector(DetectorWrapper().detector)

        #
        # Make a kernel with the exactly correct basis functions.  Useful for debugging
        #
        basisKernelList = []
        for sigma in (sigma1, sigma2):
            basisKernel = afwMath.AnalyticKernel(
                self.ksize, self.ksize,
                afwMath.GaussianFunction2D(sigma, sigma))
            basisImage = afwImage.ImageD(basisKernel.getDimensions())
            basisKernel.computeImage(basisImage, True)
            basisImage /= np.sum(basisImage.getArray())

            if sigma == sigma1:
                basisImage0 = basisImage
            else:
                basisImage -= basisImage0

            basisKernelList.append(afwMath.FixedKernel(basisImage))

        order = 1  # 1 => up to linear
        spFunc = afwMath.PolynomialFunction2D(order)

        exactKernel = afwMath.LinearCombinationKernel(basisKernelList, spFunc)
        exactKernel.setSpatialParameters([[1.0, 0, 0],
                                          [0.0, 0.5 * 1e-2, 0.2e-2]])
        self.exactPsf = measAlg.PcaPsf(exactKernel)

        rand = afwMath.Random()  # make these tests repeatable by setting seed

        addNoise = True

        if addNoise:
            im = self.mi.getImage()
            afwMath.randomGaussianImage(im, rand)  # N(0, 1)
            im *= sd  # N(0, sd^2)
            del im

        xarr, yarr = [], []

        for x, y in [
            (20, 20),
            (60, 20),
            (30, 35),
            (50, 50),
            (20, 90),
            (70, 160),
            (25, 265),
            (75, 275),
            (85, 30),
            (50, 120),
            (70, 80),
            (60, 210),
            (20, 210),
        ]:
            xarr.append(x)
            yarr.append(y)

        for x, y in zip(xarr, yarr):
            dx = rand.uniform() - 0.5  # random (centered) offsets
            dy = rand.uniform() - 0.5

            k = exactKernel.getSpatialFunction(1)(
                x, y)  # functional variation of Kernel ...
            b = (k * sigma1**2 / ((1 - k) * sigma2**2)
                 )  # ... converted double Gaussian's "b"

            # flux = 80000 - 20*x - 10*(y/float(height))**2
            flux = 80000 * (1 + 0.1 * (rand.uniform() - 0.5))
            I0 = flux * (1 + b) / (2 * np.pi * (sigma1**2 + b * sigma2**2))
            for iy in range(y - self.ksize // 2, y + self.ksize // 2 + 1):
                if iy < 0 or iy >= self.mi.getHeight():
                    continue

                for ix in range(x - self.ksize // 2, x + self.ksize // 2 + 1):
                    if ix < 0 or ix >= self.mi.getWidth():
                        continue

                    intensity = I0 * psfVal(ix, iy, x + dx, y + dy, sigma1,
                                            sigma2, b)
                    Isample = rand.poisson(
                        intensity) if addNoise else intensity
                    self.mi.getImage().set(
                        ix, iy,
                        self.mi.getImage().get(ix, iy) + Isample)
                    self.mi.getVariance().set(
                        ix, iy,
                        self.mi.getVariance().get(ix, iy) + intensity)
        #
        bbox = afwGeom.BoxI(afwGeom.PointI(0, 0),
                            afwGeom.ExtentI(width, height))
        self.cellSet = afwMath.SpatialCellSet(bbox, 100)

        self.footprintSet = afwDetection.FootprintSet(
            self.mi, afwDetection.Threshold(100), "DETECTED")
        self.catalog = self.measure(self.footprintSet, self.exposure)

        for source in self.catalog:
            try:
                cand = measAlg.makePsfCandidate(source, self.exposure)
                self.cellSet.insertCandidate(cand)

            except Exception as e:
                print(e)
                continue
예제 #26
0
    def setUp(self):
        self.x0, self.y0 = 0, 0
        self.nx, self.ny = 512, 512 #2048, 4096
        self.sky = 100.0
        self.nObj = 100

        # make a detector with distortion
        self.detector = DetectorWrapper(
            bbox = afwGeom.Box2I(afwGeom.Point2I(0,0), afwGeom.Extent2I(self.nx, self.ny)),
            orientation = cameraGeom.Orientation(afwGeom.Point2D(255.0, 255.0)),
            radialDistortion = 0.925,
        ).detector

        # make a detector with no distortion
        self.flatDetector = DetectorWrapper(
            bbox = afwGeom.Box2I(afwGeom.Point2I(0,0), afwGeom.Extent2I(self.nx, self.ny)),
            orientation = cameraGeom.Orientation(afwGeom.Point2D(255.0, 255.0)),
            radialDistortion = 0.0,
        ).detector

        # detection policies
        detConfig = measAlg.SourceDetectionConfig()
        # Cannot use default background approximation order (6) for such a small image.
        detConfig.background.approxOrderX = 4

        # measurement policies
        measConfig = measBase.SingleFrameMeasurementConfig()
        measConfig.algorithms.names = [
                 "base_SdssCentroid",
                 "base_SdssShape",
                 "base_GaussianFlux",
                 "base_PsfFlux",
                 ]
        measConfig.slots.centroid = "base_SdssCentroid"
        measConfig.slots.shape = "base_SdssShape"
        measConfig.slots.psfFlux = "base_PsfFlux"
        measConfig.slots.apFlux = None
        measConfig.slots.modelFlux = None
        measConfig.slots.instFlux = None
        measConfig.slots.calibFlux = None

        self.schema = afwTable.SourceTable.makeMinimalSchema()
        detConfig.validate()
        measConfig.validate()
        self.detTask = measAlg.SourceDetectionTask(config=detConfig, schema=self.schema)
        self.measTask = measBase.SingleFrameMeasurementTask(config=measConfig, schema=self.schema)

        # psf star selector
        starSelectorConfig = measAlg.SecondMomentStarSelectorTask.ConfigClass()
        starSelectorConfig.fluxLim = 5000.0
        starSelectorConfig.histSize = 32
        starSelectorConfig.clumpNSigma = 1.0
        starSelectorConfig.badFlags = []
        self.starSelector = measAlg.SecondMomentStarSelectorTask(
            config=starSelectorConfig, schema=self.schema
        )

        # psf determiner
        psfDeterminerFactory = measAlg.psfDeterminerRegistry["pca"]
        psfDeterminerConfig = psfDeterminerFactory.ConfigClass()
        width, height = self.nx, self.ny
        nEigenComponents = 3
        psfDeterminerConfig.sizeCellX = width//3
        psfDeterminerConfig.sizeCellY = height//3
        psfDeterminerConfig.nEigenComponents = nEigenComponents
        psfDeterminerConfig.spatialOrder = 1
        psfDeterminerConfig.kernelSizeMin = 31
        psfDeterminerConfig.nStarPerCell = 0
        psfDeterminerConfig.nStarPerCellSpatialFit = 0 # unlimited
        self.psfDeterminer = psfDeterminerFactory(psfDeterminerConfig)
 def makeSourceSchema(self):
     schema = afwTable.SourceTable.makeMinimalSchema()
     measBase.SingleFrameMeasurementTask(schema=schema)  # expand the schema
     return schema