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.doApplyApCorr =
"no"
67 self.selectMeasurement.algorithms.names.clear()
68 self.selectMeasurement.algorithms.names = (
'base_SdssCentroid',
'base_PsfFlux',
'base_PixelFlags',
69 'base_SdssShape',
'base_GaussianFlux',
'base_SkyCoord')
70 self.selectMeasurement.slots.modelFlux =
None
71 self.selectMeasurement.slots.apFlux =
None
72 self.selectMeasurement.slots.calibFlux =
None
83 \anchor ImagePsfMatchTask_
85 \brief Psf-match two MaskedImages or Exposures using the sources in the images
87 \section ip_diffim_imagepsfmatch_Contents Contents
89 - \ref ip_diffim_imagepsfmatch_Purpose
90 - \ref ip_diffim_imagepsfmatch_Initialize
91 - \ref ip_diffim_imagepsfmatch_IO
92 - \ref ip_diffim_imagepsfmatch_Config
93 - \ref ip_diffim_imagepsfmatch_Metadata
94 - \ref ip_diffim_imagepsfmatch_Debug
95 - \ref ip_diffim_imagepsfmatch_Example
97 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
99 \section ip_diffim_imagepsfmatch_Purpose Description
101 Build a Psf-matching kernel using two input images, either as MaskedImages (in which case they need
102 to be astrometrically aligned) or Exposures (in which case astrometric alignment will happen by
103 default but may be turned off). This requires a list of input Sources which may be provided
104 by the calling Task; if not, the Task will perform a coarse source detection and selection for this purpose.
105 Sources are vetted for signal-to-noise and masked pixels (in both the template and science image), and
106 substamps around each acceptable source are extracted and used to create an instance of KernelCandidate.
107 Each KernelCandidate is then placed within a lsst.afw.math.SpatialCellSet, which is used by an ensemble of
108 lsst.afw.math.CandidateVisitor instances to build the Psf-matching kernel. These visitors include, in
109 the order that they are called: BuildSingleKernelVisitor, KernelSumVisitor, BuildSpatialKernelVisitor,
110 and AssessSpatialKernelVisitor.
112 Sigma clipping of KernelCandidates is performed as follows:
113 - BuildSingleKernelVisitor, using the substamp diffim residuals from the per-source kernel fit,
114 if PsfMatchConfig.singleKernelClipping is True
115 - KernelSumVisitor, using the mean and standard deviation of the kernel sum from all candidates,
116 if PsfMatchConfig.kernelSumClipping is True
117 - AssessSpatialKernelVisitor, using the substamp diffim ressiduals from the spatial kernel fit,
118 if PsfMatchConfig.spatialKernelClipping is True
120 The actual solving for the kernel (and differential background model) happens in
121 lsst.ip.diffim.PsfMatchTask._solve. This involves a loop over the SpatialCellSet that first builds the
122 per-candidate matching kernel for the requested number of KernelCandidates per cell
123 (PsfMatchConfig.nStarPerCell). The quality of this initial per-candidate difference image is examined,
124 using moments of the pixel residuals in the difference image normalized by the square root of the variance
125 (i.e. sigma); ideally this should follow a normal (0, 1) distribution, but the rejection thresholds are set
126 by the config (PsfMatchConfig.candidateResidualMeanMax and PsfMatchConfig.candidateResidualStdMax).
127 All candidates that pass this initial build are then examined en masse to find the
128 mean/stdev of the kernel sums across all candidates. Objects that are significantly above or below the mean,
129 typically due to variability or sources that are saturated in one image but not the other, are also rejected.
130 This threshold is defined by PsfMatchConfig.maxKsumSigma. Finally, a spatial model is built using all
131 currently-acceptable candidates, and the spatial model used to derive a second set of (spatial) residuals
132 which are again used to reject bad candidates, using the same thresholds as above.
134 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
136 \section ip_diffim_imagepsfmatch_Initialize Task initialization
138 \copydoc \_\_init\_\_
140 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
142 \section ip_diffim_imagepsfmatch_IO Invoking the Task
144 There is no run() method for this Task. Instead there are 4 methods that
145 may be used to invoke the Psf-matching. These are
146 \link lsst.ip.diffim.imagePsfMatch.ImagePsfMatchTask.matchMaskedImages matchMaskedImages\endlink,
147 \link lsst.ip.diffim.imagePsfMatch.ImagePsfMatchTask.subtractMaskedImages subtractMaskedImages\endlink,
148 \link lsst.ip.diffim.imagePsfMatch.ImagePsfMatchTask.matchExposures matchExposures\endlink, and
149 \link lsst.ip.diffim.imagePsfMatch.ImagePsfMatchTask.subtractExposures subtractExposures\endlink.
151 The methods that operate on lsst.afw.image.MaskedImage require that the images already be astrometrically
152 aligned, and are the same shape. The methods that operate on lsst.afw.image.Exposure allow for the
153 input images to be misregistered and potentially be different sizes; by default a
154 lsst.afw.math.LanczosWarpingKernel is used to perform the astrometric alignment. The methods
155 that "match" images return a Psf-matched image, while the methods that "subtract" images
156 return a Psf-matched and template subtracted image.
158 See each method's returned lsst.pipe.base.Struct for more details.
160 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
162 \section ip_diffim_imagepsfmatch_Config Configuration parameters
164 See \ref ImagePsfMatchConfig
166 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
168 \section ip_diffim_imagepsfmatch_Metadata Quantities set in Metadata
170 See \ref ip_diffim_psfmatch_Metadata "PsfMatchTask"
172 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
174 \section ip_diffim_imagepsfmatch_Debug Debug variables
176 The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a
177 flag \c -d/--debug to import \b debug.py from your \c PYTHONPATH. The relevant contents of debug.py
178 for this Task include:
184 di = lsstDebug.getInfo(name)
185 if name == "lsst.ip.diffim.psfMatch":
186 di.display = True # enable debug output
187 di.maskTransparency = 80 # ds9 mask transparency
188 di.displayCandidates = True # show all the candidates and residuals
189 di.displayKernelBasis = False # show kernel basis functions
190 di.displayKernelMosaic = True # show kernel realized across the image
191 di.plotKernelSpatialModel = False # show coefficients of spatial model
192 di.showBadCandidates = True # show the bad candidates (red) along with good (green)
193 elif name == "lsst.ip.diffim.imagePsfMatch":
194 di.display = True # enable debug output
195 di.maskTransparency = 30 # ds9 mask transparency
196 di.displayTemplate = True # show full (remapped) template
197 di.displaySciIm = True # show science image to match to
198 di.displaySpatialCells = True # show spatial cells
199 di.displayDiffIm = True # show difference image
200 di.showBadCandidates = True # show the bad candidates (red) along with good (green)
201 elif name == "lsst.ip.diffim.diaCatalogSourceSelector":
202 di.display = False # enable debug output
203 di.maskTransparency = 30 # ds9 mask transparency
204 di.displayExposure = True # show exposure with candidates indicated
205 di.pauseAtEnd = False # pause when done
207 lsstDebug.Info = DebugInfo
211 Note that if you want addional logging info, you may add to your scripts:
213 import lsst.pex.logging as pexLog
214 pexLog.Trace_setVerbosity('lsst.ip.diffim', 5)
217 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
219 \section ip_diffim_imagepsfmatch_Example A complete example of using ImagePsfMatchTask
221 This code is imagePsfMatchTask.py in the examples directory, and can be run as \em e.g.
223 examples/imagePsfMatchTask.py --debug
224 examples/imagePsfMatchTask.py --debug --mode="matchExposures"
225 examples/imagePsfMatchTask.py --debug --template /path/to/templateExp.fits --science /path/to/scienceExp.fits
228 \dontinclude imagePsfMatchTask.py
229 Create a subclass of ImagePsfMatchTask that allows us to either match exposures, or subtract exposures:
230 \skip MyImagePsfMatchTask
231 \until self.subtractExposures
233 And allow the user the freedom to either run the script in default mode, or point to their own images on disk.
234 Note that these images must be readable as an lsst.afw.image.Exposure:
238 We have enabled some minor display debugging in this script via the --debug option. However, if you
239 have an lsstDebug debug.py in your PYTHONPATH you will get additional debugging displays. The following
240 block checks for this script:
244 \dontinclude imagePsfMatchTask.py
245 Finally, we call a run method that we define below. First set up a Config and modify some of the parameters.
246 E.g. use an "Alard-Lupton" sum-of-Gaussian basis, fit for a differential background, and use low order spatial
247 variation in the kernel and background:
249 \until spatialBgOrder
251 Make sure the images (if any) that were sent to the script exist on disk and are readable. If no images
252 are sent, make some fake data up for the sake of this example script (have a look at the code if you want
253 more details on generateFakeImages):
257 Create and run the Task:
261 And finally provide some optional debugging displays:
263 \until result.subtractedExposure
264 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
267 ConfigClass = ImagePsfMatchConfig
270 """!Create the ImagePsfMatchTask
272 \param *args arguments to be passed to lsst.ip.diffim.PsfMatchTask.__init__
273 \param **kwargs keyword arguments to be passed to lsst.ip.diffim.PsfMatchTask.__init__
275 Upon initialization, the kernel configuration is defined by self.config.kernel.active.
276 The task creates an lsst.afw.math.Warper from the subConfig self.config.kernel.active.warpingConfig.
277 A schema for the selection and measurement of candidate lsst.ip.diffim.KernelCandidates is
278 defined, and used to initize subTasks selectDetection (for candidate detection) and selectMeasurement
279 (for candidate measurement).
281 PsfMatchTask.__init__(self, *args, **kwargs)
283 self.
_warper = afwMath.Warper.fromConfig(self.kConfig.warpingConfig)
286 self.makeSubtask(
"selectDetection", schema=self.
selectSchema)
290 """!Return the FWHM in pixels of a Psf"""
291 sigPix = psf.computeShape().getDeterminantRadius()
292 return sigPix * sigma2fwhm
296 templateFwhmPix=
None, scienceFwhmPix=
None,
297 candidateList=
None, doWarping=
True, convolveTemplate=
True):
298 """!Warp and PSF-match an exposure to the reference
300 Do the following, in order:
301 - Warp templateExposure to match scienceExposure,
302 if doWarping True and their WCSs do not already match
303 - Determine a PSF matching kernel and differential background model
304 that matches templateExposure to scienceExposure
305 - Convolve templateExposure by PSF matching kernel
307 @param templateExposure: Exposure to warp and PSF-match to the reference masked image
308 @param scienceExposure: Exposure whose WCS and PSF are to be matched to
309 @param templateFwhmPix: FWHM (in pixels) of the Psf in the template image (image to convolve)
310 @param scienceFwhmPix: FWHM (in pixels) of the Psf in the science image
311 @param candidateList: a list of footprints/maskedImages for kernel candidates;
312 if None then source detection is run.
313 - Currently supported: list of Footprints or measAlg.PsfCandidateF
314 @param doWarping: what to do if templateExposure's and scienceExposure's WCSs do not match:
315 - if True then warp templateExposure to match scienceExposure
316 - if False then raise an Exception
317 @param convolveTemplate: convolve the template image or the science image
318 - if True, templateExposure is warped if doWarping, templateExposure is convolved
319 - if False, templateExposure is warped if doWarping, scienceExposure is convolved
321 @return a pipeBase.Struct containing these fields:
322 - matchedImage: the PSF-matched exposure =
323 warped templateExposure convolved by psfMatchingKernel. This has:
324 - the same parent bbox, Wcs and Calib as scienceExposure
325 - the same filter as templateExposure
326 - no Psf (because the PSF-matching process does not compute one)
327 - psfMatchingKernel: the PSF matching kernel
328 - backgroundModel: differential background model
329 - kernelCellSet: SpatialCellSet used to solve for the PSF matching kernel
331 Raise a RuntimeError if doWarping is False and templateExposure's and scienceExposure's
334 if not self.
_validateWcs(templateExposure, scienceExposure):
336 self.log.info(
"Astrometrically registering template to science image")
337 templatePsf = templateExposure.getPsf()
338 templateExposure = self._warper.warpExposure(scienceExposure.getWcs(),
339 templateExposure, destBBox=scienceExposure.getBBox())
340 templateExposure.setPsf(templatePsf)
342 pexLog.Trace(self.log.getName(), 1,
"ERROR: Input images not registered")
343 raise RuntimeError(
"Input images not registered")
344 if templateFwhmPix
is None:
345 if not templateExposure.hasPsf():
346 self.log.warn(
"No estimate of Psf FWHM for template image")
348 templateFwhmPix = self.
getFwhmPix(templateExposure.getPsf())
350 if scienceFwhmPix
is None:
351 if not scienceExposure.hasPsf():
352 self.log.warn(
"No estimate of Psf FWHM for science image")
354 scienceFwhmPix = self.
getFwhmPix(scienceExposure.getPsf())
358 candidateList = self.
makeCandidateList(templateExposure, scienceExposure, kernelSize, candidateList)
362 templateExposure.getMaskedImage(), scienceExposure.getMaskedImage(), candidateList,
363 templateFwhmPix=templateFwhmPix, scienceFwhmPix=scienceFwhmPix)
366 scienceExposure.getMaskedImage(), templateExposure.getMaskedImage(), candidateList,
367 templateFwhmPix=scienceFwhmPix, scienceFwhmPix=templateFwhmPix)
370 psfMatchedExposure.setFilter(templateExposure.getFilter())
371 psfMatchedExposure.setCalib(scienceExposure.getCalib())
372 results.warpedExposure = templateExposure
373 results.matchedExposure = psfMatchedExposure
377 def matchMaskedImages(self, templateMaskedImage, scienceMaskedImage, candidateList,
378 templateFwhmPix=
None, scienceFwhmPix=
None):
379 """!PSF-match a MaskedImage (templateMaskedImage) to a reference MaskedImage (scienceMaskedImage)
381 Do the following, in order:
382 - Determine a PSF matching kernel and differential background model
383 that matches templateMaskedImage to scienceMaskedImage
384 - Convolve templateMaskedImage by the PSF matching kernel
386 @param templateMaskedImage: masked image to PSF-match to the reference masked image;
387 must be warped to match the reference masked image
388 @param scienceMaskedImage: maskedImage whose PSF is to be matched to
389 @param templateFwhmPix: FWHM (in pixels) of the Psf in the template image (image to convolve)
390 @param scienceFwhmPix: FWHM (in pixels) of the Psf in the science image
391 @param candidateList: a list of footprints/maskedImages for kernel candidates;
392 if None then source detection is run.
393 - Currently supported: list of Footprints or measAlg.PsfCandidateF
395 @return a pipeBase.Struct containing these fields:
396 - psfMatchedMaskedImage: the PSF-matched masked image =
397 templateMaskedImage convolved with psfMatchingKernel.
398 This has the same xy0, dimensions and wcs as scienceMaskedImage.
399 - psfMatchingKernel: the PSF matching kernel
400 - backgroundModel: differential background model
401 - kernelCellSet: SpatialCellSet used to solve for the PSF matching kernel
403 Raise a RuntimeError if input images have different dimensions
410 displaySpatialCells =
lsstDebug.Info(__name__).displaySpatialCells
412 if not maskTransparency:
415 ds9.setMaskTransparency(maskTransparency)
417 if not candidateList:
418 raise RuntimeError(
"Candidate list must be populated by makeCandidateList")
420 if not self.
_validateSize(templateMaskedImage, scienceMaskedImage):
421 pexLog.Trace(self.log.getName(), 1,
"ERROR: Input images different size")
422 raise RuntimeError(
"Input images different size")
424 if display
and displayTemplate:
425 ds9.mtv(templateMaskedImage, frame=lsstDebug.frame, title=
"Image to convolve")
428 if display
and displaySciIm:
429 ds9.mtv(scienceMaskedImage, frame=lsstDebug.frame, title=
"Image to not convolve")
436 if display
and displaySpatialCells:
437 diUtils.showKernelSpatialCells(scienceMaskedImage, kernelCellSet,
438 symb=
"o", ctype=ds9.CYAN, ctypeUnused=ds9.YELLOW, ctypeBad=ds9.RED,
439 size=4, frame=lsstDebug.frame, title=
"Image to not convolve")
442 if templateFwhmPix
and scienceFwhmPix:
443 self.log.info(
"Matching Psf FWHM %.2f -> %.2f pix" % (templateFwhmPix, scienceFwhmPix))
445 if self.kConfig.useBicForKernelBasis:
450 bicDegrees = nbe(tmpKernelCellSet, self.log)
452 alardDegGauss=bicDegrees[0], metadata=self.metadata)
456 metadata=self.metadata)
458 spatialSolution, psfMatchingKernel, backgroundModel = self._solve(kernelCellSet, basisList)
463 psfMatchedMaskedImage = afwImage.MaskedImageF(templateMaskedImage.getBBox())
465 afwMath.convolve(psfMatchedMaskedImage, templateMaskedImage, psfMatchingKernel, doNormalize)
466 return pipeBase.Struct(
467 matchedImage=psfMatchedMaskedImage,
468 psfMatchingKernel=psfMatchingKernel,
469 backgroundModel=backgroundModel,
470 kernelCellSet=kernelCellSet,
475 templateFwhmPix=
None, scienceFwhmPix=
None,
476 candidateList=
None, doWarping=
True, convolveTemplate=
True):
477 """!Register, Psf-match and subtract two Exposures
479 Do the following, in order:
480 - Warp templateExposure to match scienceExposure, if their WCSs do not already match
481 - Determine a PSF matching kernel and differential background model
482 that matches templateExposure to scienceExposure
483 - PSF-match templateExposure to scienceExposure
484 - Compute subtracted exposure (see return values for equation).
486 @param templateExposure: exposure to PSF-match to scienceExposure
487 @param scienceExposure: reference Exposure
488 @param templateFwhmPix: FWHM (in pixels) of the Psf in the template image (image to convolve)
489 @param scienceFwhmPix: FWHM (in pixels) of the Psf in the science image
490 @param candidateList: a list of footprints/maskedImages for kernel candidates;
491 if None then source detection is run.
492 - Currently supported: list of Footprints or measAlg.PsfCandidateF
493 @param doWarping: what to do if templateExposure's and scienceExposure's WCSs do not match:
494 - if True then warp templateExposure to match scienceExposure
495 - if False then raise an Exception
496 @param convolveTemplate: convolve the template image or the science image
497 - if True, templateExposure is warped if doWarping, templateExposure is convolved
498 - if False, templateExposure is warped if doWarping, scienceExposure is convolved
500 @return a pipeBase.Struct containing these fields:
501 - subtractedExposure: subtracted Exposure = scienceExposure - (matchedImage + backgroundModel)
502 - matchedImage: templateExposure after warping to match templateExposure (if doWarping true),
503 and convolving with psfMatchingKernel
504 - psfMatchingKernel: PSF matching kernel
505 - backgroundModel: differential background model
506 - kernelCellSet: SpatialCellSet used to determine PSF matching kernel
509 templateExposure=templateExposure,
510 scienceExposure=scienceExposure,
511 templateFwhmPix=templateFwhmPix,
512 scienceFwhmPix=scienceFwhmPix,
513 candidateList=candidateList,
515 convolveTemplate=convolveTemplate
518 subtractedExposure = afwImage.ExposureF(scienceExposure,
True)
520 subtractedMaskedImage = subtractedExposure.getMaskedImage()
521 subtractedMaskedImage -= results.matchedExposure.getMaskedImage()
522 subtractedMaskedImage -= results.backgroundModel
524 subtractedExposure.setMaskedImage(results.warpedExposure.getMaskedImage())
525 subtractedMaskedImage = subtractedExposure.getMaskedImage()
526 subtractedMaskedImage -= results.matchedExposure.getMaskedImage()
527 subtractedMaskedImage -= results.backgroundModel
530 subtractedMaskedImage *= -1
533 subtractedMaskedImage /= results.psfMatchingKernel.computeImage(
534 afwImage.ImageD(results.psfMatchingKernel.getDimensions()),
False)
540 if not maskTransparency:
543 ds9.setMaskTransparency(maskTransparency)
544 if display
and displayDiffIm:
545 ds9.mtv(templateExposure, frame=lsstDebug.frame, title=
"Template")
547 ds9.mtv(results.matchedExposure, frame=lsstDebug.frame, title=
"Matched template")
549 ds9.mtv(scienceExposure, frame=lsstDebug.frame, title=
"Science Image")
551 ds9.mtv(subtractedExposure, frame=lsstDebug.frame, title=
"Difference Image")
554 results.subtractedExposure = subtractedExposure
559 templateFwhmPix=
None, scienceFwhmPix=
None):
560 """!Psf-match and subtract two MaskedImages
562 Do the following, in order:
563 - PSF-match templateMaskedImage to scienceMaskedImage
564 - Determine the differential background
565 - Return the difference: scienceMaskedImage -
566 ((warped templateMaskedImage convolved with psfMatchingKernel) + backgroundModel)
568 @param templateMaskedImage: MaskedImage to PSF-match to scienceMaskedImage
569 @param scienceMaskedImage: reference MaskedImage
570 @param templateFwhmPix: FWHM (in pixels) of the Psf in the template image (image to convolve)
571 @param scienceFwhmPix: FWHM (in pixels) of the Psf in the science image
572 @param candidateList: a list of footprints/maskedImages for kernel candidates;
573 if None then source detection is run.
574 - Currently supported: list of Footprints or measAlg.PsfCandidateF
576 @return a pipeBase.Struct containing these fields:
577 - subtractedMaskedImage = scienceMaskedImage - (matchedImage + backgroundModel)
578 - matchedImage: templateMaskedImage convolved with psfMatchingKernel
579 - psfMatchingKernel: PSF matching kernel
580 - backgroundModel: differential background model
581 - kernelCellSet: SpatialCellSet used to determine PSF matching kernel
583 if not candidateList:
584 raise RuntimeError(
"Candidate list must be populated by makeCandidateList")
587 templateMaskedImage=templateMaskedImage,
588 scienceMaskedImage=scienceMaskedImage,
589 candidateList=candidateList,
590 templateFwhmPix=templateFwhmPix,
591 scienceFwhmPix=scienceFwhmPix,
594 subtractedMaskedImage = afwImage.MaskedImageF(scienceMaskedImage,
True)
595 subtractedMaskedImage -= results.matchedImage
596 subtractedMaskedImage -= results.backgroundModel
597 results.subtractedMaskedImage = subtractedMaskedImage
603 if not maskTransparency:
606 ds9.setMaskTransparency(maskTransparency)
607 if display
and displayDiffIm:
608 ds9.mtv(subtractedMaskedImage, frame=lsstDebug.frame)
614 """!Get sources to use for Psf-matching
616 This method runs detection and measurement on an exposure.
617 The returned set of sources will be used as candidates for
620 @param exposure: Exposure on which to run detection/measurement
621 @param sigma: Detection threshold
622 @param doSmooth: Whether or not to smooth the Exposure with Psf before detection
623 @param idFactory: Factory for the generation of Source ids
625 @return source catalog containing candidates for the Psf-matching
629 table = afwTable.SourceTable.make(self.
selectSchema, idFactory)
632 mi = exposure.getMaskedImage()
634 imArr = mi.getImage().getArray()
635 maskArr = mi.getMask().getArray()
636 miArr = np.ma.masked_array(imArr, mask=maskArr)
638 bkgd =
getBackground(mi, self.kConfig.afwBackgroundConfig).getImageF()
640 self.log.warn(
"Failed to get background model. Falling back to median background estimation")
641 bkgd = np.ma.extras.median(miArr)
648 detRet = self.selectDetection.makeSourceCatalog(
654 selectSources = detRet.sources
655 self.selectMeasurement.run(measCat=selectSources, exposure=exposure)
663 """!Make a list of acceptable KernelCandidates
665 Accept or generate a list of candidate sources for
666 Psf-matching, and examine the Mask planes in both of the
667 images for indications of bad pixels
669 @param templateExposure: Exposure that will be convolved
670 @param scienceExposure: Exposure that will be matched-to
671 @param kernelSize: Dimensions of the Psf-matching Kernel, used to grow detection footprints
672 @param candidateList: List of Sources to examine
674 @return a list of dicts having a "source" and "footprint"
675 field for the Sources deemed to be appropriate for Psf
678 if candidateList
is None:
681 if len(candidateList) < 1:
682 raise RuntimeError(
"No candidates in candidateList")
684 listTypes = set(type(x)
for x
in candidateList)
686 raise RuntimeError(
"Can only make candidate list from set of SourceRecords. Got %s instead." \
687 % (type(candidateList[0])))
688 candidateList = diffimTools.sourceToFootprintList(candidateList,
689 templateExposure, scienceExposure,
691 self.kConfig.detectionConfig,
693 if len(candidateList) == 0:
694 raise RuntimeError(
"Cannot find any objects suitable for KernelCandidacy")
699 """! NOT IMPLEMENTED YET"""
700 return self.kConfig.sizeCellX, self.kConfig.sizeCellY
702 def _buildCellSet(self, templateMaskedImage, scienceMaskedImage, candidateList):
703 """!Build a SpatialCellSet for use with the solve method
705 @param templateMaskedImage: MaskedImage to PSF-matched to scienceMaskedImage
706 @param scienceMaskedImage: reference MaskedImage
707 @param candidateList: a list of footprints/maskedImages for kernel candidates;
708 if None then source detection is run.
709 - Currently supported: list of Footprints or measAlg.PsfCandidateF
711 @return kernelCellSet: a SpatialCellSet for use with self._solve
713 if not candidateList:
714 raise RuntimeError(
"Candidate list must be populated by makeCandidateList")
720 sizeCellX, sizeCellY)
722 policy = pexConfig.makePolicy(self.
kConfig)
724 for cand
in candidateList:
725 bbox = cand[
'footprint'].getBBox()
727 tmi = afwImage.MaskedImageF(templateMaskedImage, bbox)
728 smi = afwImage.MaskedImageF(scienceMaskedImage, bbox)
729 cand = diffimLib.makeKernelCandidate(cand[
'source'], tmi, smi, policy)
731 self.log.logdebug(
"Candidate %d at %f, %f" % (cand.getId(), cand.getXCenter(), cand.getYCenter()))
732 kernelCellSet.insertCandidate(cand)
737 """!Return True if two image-like objects are the same size
739 return templateMaskedImage.getDimensions() == scienceMaskedImage.getDimensions()
742 """!Return True if the WCS of the two Exposures have the same origin and extent
744 templateWcs = templateExposure.getWcs()
745 scienceWcs = scienceExposure.getWcs()
746 templateBBox = templateExposure.getBBox()
747 scienceBBox = scienceExposure.getBBox()
750 templateOrigin = templateWcs.pixelToSky(
afwGeom.Point2D(templateBBox.getBegin()))
751 scienceOrigin = scienceWcs.pixelToSky(
afwGeom.Point2D(scienceBBox.getBegin()))
754 templateLimit = templateWcs.pixelToSky(
afwGeom.Point2D(templateBBox.getEnd()))
755 scienceLimit = scienceWcs.pixelToSky(
afwGeom.Point2D(scienceBBox.getEnd()))
757 self.log.info(
"Template Wcs : %f,%f -> %f,%f" %
758 (templateOrigin[0], templateOrigin[1],
759 templateLimit[0], templateLimit[1]))
760 self.log.info(
"Science Wcs : %f,%f -> %f,%f" %
761 (scienceOrigin[0], scienceOrigin[1],
762 scienceLimit[0], scienceLimit[1]))
764 templateBBox =
afwGeom.Box2D(templateOrigin.getPosition(), templateLimit.getPosition())
765 scienceBBox =
afwGeom.Box2D(scienceOrigin.getPosition(), scienceLimit.getPosition())
766 if not (templateBBox.overlaps(scienceBBox)):
767 raise RuntimeError(
"Input images do not overlap at all")
769 if ( (templateOrigin.getPosition() != scienceOrigin.getPosition())
or
770 (templateLimit.getPosition() != scienceLimit.getPosition())
or
771 (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.