31 from .makeKernelBasisList
import makeKernelBasisList
32 from .psfMatch
import PsfMatchTask, PsfMatchConfigDF, PsfMatchConfigAL
33 from .
import utils
as diUtils
34 from .
import diffimLib
35 from .
import diffimTools
38 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
71 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.log.utils as logUtils
214 logUtils.traceSetAt("ip.diffim", 4)
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.
background = SubtractBackgroundTask(config=self.kConfig.afwBackgroundConfig, name=
"background",
290 self.makeSubtask(
"selectDetection", schema=self.
selectSchema)
294 """!Return the FWHM in pixels of a Psf"""
295 sigPix = psf.computeShape().getDeterminantRadius()
296 return sigPix * sigma2fwhm
300 templateFwhmPix=
None, scienceFwhmPix=
None,
301 candidateList=
None, doWarping=
True, convolveTemplate=
True):
302 """!Warp and PSF-match an exposure to the reference
304 Do the following, in order:
305 - Warp templateExposure to match scienceExposure,
306 if doWarping True and their WCSs do not already match
307 - Determine a PSF matching kernel and differential background model
308 that matches templateExposure to scienceExposure
309 - Convolve templateExposure by PSF matching kernel
311 @param templateExposure: Exposure to warp and PSF-match to the reference masked image
312 @param scienceExposure: Exposure whose WCS and PSF are to be matched to
313 @param templateFwhmPix: FWHM (in pixels) of the Psf in the template image (image to convolve)
314 @param scienceFwhmPix: FWHM (in pixels) of the Psf in the science image
315 @param candidateList: a list of footprints/maskedImages for kernel candidates;
316 if None then source detection is run.
317 - Currently supported: list of Footprints or measAlg.PsfCandidateF
318 @param doWarping: what to do if templateExposure's and scienceExposure's WCSs do not match:
319 - if True then warp templateExposure to match scienceExposure
320 - if False then raise an Exception
321 @param convolveTemplate: convolve the template image or the science image
322 - if True, templateExposure is warped if doWarping, templateExposure is convolved
323 - if False, templateExposure is warped if doWarping, scienceExposure is convolved
325 @return a pipeBase.Struct containing these fields:
326 - matchedImage: the PSF-matched exposure =
327 warped templateExposure convolved by psfMatchingKernel. This has:
328 - the same parent bbox, Wcs and Calib as scienceExposure
329 - the same filter as templateExposure
330 - no Psf (because the PSF-matching process does not compute one)
331 - psfMatchingKernel: the PSF matching kernel
332 - backgroundModel: differential background model
333 - kernelCellSet: SpatialCellSet used to solve for the PSF matching kernel
335 Raise a RuntimeError if doWarping is False and templateExposure's and scienceExposure's
338 if not self.
_validateWcs(templateExposure, scienceExposure):
340 self.log.info(
"Astrometrically registering template to science image")
341 templatePsf = templateExposure.getPsf()
342 templateExposure = self._warper.warpExposure(scienceExposure.getWcs(),
343 templateExposure, destBBox=scienceExposure.getBBox())
344 templateExposure.setPsf(templatePsf)
346 self.log.error(
"ERROR: Input images not registered")
347 raise RuntimeError(
"Input images not registered")
349 if templateFwhmPix
is None:
350 if not templateExposure.hasPsf():
351 self.log.warn(
"No estimate of Psf FWHM for template image")
353 templateFwhmPix = self.
getFwhmPix(templateExposure.getPsf())
354 self.log.info(
"templateFwhmPix: {}".
format(templateFwhmPix))
356 if scienceFwhmPix
is None:
357 if not scienceExposure.hasPsf():
358 self.log.warn(
"No estimate of Psf FWHM for science image")
360 scienceFwhmPix = self.
getFwhmPix(scienceExposure.getPsf())
361 self.log.info(
"scienceFwhmPix: {}".
format(scienceFwhmPix))
364 candidateList = self.
makeCandidateList(templateExposure, scienceExposure, kernelSize, candidateList)
368 templateExposure.getMaskedImage(), scienceExposure.getMaskedImage(), candidateList,
369 templateFwhmPix=templateFwhmPix, scienceFwhmPix=scienceFwhmPix)
372 scienceExposure.getMaskedImage(), templateExposure.getMaskedImage(), candidateList,
373 templateFwhmPix=scienceFwhmPix, scienceFwhmPix=templateFwhmPix)
376 psfMatchedExposure.setFilter(templateExposure.getFilter())
377 psfMatchedExposure.setCalib(scienceExposure.getCalib())
378 results.warpedExposure = templateExposure
379 results.matchedExposure = psfMatchedExposure
383 def matchMaskedImages(self, templateMaskedImage, scienceMaskedImage, candidateList,
384 templateFwhmPix=
None, scienceFwhmPix=
None):
385 """!PSF-match a MaskedImage (templateMaskedImage) to a reference MaskedImage (scienceMaskedImage)
387 Do the following, in order:
388 - Determine a PSF matching kernel and differential background model
389 that matches templateMaskedImage to scienceMaskedImage
390 - Convolve templateMaskedImage by the PSF matching kernel
392 @param templateMaskedImage: masked image to PSF-match to the reference masked image;
393 must be warped to match the reference masked image
394 @param scienceMaskedImage: maskedImage whose PSF is to be matched to
395 @param templateFwhmPix: FWHM (in pixels) of the Psf in the template image (image to convolve)
396 @param scienceFwhmPix: FWHM (in pixels) of the Psf in the science image
397 @param candidateList: a list of footprints/maskedImages for kernel candidates;
398 if None then source detection is run.
399 - Currently supported: list of Footprints or measAlg.PsfCandidateF
401 @return a pipeBase.Struct containing these fields:
402 - psfMatchedMaskedImage: the PSF-matched masked image =
403 templateMaskedImage convolved with psfMatchingKernel.
404 This has the same xy0, dimensions and wcs as scienceMaskedImage.
405 - psfMatchingKernel: the PSF matching kernel
406 - backgroundModel: differential background model
407 - kernelCellSet: SpatialCellSet used to solve for the PSF matching kernel
409 Raise a RuntimeError if input images have different dimensions
416 displaySpatialCells =
lsstDebug.Info(__name__).displaySpatialCells
418 if not maskTransparency:
421 ds9.setMaskTransparency(maskTransparency)
423 if not candidateList:
424 raise RuntimeError(
"Candidate list must be populated by makeCandidateList")
426 if not self.
_validateSize(templateMaskedImage, scienceMaskedImage):
427 self.log.error(
"ERROR: Input images different size")
428 raise RuntimeError(
"Input images different size")
430 if display
and displayTemplate:
431 ds9.mtv(templateMaskedImage, frame=lsstDebug.frame, title=
"Image to convolve")
434 if display
and displaySciIm:
435 ds9.mtv(scienceMaskedImage, frame=lsstDebug.frame, title=
"Image to not convolve")
442 if display
and displaySpatialCells:
443 diUtils.showKernelSpatialCells(scienceMaskedImage, kernelCellSet,
444 symb=
"o", ctype=ds9.CYAN, ctypeUnused=ds9.YELLOW, ctypeBad=ds9.RED,
445 size=4, frame=lsstDebug.frame, title=
"Image to not convolve")
448 if templateFwhmPix
and scienceFwhmPix:
449 self.log.info(
"Matching Psf FWHM %.2f -> %.2f pix", templateFwhmPix, scienceFwhmPix)
451 if self.kConfig.useBicForKernelBasis:
456 bicDegrees = nbe(tmpKernelCellSet, self.log)
458 alardDegGauss=bicDegrees[0], metadata=self.metadata)
462 metadata=self.metadata)
464 spatialSolution, psfMatchingKernel, backgroundModel = self._solve(kernelCellSet, basisList)
466 psfMatchedMaskedImage = afwImage.MaskedImageF(templateMaskedImage.getBBox())
468 afwMath.convolve(psfMatchedMaskedImage, templateMaskedImage, psfMatchingKernel, doNormalize)
469 return pipeBase.Struct(
470 matchedImage=psfMatchedMaskedImage,
471 psfMatchingKernel=psfMatchingKernel,
472 backgroundModel=backgroundModel,
473 kernelCellSet=kernelCellSet,
478 templateFwhmPix=
None, scienceFwhmPix=
None,
479 candidateList=
None, doWarping=
True, convolveTemplate=
True):
480 """!Register, Psf-match and subtract two Exposures
482 Do the following, in order:
483 - Warp templateExposure to match scienceExposure, if their WCSs do not already match
484 - Determine a PSF matching kernel and differential background model
485 that matches templateExposure to scienceExposure
486 - PSF-match templateExposure to scienceExposure
487 - Compute subtracted exposure (see return values for equation).
489 @param templateExposure: exposure to PSF-match to scienceExposure
490 @param scienceExposure: reference Exposure
491 @param templateFwhmPix: FWHM (in pixels) of the Psf in the template image (image to convolve)
492 @param scienceFwhmPix: FWHM (in pixels) of the Psf in the science image
493 @param candidateList: a list of footprints/maskedImages for kernel candidates;
494 if None then source detection is run.
495 - Currently supported: list of Footprints or measAlg.PsfCandidateF
496 @param doWarping: what to do if templateExposure's and scienceExposure's WCSs do not match:
497 - if True then warp templateExposure to match scienceExposure
498 - if False then raise an Exception
499 @param convolveTemplate: convolve the template image or the science image
500 - if True, templateExposure is warped if doWarping, templateExposure is convolved
501 - if False, templateExposure is warped if doWarping, scienceExposure is convolved
503 @return a pipeBase.Struct containing these fields:
504 - subtractedExposure: subtracted Exposure = scienceExposure - (matchedImage + backgroundModel)
505 - matchedImage: templateExposure after warping to match templateExposure (if doWarping true),
506 and convolving with psfMatchingKernel
507 - psfMatchingKernel: PSF matching kernel
508 - backgroundModel: differential background model
509 - kernelCellSet: SpatialCellSet used to determine PSF matching kernel
512 templateExposure=templateExposure,
513 scienceExposure=scienceExposure,
514 templateFwhmPix=templateFwhmPix,
515 scienceFwhmPix=scienceFwhmPix,
516 candidateList=candidateList,
518 convolveTemplate=convolveTemplate
521 subtractedExposure = afwImage.ExposureF(scienceExposure,
True)
523 subtractedMaskedImage = subtractedExposure.getMaskedImage()
524 subtractedMaskedImage -= results.matchedExposure.getMaskedImage()
525 subtractedMaskedImage -= results.backgroundModel
527 subtractedExposure.setMaskedImage(results.warpedExposure.getMaskedImage())
528 subtractedMaskedImage = subtractedExposure.getMaskedImage()
529 subtractedMaskedImage -= results.matchedExposure.getMaskedImage()
530 subtractedMaskedImage -= results.backgroundModel
533 subtractedMaskedImage *= -1
536 subtractedMaskedImage /= results.psfMatchingKernel.computeImage(
537 afwImage.ImageD(results.psfMatchingKernel.getDimensions()),
False)
543 if not maskTransparency:
546 ds9.setMaskTransparency(maskTransparency)
547 if display
and displayDiffIm:
548 ds9.mtv(templateExposure, frame=lsstDebug.frame, title=
"Template")
550 ds9.mtv(results.matchedExposure, frame=lsstDebug.frame, title=
"Matched template")
552 ds9.mtv(scienceExposure, frame=lsstDebug.frame, title=
"Science Image")
554 ds9.mtv(subtractedExposure, frame=lsstDebug.frame, title=
"Difference Image")
557 results.subtractedExposure = subtractedExposure
562 templateFwhmPix=
None, scienceFwhmPix=
None):
563 """!Psf-match and subtract two MaskedImages
565 Do the following, in order:
566 - PSF-match templateMaskedImage to scienceMaskedImage
567 - Determine the differential background
568 - Return the difference: scienceMaskedImage -
569 ((warped templateMaskedImage convolved with psfMatchingKernel) + backgroundModel)
571 @param templateMaskedImage: MaskedImage to PSF-match to scienceMaskedImage
572 @param scienceMaskedImage: reference MaskedImage
573 @param templateFwhmPix: FWHM (in pixels) of the Psf in the template image (image to convolve)
574 @param scienceFwhmPix: FWHM (in pixels) of the Psf in the science image
575 @param candidateList: a list of footprints/maskedImages for kernel candidates;
576 if None then source detection is run.
577 - Currently supported: list of Footprints or measAlg.PsfCandidateF
579 @return a pipeBase.Struct containing these fields:
580 - subtractedMaskedImage = scienceMaskedImage - (matchedImage + backgroundModel)
581 - matchedImage: templateMaskedImage convolved with psfMatchingKernel
582 - psfMatchingKernel: PSF matching kernel
583 - backgroundModel: differential background model
584 - kernelCellSet: SpatialCellSet used to determine PSF matching kernel
586 if not candidateList:
587 raise RuntimeError(
"Candidate list must be populated by makeCandidateList")
590 templateMaskedImage=templateMaskedImage,
591 scienceMaskedImage=scienceMaskedImage,
592 candidateList=candidateList,
593 templateFwhmPix=templateFwhmPix,
594 scienceFwhmPix=scienceFwhmPix,
597 subtractedMaskedImage = afwImage.MaskedImageF(scienceMaskedImage,
True)
598 subtractedMaskedImage -= results.matchedImage
599 subtractedMaskedImage -= results.backgroundModel
600 results.subtractedMaskedImage = subtractedMaskedImage
606 if not maskTransparency:
609 ds9.setMaskTransparency(maskTransparency)
610 if display
and displayDiffIm:
611 ds9.mtv(subtractedMaskedImage, frame=lsstDebug.frame)
617 """!Get sources to use for Psf-matching
619 This method runs detection and measurement on an exposure.
620 The returned set of sources will be used as candidates for
623 @param exposure: Exposure on which to run detection/measurement
624 @param sigma: Detection threshold
625 @param doSmooth: Whether or not to smooth the Exposure with Psf before detection
626 @param idFactory: Factory for the generation of Source ids
628 @return source catalog containing candidates for the Psf-matching
632 table = afwTable.SourceTable.make(self.
selectSchema, idFactory)
635 mi = exposure.getMaskedImage()
637 imArr = mi.getImage().getArray()
638 maskArr = mi.getMask().getArray()
639 miArr = np.ma.masked_array(imArr, mask=maskArr)
641 bkgd = self.background.fitBackground(mi).getImageF()
643 self.log.warn(
"Failed to get background model. Falling back to median background estimation")
644 bkgd = np.ma.extras.median(miArr)
650 detRet = self.selectDetection.makeSourceCatalog(
656 selectSources = detRet.sources
657 self.selectMeasurement.run(measCat=selectSources, exposure=exposure)
665 """!Make a list of acceptable KernelCandidates
667 Accept or generate a list of candidate sources for
668 Psf-matching, and examine the Mask planes in both of the
669 images for indications of bad pixels
671 @param templateExposure: Exposure that will be convolved
672 @param scienceExposure: Exposure that will be matched-to
673 @param kernelSize: Dimensions of the Psf-matching Kernel, used to grow detection footprints
674 @param candidateList: List of Sources to examine. Elements must be of type afw.table.Source
675 or a type that wraps a Source and has a getSource() method, such as
676 meas.algorithms.PsfCandidateF.
678 @return a list of dicts having a "source" and "footprint"
679 field for the Sources deemed to be appropriate for Psf
682 if candidateList
is None:
685 if len(candidateList) < 1:
686 raise RuntimeError(
"No candidates in candidateList")
688 listTypes = set(type(x)
for x
in candidateList)
689 if len(listTypes) > 1:
690 raise RuntimeError(
"Candidate list contains mixed types: %s" % [l
for l
in listTypes])
694 candidateList[0].getSource()
695 except Exception
as e:
696 raise RuntimeError(
"Candidate List is of type: %s. " % (type(candidateList[0])) +
697 "Can only make candidate list from list of afwTable.SourceRecords, " +
698 "measAlg.PsfCandidateF or other type with a getSource() method: %s" % (e))
699 candidateList = [c.getSource()
for c
in candidateList]
701 candidateList = diffimTools.sourceToFootprintList(candidateList,
702 templateExposure, scienceExposure,
704 self.kConfig.detectionConfig,
706 if len(candidateList) == 0:
707 raise RuntimeError(
"Cannot find any objects suitable for KernelCandidacy")
712 """! NOT IMPLEMENTED YET"""
713 return self.kConfig.sizeCellX, self.kConfig.sizeCellY
715 def _buildCellSet(self, templateMaskedImage, scienceMaskedImage, candidateList):
716 """!Build a SpatialCellSet for use with the solve method
718 @param templateMaskedImage: MaskedImage to PSF-matched to scienceMaskedImage
719 @param scienceMaskedImage: reference MaskedImage
720 @param candidateList: a list of footprints/maskedImages for kernel candidates;
721 if None then source detection is run.
722 - Currently supported: list of Footprints or measAlg.PsfCandidateF
724 @return kernelCellSet: a SpatialCellSet for use with self._solve
726 if not candidateList:
727 raise RuntimeError(
"Candidate list must be populated by makeCandidateList")
733 sizeCellX, sizeCellY)
735 policy = pexConfig.makePolicy(self.
kConfig)
737 for cand
in candidateList:
738 bbox = cand[
'footprint'].getBBox()
740 tmi = afwImage.MaskedImageF(templateMaskedImage, bbox)
741 smi = afwImage.MaskedImageF(scienceMaskedImage, bbox)
742 cand = diffimLib.makeKernelCandidate(cand[
'source'], tmi, smi, policy)
744 self.log.debug(
"Candidate %d at %f, %f", cand.getId(), cand.getXCenter(), cand.getYCenter())
745 kernelCellSet.insertCandidate(cand)
750 """!Return True if two image-like objects are the same size
752 return templateMaskedImage.getDimensions() == scienceMaskedImage.getDimensions()
755 """!Return True if the WCS of the two Exposures have the same origin and extent
757 templateWcs = templateExposure.getWcs()
758 scienceWcs = scienceExposure.getWcs()
759 templateBBox = templateExposure.getBBox()
760 scienceBBox = scienceExposure.getBBox()
763 templateOrigin = templateWcs.pixelToSky(
afwGeom.Point2D(templateBBox.getBegin()))
764 scienceOrigin = scienceWcs.pixelToSky(
afwGeom.Point2D(scienceBBox.getBegin()))
767 templateLimit = templateWcs.pixelToSky(
afwGeom.Point2D(templateBBox.getEnd()))
768 scienceLimit = scienceWcs.pixelToSky(
afwGeom.Point2D(scienceBBox.getEnd()))
770 self.log.info(
"Template Wcs : %f,%f -> %f,%f",
771 templateOrigin[0], templateOrigin[1],
772 templateLimit[0], templateLimit[1])
773 self.log.info(
"Science Wcs : %f,%f -> %f,%f",
774 scienceOrigin[0], scienceOrigin[1],
775 scienceLimit[0], scienceLimit[1])
777 templateBBox =
afwGeom.Box2D(templateOrigin.getPosition(), templateLimit.getPosition())
778 scienceBBox =
afwGeom.Box2D(scienceOrigin.getPosition(), scienceLimit.getPosition())
779 if not (templateBBox.overlaps(scienceBBox)):
780 raise RuntimeError(
"Input images do not overlap at all")
782 if ((templateOrigin.getPosition() != scienceOrigin.getPosition())
or
783 (templateLimit.getPosition() != scienceLimit.getPosition())
or
784 (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.
def subtractMaskedImages
Psf-match and subtract two MaskedImages.
def makeCandidateList
Make a list of acceptable KernelCandidates.
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations...
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 >())
A function to return an Exposure of the correct type (cf.
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.
A floating-point coordinate rectangle geometry.
def matchExposures
Warp and PSF-match an exposure to the reference.
def __init__
Create the ImagePsfMatchTask.