32 from .makeKernelBasisList
import makeKernelBasisList
33 from .psfMatch
import PsfMatchTask, PsfMatchConfigDF, PsfMatchConfigAL
34 from .
import utils
as diUtils
35 from .
import diffimLib
36 from .
import diffimTools
39 sigma2fwhm = 2. * np.sqrt(2. * np.log(2.))
42 """!Configuration for image-to-image Psf matching"""
43 kernel = pexConfig.ConfigChoiceField(
51 selectDetection = pexConfig.ConfigurableField(
52 target=SourceDetectionTask,
53 doc=
"Initial detections used to feed stars to kernel fitting",
55 selectMeasurement = pexConfig.ConfigurableField(
56 target=SingleFrameMeasurementTask,
57 doc=
"Initial measurements used to feed stars to kernel fitting",
62 self.selectDetection.reEstimateBackground =
False
63 self.selectDetection.thresholdValue = 10.0
66 self.selectMeasurement.algorithms.names.clear()
67 self.selectMeasurement.algorithms.names = (
'base_SdssCentroid',
'base_PsfFlux',
'base_PixelFlags',
68 'base_SdssShape',
'base_GaussianFlux',
'base_SkyCoord')
69 self.selectMeasurement.slots.modelFlux =
None
70 self.selectMeasurement.slots.apFlux =
None
81 \anchor ImagePsfMatchTask_
83 \brief Psf-match two MaskedImages or Exposures using the sources in the images
85 \section ip_diffim_imagepsfmatch_Contents Contents
87 - \ref ip_diffim_imagepsfmatch_Purpose
88 - \ref ip_diffim_imagepsfmatch_Initialize
89 - \ref ip_diffim_imagepsfmatch_IO
90 - \ref ip_diffim_imagepsfmatch_Config
91 - \ref ip_diffim_imagepsfmatch_Metadata
92 - \ref ip_diffim_imagepsfmatch_Debug
93 - \ref ip_diffim_imagepsfmatch_Example
95 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
97 \section ip_diffim_imagepsfmatch_Purpose Description
99 Build a Psf-matching kernel using two input images, either as MaskedImages (in which case they need
100 to be astrometrically aligned) or Exposures (in which case astrometric alignment will happen by
101 default but may be turned off). This requires a list of input Sources which may be provided
102 by the calling Task; if not, the Task will perform a coarse source detection and selection for this purpose.
103 Sources are vetted for signal-to-noise and masked pixels (in both the template and science image), and
104 substamps around each acceptable source are extracted and used to create an instance of KernelCandidate.
105 Each KernelCandidate is then placed within a lsst.afw.math.SpatialCellSet, which is used by an ensemble of
106 lsst.afw.math.CandidateVisitor instances to build the Psf-matching kernel. These visitors include, in
107 the order that they are called: BuildSingleKernelVisitor, KernelSumVisitor, BuildSpatialKernelVisitor,
108 and AssessSpatialKernelVisitor.
110 Sigma clipping of KernelCandidates is performed as follows:
111 - BuildSingleKernelVisitor, using the substamp diffim residuals from the per-source kernel fit,
112 if PsfMatchConfig.singleKernelClipping is True
113 - KernelSumVisitor, using the mean and standard deviation of the kernel sum from all candidates,
114 if PsfMatchConfig.kernelSumClipping is True
115 - AssessSpatialKernelVisitor, using the substamp diffim ressiduals from the spatial kernel fit,
116 if PsfMatchConfig.spatialKernelClipping is True
118 The actual solving for the kernel (and differential background model) happens in
119 lsst.ip.diffim.PsfMatchTask._solve. This involves a loop over the SpatialCellSet that first builds the
120 per-candidate matching kernel for the requested number of KernelCandidates per cell
121 (PsfMatchConfig.nStarPerCell). The quality of this initial per-candidate difference image is examined,
122 using moments of the pixel residuals in the difference image normalized by the square root of the variance
123 (i.e. sigma); ideally this should follow a normal (0, 1) distribution, but the rejection thresholds are set
124 by the config (PsfMatchConfig.candidateResidualMeanMax and PsfMatchConfig.candidateResidualStdMax).
125 All candidates that pass this initial build are then examined en masse to find the
126 mean/stdev of the kernel sums across all candidates. Objects that are significantly above or below the mean,
127 typically due to variability or sources that are saturated in one image but not the other, are also rejected.
128 This threshold is defined by PsfMatchConfig.maxKsumSigma. Finally, a spatial model is built using all
129 currently-acceptable candidates, and the spatial model used to derive a second set of (spatial) residuals
130 which are again used to reject bad candidates, using the same thresholds as above.
132 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
134 \section ip_diffim_imagepsfmatch_Initialize Task initialization
136 \copydoc \_\_init\_\_
138 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
140 \section ip_diffim_imagepsfmatch_IO Invoking the Task
142 There is no run() method for this Task. Instead there are 4 methods that
143 may be used to invoke the Psf-matching. These are
144 \link lsst.ip.diffim.imagePsfMatch.ImagePsfMatchTask.matchMaskedImages matchMaskedImages\endlink,
145 \link lsst.ip.diffim.imagePsfMatch.ImagePsfMatchTask.subtractMaskedImages subtractMaskedImages\endlink,
146 \link lsst.ip.diffim.imagePsfMatch.ImagePsfMatchTask.matchExposures matchExposures\endlink, and
147 \link lsst.ip.diffim.imagePsfMatch.ImagePsfMatchTask.subtractExposures subtractExposures\endlink.
149 The methods that operate on lsst.afw.image.MaskedImage require that the images already be astrometrically
150 aligned, and are the same shape. The methods that operate on lsst.afw.image.Exposure allow for the
151 input images to be misregistered and potentially be different sizes; by default a
152 lsst.afw.math.LanczosWarpingKernel is used to perform the astrometric alignment. The methods
153 that "match" images return a Psf-matched image, while the methods that "subtract" images
154 return a Psf-matched and template subtracted image.
156 See each method's returned lsst.pipe.base.Struct for more details.
158 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
160 \section ip_diffim_imagepsfmatch_Config Configuration parameters
162 See \ref ImagePsfMatchConfig
164 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
166 \section ip_diffim_imagepsfmatch_Metadata Quantities set in Metadata
168 See \ref ip_diffim_psfmatch_Metadata "PsfMatchTask"
170 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
172 \section ip_diffim_imagepsfmatch_Debug Debug variables
174 The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a
175 flag \c -d/--debug to import \b debug.py from your \c PYTHONPATH. The relevant contents of debug.py
176 for this Task include:
182 di = lsstDebug.getInfo(name)
183 if name == "lsst.ip.diffim.psfMatch":
184 di.display = True # enable debug output
185 di.maskTransparency = 80 # ds9 mask transparency
186 di.displayCandidates = True # show all the candidates and residuals
187 di.displayKernelBasis = False # show kernel basis functions
188 di.displayKernelMosaic = True # show kernel realized across the image
189 di.plotKernelSpatialModel = False # show coefficients of spatial model
190 di.showBadCandidates = True # show the bad candidates (red) along with good (green)
191 elif name == "lsst.ip.diffim.imagePsfMatch":
192 di.display = True # enable debug output
193 di.maskTransparency = 30 # ds9 mask transparency
194 di.displayTemplate = True # show full (remapped) template
195 di.displaySciIm = True # show science image to match to
196 di.displaySpatialCells = True # show spatial cells
197 di.displayDiffIm = True # show difference image
198 di.showBadCandidates = True # show the bad candidates (red) along with good (green)
199 elif name == "lsst.ip.diffim.diaCatalogSourceSelector":
200 di.display = False # enable debug output
201 di.maskTransparency = 30 # ds9 mask transparency
202 di.displayExposure = True # show exposure with candidates indicated
203 di.pauseAtEnd = False # pause when done
205 lsstDebug.Info = DebugInfo
209 Note that if you want addional logging info, you may add to your scripts:
211 import lsst.pex.logging as pexLog
212 pexLog.Trace_setVerbosity('lsst.ip.diffim', 5)
215 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
217 \section ip_diffim_imagepsfmatch_Example A complete example of using ImagePsfMatchTask
219 This code is imagePsfMatchTask.py in the examples directory, and can be run as \em e.g.
221 examples/imagePsfMatchTask.py --debug
222 examples/imagePsfMatchTask.py --debug --mode="matchExposures"
223 examples/imagePsfMatchTask.py --debug --template /path/to/templateExp.fits --science /path/to/scienceExp.fits
226 \dontinclude imagePsfMatchTask.py
227 Create a subclass of ImagePsfMatchTask that allows us to either match exposures, or subtract exposures:
228 \skip MyImagePsfMatchTask
229 \until self.subtractExposures
231 And allow the user the freedom to either run the script in default mode, or point to their own images on disk.
232 Note that these images must be readable as an lsst.afw.image.Exposure:
236 We have enabled some minor display debugging in this script via the --debug option. However, if you
237 have an lsstDebug debug.py in your PYTHONPATH you will get additional debugging displays. The following
238 block checks for this script:
242 \dontinclude imagePsfMatchTask.py
243 Finally, we call a run method that we define below. First set up a Config and modify some of the parameters.
244 E.g. use an "Alard-Lupton" sum-of-Gaussian basis, fit for a differential background, and use low order spatial
245 variation in the kernel and background:
247 \until spatialBgOrder
249 Make sure the images (if any) that were sent to the script exist on disk and are readable. If no images
250 are sent, make some fake data up for the sake of this example script (have a look at the code if you want
251 more details on generateFakeImages):
255 Create and run the Task:
259 And finally provide some optional debugging displays:
261 \until result.subtractedExposure
262 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
265 ConfigClass = ImagePsfMatchConfig
268 """!Create the ImagePsfMatchTask
270 \param *args arguments to be passed to lsst.ip.diffim.PsfMatchTask.__init__
271 \param **kwargs keyword arguments to be passed to lsst.ip.diffim.PsfMatchTask.__init__
273 Upon initialization, the kernel configuration is defined by self.config.kernel.active.
274 The task creates an lsst.afw.math.Warper from the subConfig self.config.kernel.active.warpingConfig.
275 A schema for the selection and measurement of candidate lsst.ip.diffim.KernelCandidates is
276 defined, and used to initize subTasks selectDetection (for candidate detection) and selectMeasurement
277 (for candidate measurement).
279 PsfMatchTask.__init__(self, *args, **kwargs)
281 self.
_warper = afwMath.Warper.fromConfig(self.kConfig.warpingConfig)
284 self.makeSubtask(
"selectDetection", schema=self.
selectSchema)
288 """!Return the FWHM in pixels of a Psf"""
289 sigPix = psf.computeShape().getDeterminantRadius()
290 return sigPix * sigma2fwhm
294 templateFwhmPix=
None, scienceFwhmPix=
None,
295 candidateList=
None, doWarping=
True, convolveTemplate=
True):
296 """!Warp and PSF-match an exposure to the reference
298 Do the following, in order:
299 - Warp templateExposure to match scienceExposure,
300 if doWarping True and their WCSs do not already match
301 - Determine a PSF matching kernel and differential background model
302 that matches templateExposure to scienceExposure
303 - Convolve templateExposure by PSF matching kernel
305 @param templateExposure: Exposure to warp and PSF-match to the reference masked image
306 @param scienceExposure: Exposure whose WCS and PSF are to be matched to
307 @param templateFwhmPix: FWHM (in pixels) of the Psf in the template image (image to convolve)
308 @param scienceFwhmPix: FWHM (in pixels) of the Psf in the science image
309 @param candidateList: a list of footprints/maskedImages for kernel candidates;
310 if None then source detection is run.
311 - Currently supported: list of Footprints or measAlg.PsfCandidateF
312 @param doWarping: what to do if templateExposure's and scienceExposure's WCSs do not match:
313 - if True then warp templateExposure to match scienceExposure
314 - if False then raise an Exception
315 @param convolveTemplate: convolve the template image or the science image
316 - if True, templateExposure is warped if doWarping, templateExposure is convolved
317 - if False, templateExposure is warped if doWarping, scienceExposure is convolved
319 @return a pipeBase.Struct containing these fields:
320 - matchedImage: the PSF-matched exposure =
321 warped templateExposure convolved by psfMatchingKernel. This has:
322 - the same parent bbox, Wcs and Calib as scienceExposure
323 - the same filter as templateExposure
324 - no Psf (because the PSF-matching process does not compute one)
325 - psfMatchingKernel: the PSF matching kernel
326 - backgroundModel: differential background model
327 - kernelCellSet: SpatialCellSet used to solve for the PSF matching kernel
329 Raise a RuntimeError if doWarping is False and templateExposure's and scienceExposure's
332 if not self.
_validateWcs(templateExposure, scienceExposure):
334 self.log.info(
"Astrometrically registering template to science image")
335 templatePsf = templateExposure.getPsf()
336 templateExposure = self._warper.warpExposure(scienceExposure.getWcs(),
337 templateExposure, destBBox=scienceExposure.getBBox())
338 templateExposure.setPsf(templatePsf)
340 pexLog.Trace(self.log.getName(), 1,
"ERROR: Input images not registered")
341 raise RuntimeError(
"Input images not registered")
342 if templateFwhmPix
is None:
343 if not templateExposure.hasPsf():
344 self.log.warn(
"No estimate of Psf FWHM for template image")
346 templateFwhmPix = self.
getFwhmPix(templateExposure.getPsf())
348 if scienceFwhmPix
is None:
349 if not scienceExposure.hasPsf():
350 self.log.warn(
"No estimate of Psf FWHM for science image")
352 scienceFwhmPix = self.
getFwhmPix(scienceExposure.getPsf())
356 candidateList = self.
makeCandidateList(templateExposure, scienceExposure, kernelSize, candidateList)
360 templateExposure.getMaskedImage(), scienceExposure.getMaskedImage(), candidateList,
361 templateFwhmPix=templateFwhmPix, scienceFwhmPix=scienceFwhmPix)
364 scienceExposure.getMaskedImage(), templateExposure.getMaskedImage(), candidateList,
365 templateFwhmPix=scienceFwhmPix, scienceFwhmPix=templateFwhmPix)
368 psfMatchedExposure.setFilter(templateExposure.getFilter())
369 psfMatchedExposure.setCalib(scienceExposure.getCalib())
370 results.warpedExposure = templateExposure
371 results.matchedExposure = psfMatchedExposure
375 def matchMaskedImages(self, templateMaskedImage, scienceMaskedImage, candidateList,
376 templateFwhmPix=
None, scienceFwhmPix=
None):
377 """!PSF-match a MaskedImage (templateMaskedImage) to a reference MaskedImage (scienceMaskedImage)
379 Do the following, in order:
380 - Determine a PSF matching kernel and differential background model
381 that matches templateMaskedImage to scienceMaskedImage
382 - Convolve templateMaskedImage by the PSF matching kernel
384 @param templateMaskedImage: masked image to PSF-match to the reference masked image;
385 must be warped to match the reference masked image
386 @param scienceMaskedImage: maskedImage whose PSF is to be matched to
387 @param templateFwhmPix: FWHM (in pixels) of the Psf in the template image (image to convolve)
388 @param scienceFwhmPix: FWHM (in pixels) of the Psf in the science image
389 @param candidateList: a list of footprints/maskedImages for kernel candidates;
390 if None then source detection is run.
391 - Currently supported: list of Footprints or measAlg.PsfCandidateF
393 @return a pipeBase.Struct containing these fields:
394 - psfMatchedMaskedImage: the PSF-matched masked image =
395 templateMaskedImage convolved with psfMatchingKernel.
396 This has the same xy0, dimensions and wcs as scienceMaskedImage.
397 - psfMatchingKernel: the PSF matching kernel
398 - backgroundModel: differential background model
399 - kernelCellSet: SpatialCellSet used to solve for the PSF matching kernel
401 Raise a RuntimeError if input images have different dimensions
408 displaySpatialCells =
lsstDebug.Info(__name__).displaySpatialCells
410 if not maskTransparency:
412 ds9.setMaskTransparency(maskTransparency)
414 if not candidateList:
415 raise RuntimeError(
"Candidate list must be populated by makeCandidateList")
417 if not self.
_validateSize(templateMaskedImage, scienceMaskedImage):
418 pexLog.Trace(self.log.getName(), 1,
"ERROR: Input images different size")
419 raise RuntimeError(
"Input images different size")
421 if display
and displayTemplate:
422 ds9.mtv(templateMaskedImage, frame=lsstDebug.frame, title=
"Image to convolve")
425 if display
and displaySciIm:
426 ds9.mtv(scienceMaskedImage, frame=lsstDebug.frame, title=
"Image to not convolve")
433 if display
and displaySpatialCells:
434 diUtils.showKernelSpatialCells(scienceMaskedImage, kernelCellSet,
435 symb=
"o", ctype=ds9.CYAN, ctypeUnused=ds9.YELLOW, ctypeBad=ds9.RED,
436 size=4, frame=lsstDebug.frame, title=
"Image to not convolve")
439 if templateFwhmPix
and scienceFwhmPix:
440 self.log.info(
"Matching Psf FWHM %.2f -> %.2f pix" % (templateFwhmPix, scienceFwhmPix))
442 if self.kConfig.useBicForKernelBasis:
447 bicDegrees = nbe(tmpKernelCellSet, self.log)
449 alardDegGauss=bicDegrees[0], metadata=self.metadata)
453 metadata=self.metadata)
455 spatialSolution, psfMatchingKernel, backgroundModel = self._solve(kernelCellSet, basisList)
460 psfMatchedMaskedImage = afwImage.MaskedImageF(templateMaskedImage.getBBox())
462 afwMath.convolve(psfMatchedMaskedImage, templateMaskedImage, psfMatchingKernel, doNormalize)
463 return pipeBase.Struct(
464 matchedImage=psfMatchedMaskedImage,
465 psfMatchingKernel=psfMatchingKernel,
466 backgroundModel=backgroundModel,
467 kernelCellSet=kernelCellSet,
472 templateFwhmPix=
None, scienceFwhmPix=
None,
473 candidateList=
None, doWarping=
True, convolveTemplate=
True):
474 """!Register, Psf-match and subtract two Exposures
476 Do the following, in order:
477 - Warp templateExposure to match scienceExposure, if their WCSs do not already match
478 - Determine a PSF matching kernel and differential background model
479 that matches templateExposure to scienceExposure
480 - PSF-match templateExposure to scienceExposure
481 - Compute subtracted exposure (see return values for equation).
483 @param templateExposure: exposure to PSF-match to scienceExposure
484 @param scienceExposure: reference Exposure
485 @param templateFwhmPix: FWHM (in pixels) of the Psf in the template image (image to convolve)
486 @param scienceFwhmPix: FWHM (in pixels) of the Psf in the science image
487 @param candidateList: a list of footprints/maskedImages for kernel candidates;
488 if None then source detection is run.
489 - Currently supported: list of Footprints or measAlg.PsfCandidateF
490 @param doWarping: what to do if templateExposure's and scienceExposure's WCSs do not match:
491 - if True then warp templateExposure to match scienceExposure
492 - if False then raise an Exception
493 @param convolveTemplate: convolve the template image or the science image
494 - if True, templateExposure is warped if doWarping, templateExposure is convolved
495 - if False, templateExposure is warped if doWarping, scienceExposure is convolved
497 @return a pipeBase.Struct containing these fields:
498 - subtractedExposure: subtracted Exposure = scienceExposure - (matchedImage + backgroundModel)
499 - matchedImage: templateExposure after warping to match templateExposure (if doWarping true),
500 and convolving with psfMatchingKernel
501 - psfMatchingKernel: PSF matching kernel
502 - backgroundModel: differential background model
503 - kernelCellSet: SpatialCellSet used to determine PSF matching kernel
506 templateExposure=templateExposure,
507 scienceExposure=scienceExposure,
508 templateFwhmPix=templateFwhmPix,
509 scienceFwhmPix=scienceFwhmPix,
510 candidateList=candidateList,
512 convolveTemplate=convolveTemplate
515 subtractedExposure = afwImage.ExposureF(scienceExposure,
True)
517 subtractedMaskedImage = subtractedExposure.getMaskedImage()
518 subtractedMaskedImage -= results.matchedExposure.getMaskedImage()
519 subtractedMaskedImage -= results.backgroundModel
521 subtractedExposure.setMaskedImage(results.warpedExposure.getMaskedImage())
522 subtractedMaskedImage = subtractedExposure.getMaskedImage()
523 subtractedMaskedImage -= results.matchedExposure.getMaskedImage()
524 subtractedMaskedImage -= results.backgroundModel
527 subtractedMaskedImage *= -1
530 subtractedMaskedImage /= results.psfMatchingKernel.computeImage(
531 afwImage.ImageD(results.psfMatchingKernel.getDimensions()),
False)
537 if not maskTransparency:
539 ds9.setMaskTransparency(maskTransparency)
540 if display
and displayDiffIm:
541 ds9.mtv(templateExposure, frame=lsstDebug.frame, title=
"Template")
543 ds9.mtv(results.matchedExposure, frame=lsstDebug.frame, title=
"Matched template")
545 ds9.mtv(scienceExposure, frame=lsstDebug.frame, title=
"Science Image")
547 ds9.mtv(subtractedExposure, frame=lsstDebug.frame, title=
"Difference Image")
550 results.subtractedExposure = subtractedExposure
555 templateFwhmPix=
None, scienceFwhmPix=
None):
556 """!Psf-match and subtract two MaskedImages
558 Do the following, in order:
559 - PSF-match templateMaskedImage to scienceMaskedImage
560 - Determine the differential background
561 - Return the difference: scienceMaskedImage -
562 ((warped templateMaskedImage convolved with psfMatchingKernel) + backgroundModel)
564 @param templateMaskedImage: MaskedImage to PSF-match to scienceMaskedImage
565 @param scienceMaskedImage: reference MaskedImage
566 @param templateFwhmPix: FWHM (in pixels) of the Psf in the template image (image to convolve)
567 @param scienceFwhmPix: FWHM (in pixels) of the Psf in the science image
568 @param candidateList: a list of footprints/maskedImages for kernel candidates;
569 if None then source detection is run.
570 - Currently supported: list of Footprints or measAlg.PsfCandidateF
572 @return a pipeBase.Struct containing these fields:
573 - subtractedMaskedImage = scienceMaskedImage - (matchedImage + backgroundModel)
574 - matchedImage: templateMaskedImage convolved with psfMatchingKernel
575 - psfMatchingKernel: PSF matching kernel
576 - backgroundModel: differential background model
577 - kernelCellSet: SpatialCellSet used to determine PSF matching kernel
579 if not candidateList:
580 raise RuntimeError(
"Candidate list must be populated by makeCandidateList")
583 templateMaskedImage=templateMaskedImage,
584 scienceMaskedImage=scienceMaskedImage,
585 candidateList=candidateList,
586 templateFwhmPix=templateFwhmPix,
587 scienceFwhmPix=scienceFwhmPix,
590 subtractedMaskedImage = afwImage.MaskedImageF(scienceMaskedImage,
True)
591 subtractedMaskedImage -= results.matchedImage
592 subtractedMaskedImage -= results.backgroundModel
593 results.subtractedMaskedImage = subtractedMaskedImage
599 if not maskTransparency:
601 ds9.setMaskTransparency(maskTransparency)
602 if display
and displayDiffIm:
603 ds9.mtv(subtractedMaskedImage, frame=lsstDebug.frame)
609 """!Get sources to use for Psf-matching
611 This method runs detection and measurement on an exposure.
612 The returned set of sources will be used as candidates for
615 @param exposure: Exposure on which to run detection/measurement
616 @param sigma: Detection threshold
617 @param doSmooth: Whether or not to smooth the Exposure with Psf before detection
618 @param idFactory: Factory for the generation of Source ids
620 @return source catalog containing candidates for the Psf-matching
624 table = afwTable.SourceTable.make(self.
selectSchema, idFactory)
627 mi = exposure.getMaskedImage()
629 imArr = mi.getImage().getArray()
630 maskArr = mi.getMask().getArray()
631 miArr = np.ma.masked_array(imArr, mask=maskArr)
633 bkgd =
getBackground(mi, self.kConfig.afwBackgroundConfig).getImageF()
635 self.log.warn(
"Failed to get background model. Falling back to median background estimation")
636 bkgd = np.ma.extras.median(miArr)
643 detRet = self.selectDetection.makeSourceCatalog(
649 selectSources = detRet.sources
650 self.selectMeasurement.run(measCat=selectSources, exposure=exposure)
658 """!Make a list of acceptable KernelCandidates
660 Accept or generate a list of candidate sources for
661 Psf-matching, and examine the Mask planes in both of the
662 images for indications of bad pixels
664 @param templateExposure: Exposure that will be convolved
665 @param scienceExposure: Exposure that will be matched-to
666 @param kernelSize: Dimensions of the Psf-matching Kernel, used to grow detection footprints
667 @param candidateList: List of Sources to examine
669 @return a list of dicts having a "source" and "footprint"
670 field for the Sources deemed to be appropriate for Psf
673 if candidateList
is None:
676 if len(candidateList) < 1:
677 raise RuntimeError(
"No candidates in candidateList")
679 listTypes = set(type(x)
for x
in candidateList)
681 raise RuntimeError(
"Can only make candidate list from set of SourceRecords. Got %s instead." \
682 % (type(candidateList[0])))
683 candidateList = diffimTools.sourceToFootprintList(candidateList,
684 templateExposure, scienceExposure,
686 self.kConfig.detectionConfig,
688 if len(candidateList) == 0:
689 raise RuntimeError(
"Cannot find any objects suitable for KernelCandidacy")
694 """! NOT IMPLEMENTED YET"""
695 return self.kConfig.sizeCellX, self.kConfig.sizeCellY
697 def _buildCellSet(self, templateMaskedImage, scienceMaskedImage, candidateList):
698 """!Build a SpatialCellSet for use with the solve method
700 @param templateMaskedImage: MaskedImage to PSF-matched to scienceMaskedImage
701 @param scienceMaskedImage: reference MaskedImage
702 @param candidateList: a list of footprints/maskedImages for kernel candidates;
703 if None then source detection is run.
704 - Currently supported: list of Footprints or measAlg.PsfCandidateF
706 @return kernelCellSet: a SpatialCellSet for use with self._solve
708 if not candidateList:
709 raise RuntimeError(
"Candidate list must be populated by makeCandidateList")
715 sizeCellX, sizeCellY)
717 policy = pexConfig.makePolicy(self.
kConfig)
719 for cand
in candidateList:
720 bbox = cand[
'footprint'].getBBox()
722 tmi = afwImage.MaskedImageF(templateMaskedImage, bbox)
723 smi = afwImage.MaskedImageF(scienceMaskedImage, bbox)
724 cand = diffimLib.makeKernelCandidate(cand[
'source'], tmi, smi, policy)
726 self.log.logdebug(
"Candidate %d at %f, %f" % (cand.getId(), cand.getXCenter(), cand.getYCenter()))
727 kernelCellSet.insertCandidate(cand)
732 """!Return True if two image-like objects are the same size
734 return templateMaskedImage.getDimensions() == scienceMaskedImage.getDimensions()
737 """!Return True if the WCS of the two Exposures have the same origin and extent
739 templateWcs = templateExposure.getWcs()
740 scienceWcs = scienceExposure.getWcs()
741 templateBBox = templateExposure.getBBox()
742 scienceBBox = scienceExposure.getBBox()
745 templateOrigin = templateWcs.pixelToSky(
afwGeom.Point2D(templateBBox.getBegin()))
746 scienceOrigin = scienceWcs.pixelToSky(
afwGeom.Point2D(scienceBBox.getBegin()))
749 templateLimit = templateWcs.pixelToSky(
afwGeom.Point2D(templateBBox.getEnd()))
750 scienceLimit = scienceWcs.pixelToSky(
afwGeom.Point2D(scienceBBox.getEnd()))
752 self.log.info(
"Template Wcs : %f,%f -> %f,%f" %
753 (templateOrigin[0], templateOrigin[1],
754 templateLimit[0], templateLimit[1]))
755 self.log.info(
"Science Wcs : %f,%f -> %f,%f" %
756 (scienceOrigin[0], scienceOrigin[1],
757 scienceLimit[0], scienceLimit[1]))
759 templateBBox =
afwGeom.Box2D(templateOrigin.getPosition(), templateLimit.getPosition())
760 scienceBBox =
afwGeom.Box2D(scienceOrigin.getPosition(), scienceLimit.getPosition())
761 if not (templateBBox.overlaps(scienceBBox)):
762 raise RuntimeError(
"Input images do not overlap at all")
764 if ( (templateOrigin.getPosition() != scienceOrigin.getPosition())
or
765 (templateLimit.getPosition() != scienceLimit.getPosition())
or
766 (templateExposure.getDimensions() != scienceExposure.getDimensions())):
def getFwhmPix
Return the FWHM in pixels of a Psf.
def getSelectSources
Get sources to use for Psf-matching.
def matchMaskedImages
PSF-match a MaskedImage (templateMaskedImage) to a reference MaskedImage (scienceMaskedImage) ...
Configuration for image-to-image Psf matching.
Class for storing ordered metadata with comments.
limited backward compatibility to the DC2 run-time trace facilities
def subtractMaskedImages
Psf-match and subtract two MaskedImages.
def makeCandidateList
Make a list of acceptable KernelCandidates.
Psf-match two MaskedImages or Exposures using the sources in the images.
def _validateSize
Return True if two image-like objects are the same size.
def _buildCellSet
Build a SpatialCellSet for use with the solve method.
A collection of SpatialCells covering an entire image.
def _validateWcs
Return True if the WCS of the two Exposures have the same origin and extent.
def subtractExposures
Register, Psf-match and subtract two Exposures.
def _adaptCellSize
NOT IMPLEMENTED YET.
Exposure< ImagePixelT, MaskPixelT, VariancePixelT >::Ptr makeExposure(MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > &mimage, boost::shared_ptr< Wcs const > wcs=boost::shared_ptr< Wcs const >())
Record class that contains measurements made on a single exposure.
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, bool doNormalize, bool doCopyEdge=false)
Old, deprecated version of convolve.
def getBackground
Estimate the background of an image (a thin layer on lsst.afw.math.makeBackground) ...
A floating-point coordinate rectangle geometry.
def matchExposures
Warp and PSF-match an exposure to the reference.
def __init__
Create the ImagePsfMatchTask.