33 from .sfm
import SingleFrameMeasurementTask
38 bbox = image.getBBox()
39 x, y = numpy.meshgrid(numpy.arange(bbox.getBeginX(), bbox.getEndX()),
40 numpy.arange(bbox.getBeginY(), bbox.getEndY()))
41 t = ellipse.getGridTransform()
42 xt = t[t.XX] * x + t[t.XY] * y + t[t.X]
43 yt = t[t.YX] * y + t[t.YY] * y + t[t.Y]
44 image.getArray()[:,:] = numpy.exp(-0.5*(xt**2 + yt**2))
45 image.getArray()[:,:] *= flux / image.getArray().
sum()
49 """Create and return the truth catalog and bounding box for the simulation.
51 The simulated records will be in image coordinates, and no footprints will be attached.
54 nChildKey = schema.addField(
"deblend_nchild", type=int)
55 xKey = schema.addField(
"truth_x", type=float,
56 doc=
"true simulated centroid x", units=
"pixels")
57 yKey = schema.addField(
"truth_y", type=float,
58 doc=
"true simulated centroid y", units=
"pixels")
60 fluxKey = schema.addField(
"truth_flux", type=float, doc=
"true flux", units=
"dn")
61 xxKey = schema.addField(
"truth_xx", type=float,
62 doc=
"true shape after PSF convolution", units=
"pixels^2")
63 yyKey = schema.addField(
"truth_yy", type=float,
64 doc=
"true shape after PSF convolution", units=
"pixels^2")
65 xyKey = schema.addField(
"truth_xy", type=float,
66 doc=
"true shape after PSF convolution", units=
"pixels^2")
68 starFlagKey = schema.addField(
"truth_isStar", type=
"Flag", doc=
"set if the object is a star")
73 record = catalog.addNew()
74 record.set(nChildKey, 0)
76 record.set(fluxKey, 100000.0)
78 record.set(starFlagKey,
True)
80 record = catalog.addNew()
81 record.set(nChildKey, 0)
83 record.set(fluxKey, 75000.0)
85 record.set(starFlagKey,
False)
87 parent = catalog.addNew()
88 parent.set(nChildKey, 2)
89 record1 = catalog.addNew()
90 record1.set(nChildKey, 0)
91 record1.setParent(parent.getId())
93 record1.set(fluxKey, 80000.0)
95 record1.set(starFlagKey,
True)
96 record2 = catalog.addNew()
97 record2.set(nChildKey, 0)
98 record2.setParent(parent.getId())
100 record2.set(fluxKey, 120000.0)
102 record2.set(starFlagKey,
False)
103 parent.set(fluxKey, record1.get(fluxKey) + record2.get(fluxKey))
104 parent.set(starFlagKey,
False)
110 / parent.get(fluxKey)
119 """Create an Exposure, with a Calib, Wcs, and Psf, but no pixel values set.
121 @param[in] bbox Bounding box of the image (image coordinates) as returned by makeCatalog.
122 @param[in] crval afw.coord.Coord: center of the TAN WCS attached to the image.
123 @param[in] psfSigma Radius (sigma) of the Gaussian PSF attached to the image
124 @param[in] psfDim Width and height of the image's Gaussian PSF attached to the image
125 @param[in] fluxMag0 Flux at magnitude zero (in e-) used to set the Calib of the exposure.
129 exposure = lsst.afw.image.ExposureF(bbox)
131 cdelt = (0.2 * lsst.afw.geom.arcseconds).asDegrees()
135 calib.setFluxMag0(fluxMag0)
138 exposure.setCalib(calib)
142 def fillImages(catalog, exposure, threshold=None, noise=100.0):
143 """Fill a simulated Exposure from makeEmptyExposure() with the objects defined by a truth catalog from
144 makeTruthCatalog(). Also attaches Footprints to the SourceRecords in the catalog, sets the
145 'coord' field, and fills in the detection mask planes. The Footprints will be regular Footprints
146 for non-blended objects, and HeavyFootprints for deblended objects, intended to mimic
147 better-than-realistic outputs from detection and deblending.
149 @param[in,out] catalog SourceCatalog created by makeCatalog. HeavyFootprints and 'coord' will
150 be filled on return, and shapes will be convolved by the PSF shape.
151 @param[in,out] exposure ExposureF to fill, as created by makeEmptyExposure()
152 @param[in] threshold afw.detection.Threshold object used to determine the size of the
153 HeavyFootprints attached to the SourceCatalog (after thresholding, we'll
154 also grow the Footprints by the PSF sigma).
155 @param[in] noise Standard deviation of Gaussian noise added to image (constant across the
156 image; appropriate for sky-dominated limit).
158 if threshold
is None:
161 psf = lsst.afw.detection.GaussianPsf.cast(exposure.getPsf())
162 schema = catalog.schema
163 nChildKey = schema.find(
"deblend_nchild").key
166 schema.find(
"truth_xy").key)
167 fluxKey = schema.find(
"truth_flux").key
171 images = {record.getId(): lsst.afw.image.ImageF(exposure.getBBox())
172 for record
in catalog}
173 for record
in catalog:
174 if record.get(nChildKey) != 0:
continue
176 record.get(centroidKey))
177 record.set(shapeKey, ellipse.getCore())
178 MakeTestData.drawGaussian(images[record.getId()], record.get(fluxKey), ellipse)
179 exposure.getMaskedImage().getImage().getArray()[:,:] += images[record.getId()].getArray()[:,:]
180 if record.getParent() != 0:
181 images[record.getParent()] += images[record.getId()]
183 exposure.getMaskedImage().getVariance().getArray()[:,:] = noise**2
184 exposure.getMaskedImage().getImage().getArray()[:,:] \
185 += numpy.random.randn(exposure.getHeight(), exposure.getWidth())*noise
188 for record
in catalog:
193 if len(fpSet.getFootprints()) != 1:
194 raise ValueError(
"Threshold value results in multiple Footprints for a single object")
195 fpSet.setMask(exposure.getMaskedImage().getMask(),
"DETECTED")
196 record.setFootprint(fpSet.getFootprints()[0])
200 for parent
in catalog.getChildren(0):
201 print "Processing parent object", parent.getId()
202 for child
in catalog.getChildren(parent.getId()):
203 print "Processing child object", child.getId()
204 fraction = images[child.getId()].getArray() / images[parent.getId()].getArray()
205 deblend = lsst.afw.image.MaskedImageF(exposure.getMaskedImage(),
True)
206 deblend.getImage().getArray()[:,:] *= fraction
207 child.setFootprint(lsst.afw.detection.HeavyFootprintF(child.getFootprint(), deblend))
213 catalog, bbox = MakeTestData.makeCatalog()
214 exposure = MakeTestData.makeEmptyExposure(bbox)
215 MakeTestData.fillImages(catalog, exposure)
216 schema = catalog.schema
221 schema.find(
"truth_xy").key)
233 config = SingleFrameMeasurementTask.ConfigClass()
234 config.slots.centroid =
None
235 config.slots.shape =
None
236 config.slots.modelFlux =
None
237 config.slots.apFlux =
None
238 config.slots.psfFlux =
None
239 config.slots.instFlux =
None
240 config.plugins.names = (plugin,) + tuple(dependencies)
242 schemaMapper.addMinimalSchema(self.truth.schema)
244 task = SingleFrameMeasurementTask(schema=schemaMapper.editOutputSchema(), algMetadata=algMetadata,
247 measCat.table.setMetadata(algMetadata)
248 measCat.extend(self.
truth, schemaMapper)
249 measCat.getTable().defineModelFlux(
"truth")
250 measCat.getTable().defineCentroid(
"truth")
251 measCat.getTable().defineShape(
"truth")
252 task.run(measCat, self.
calexp)
An ellipse core with quadrupole moments as parameters.
Class for storing ordered metadata with comments.
A mapping between the keys of two Schemas, used to copy data between them.
def runSingleFrameMeasurementTask
A Threshold is used to pass a threshold value to detection algorithms.
An integer coordinate rectangle.
Custom catalog class for record/table subclasses that are guaranteed to have an ID, and should generally be sorted by that ID.
An ellipse defined by an arbitrary BaseCore and a center point.
Wcs::Ptr makeWcs(coord::Coord const &crval, geom::Point2D const &crpix, double CD11, double CD12, double CD21, double CD22)
Create a Wcs object from crval, crpix, CD, using CD elements (useful from python) ...
static Schema makeMinimalSchema()
Return a minimal schema for Source tables and records.
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, ConvolutionControl const &convolutionControl=ConvolutionControl())
Convolve an Image or MaskedImage with a Kernel, setting pixels of an existing output image...
A floating-point coordinate rectangle geometry.
A FunctorKey used to get or set a geom::ellipses::Quadrupole from an (xx,yy,xy) tuple of Keys...
A class to handle Icrs coordinates (inherits from Coord)
A circularly symmetric Gaussian Psf class with no spatial variation, intended mostly for testing purp...