LSST Applications  21.0.0-147-g0e635eb1+1acddb5be5,22.0.0+052faf71bd,22.0.0+1ea9a8b2b2,22.0.0+6312710a6c,22.0.0+729191ecac,22.0.0+7589c3a021,22.0.0+9f079a9461,22.0.1-1-g7d6de66+b8044ec9de,22.0.1-1-g87000a6+536b1ee016,22.0.1-1-g8e32f31+6312710a6c,22.0.1-10-gd060f87+016f7cdc03,22.0.1-12-g9c3108e+df145f6f68,22.0.1-16-g314fa6d+c825727ab8,22.0.1-19-g93a5c75+d23f2fb6d8,22.0.1-19-gb93eaa13+aab3ef7709,22.0.1-2-g8ef0a89+b8044ec9de,22.0.1-2-g92698f7+9f079a9461,22.0.1-2-ga9b0f51+052faf71bd,22.0.1-2-gac51dbf+052faf71bd,22.0.1-2-gb66926d+6312710a6c,22.0.1-2-gcb770ba+09e3807989,22.0.1-20-g32debb5+b8044ec9de,22.0.1-23-gc2439a9a+fb0756638e,22.0.1-3-g496fd5d+09117f784f,22.0.1-3-g59f966b+1e6ba2c031,22.0.1-3-g849a1b8+f8b568069f,22.0.1-3-gaaec9c0+c5c846a8b1,22.0.1-32-g5ddfab5d3+60ce4897b0,22.0.1-4-g037fbe1+64e601228d,22.0.1-4-g8623105+b8044ec9de,22.0.1-5-g096abc9+d18c45d440,22.0.1-5-g15c806e+57f5c03693,22.0.1-7-gba73697+57f5c03693,master-g6e05de7fdc+c1283a92b8,master-g72cdda8301+729191ecac,w.2021.39
LSST Data Management Base Package
imagePsfMatch.py
Go to the documentation of this file.
1 # This file is part of ip_diffim.
2 #
3 # Developed for the LSST Data Management System.
4 # This product includes software developed by the LSST Project
5 # (https://www.lsst.org).
6 # See the COPYRIGHT file at the top-level directory of this distribution
7 # for details of code ownership.
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <https://www.gnu.org/licenses/>.
21 
22 import numpy as np
23 
24 import lsst.daf.base as dafBase
25 import lsst.pex.config as pexConfig
26 import lsst.afw.detection as afwDetect
27 import lsst.afw.image as afwImage
28 import lsst.afw.math as afwMath
29 import lsst.afw.geom as afwGeom
30 import lsst.afw.table as afwTable
31 import lsst.geom as geom
32 import lsst.pipe.base as pipeBase
33 from lsst.meas.algorithms import SourceDetectionTask, SubtractBackgroundTask, WarpedPsf
34 from lsst.meas.base import SingleFrameMeasurementTask
35 from .makeKernelBasisList import makeKernelBasisList
36 from .psfMatch import PsfMatchTask, PsfMatchConfigDF, PsfMatchConfigAL
37 from . import utils as diffimUtils
38 from . import diffimLib
39 from . import diffimTools
40 import lsst.afw.display as afwDisplay
41 
42 __all__ = ["ImagePsfMatchConfig", "ImagePsfMatchTask", "subtractAlgorithmRegistry"]
43 
44 sigma2fwhm = 2.*np.sqrt(2.*np.log(2.))
45 
46 
47 class ImagePsfMatchConfig(pexConfig.Config):
48  """Configuration for image-to-image Psf matching.
49  """
50  kernel = pexConfig.ConfigChoiceField(
51  doc="kernel type",
52  typemap=dict(
53  AL=PsfMatchConfigAL,
54  DF=PsfMatchConfigDF
55  ),
56  default="AL",
57  )
58  selectDetection = pexConfig.ConfigurableField(
59  target=SourceDetectionTask,
60  doc="Initial detections used to feed stars to kernel fitting",
61  )
62  selectMeasurement = pexConfig.ConfigurableField(
63  target=SingleFrameMeasurementTask,
64  doc="Initial measurements used to feed stars to kernel fitting",
65  )
66 
67  def setDefaults(self):
68  # High sigma detections only
69  self.selectDetectionselectDetection.reEstimateBackground = False
70  self.selectDetectionselectDetection.thresholdValue = 10.0
71 
72  # Minimal set of measurments for star selection
73  self.selectMeasurementselectMeasurement.algorithms.names.clear()
74  self.selectMeasurementselectMeasurement.algorithms.names = ('base_SdssCentroid', 'base_PsfFlux', 'base_PixelFlags',
75  'base_SdssShape', 'base_GaussianFlux', 'base_SkyCoord')
76  self.selectMeasurementselectMeasurement.slots.modelFlux = None
77  self.selectMeasurementselectMeasurement.slots.apFlux = None
78  self.selectMeasurementselectMeasurement.slots.calibFlux = None
79 
80 
82  """Psf-match two MaskedImages or Exposures using the sources in the images.
83 
84  Parameters
85  ----------
86  args :
87  Arguments to be passed to lsst.ip.diffim.PsfMatchTask.__init__
88  kwargs :
89  Keyword arguments to be passed to lsst.ip.diffim.PsfMatchTask.__init__
90 
91  Notes
92  -----
93  Upon initialization, the kernel configuration is defined by self.config.kernel.active.
94  The task creates an lsst.afw.math.Warper from the subConfig self.config.kernel.active.warpingConfig.
95  A schema for the selection and measurement of candidate lsst.ip.diffim.KernelCandidates is
96  defined, and used to initize subTasks selectDetection (for candidate detection) and selectMeasurement
97  (for candidate measurement).
98 
99  Description
100 
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
105  and selection for this purpose. Sources are vetted for signal-to-noise and masked pixels
106  (in both the template and science image), and substamps around each acceptable
107  source are extracted and used to create an instance of KernelCandidate.
108  Each KernelCandidate is then placed within a lsst.afw.math.SpatialCellSet, which is used by an ensemble of
109  lsst.afw.math.CandidateVisitor instances to build the Psf-matching kernel. These visitors include, in
110  the order that they are called: BuildSingleKernelVisitor, KernelSumVisitor, BuildSpatialKernelVisitor,
111  and AssessSpatialKernelVisitor.
112 
113  Sigma clipping of KernelCandidates is performed as follows:
114 
115  - BuildSingleKernelVisitor, using the substamp diffim residuals from the per-source kernel fit,
116  if PsfMatchConfig.singleKernelClipping is True
117  - KernelSumVisitor, using the mean and standard deviation of the kernel sum from all candidates,
118  if PsfMatchConfig.kernelSumClipping is True
119  - AssessSpatialKernelVisitor, using the substamp diffim ressiduals from the spatial kernel fit,
120  if PsfMatchConfig.spatialKernelClipping is True
121 
122  The actual solving for the kernel (and differential background model) happens in
123  lsst.ip.diffim.PsfMatchTask._solve. This involves a loop over the SpatialCellSet that first builds the
124  per-candidate matching kernel for the requested number of KernelCandidates per cell
125  (PsfMatchConfig.nStarPerCell). The quality of this initial per-candidate difference image is examined,
126  using moments of the pixel residuals in the difference image normalized by the square root of the variance
127  (i.e. sigma); ideally this should follow a normal (0, 1) distribution,
128  but the rejection thresholds are set
129  by the config (PsfMatchConfig.candidateResidualMeanMax and PsfMatchConfig.candidateResidualStdMax).
130  All candidates that pass this initial build are then examined en masse to find the
131  mean/stdev of the kernel sums across all candidates.
132  Objects that are significantly above or below the mean,
133  typically due to variability or sources that are saturated in one image but not the other,
134  are also rejected.This threshold is defined by PsfMatchConfig.maxKsumSigma.
135  Finally, a spatial model is built using all currently-acceptable candidates,
136  and the spatial model used to derive a second set of (spatial) residuals
137  which are again used to reject bad candidates, using the same thresholds as above.
138 
139  Invoking the Task
140 
141  There is no run() method for this Task. Instead there are 4 methods that
142  may be used to invoke the Psf-matching. These are
143  `~lsst.ip.diffim.imagePsfMatch.ImagePsfMatchTask.matchMaskedImages`,
144  `~lsst.ip.diffim.imagePsfMatch.ImagePsfMatchTask.subtractMaskedImages`,
145  `~lsst.ip.diffim.imagePsfMatch.ImagePsfMatchTask.matchExposures`, and
146  `~lsst.ip.diffim.imagePsfMatch.ImagePsfMatchTask.subtractExposures`.
147 
148  The methods that operate on lsst.afw.image.MaskedImage require that the images already be astrometrically
149  aligned, and are the same shape. The methods that operate on lsst.afw.image.Exposure allow for the
150  input images to be misregistered and potentially be different sizes; by default a
151  lsst.afw.math.LanczosWarpingKernel is used to perform the astrometric alignment. The methods
152  that "match" images return a Psf-matched image, while the methods that "subtract" images
153  return a Psf-matched and template subtracted image.
154 
155  See each method's returned lsst.pipe.base.Struct for more details.
156 
157  Debug variables
158 
159  The lsst.pipe.base.cmdLineTask.CmdLineTask command line task interface supports a
160  flag -d/--debug to import debug.py from your PYTHONPATH. The relevant contents of debug.py
161  for this Task include:
162 
163  .. code-block:: py
164 
165  import sys
166  import lsstDebug
167  def DebugInfo(name):
168  di = lsstDebug.getInfo(name)
169  if name == "lsst.ip.diffim.psfMatch":
170  di.display = True # enable debug output
171  di.maskTransparency = 80 # display mask transparency
172  di.displayCandidates = True # show all the candidates and residuals
173  di.displayKernelBasis = False # show kernel basis functions
174  di.displayKernelMosaic = True # show kernel realized across the image
175  di.plotKernelSpatialModel = False # show coefficients of spatial model
176  di.showBadCandidates = True # show the bad candidates (red) along with good (green)
177  elif name == "lsst.ip.diffim.imagePsfMatch":
178  di.display = True # enable debug output
179  di.maskTransparency = 30 # display mask transparency
180  di.displayTemplate = True # show full (remapped) template
181  di.displaySciIm = True # show science image to match to
182  di.displaySpatialCells = True # show spatial cells
183  di.displayDiffIm = True # show difference image
184  di.showBadCandidates = True # show the bad candidates (red) along with good (green)
185  elif name == "lsst.ip.diffim.diaCatalogSourceSelector":
186  di.display = False # enable debug output
187  di.maskTransparency = 30 # display mask transparency
188  di.displayExposure = True # show exposure with candidates indicated
189  di.pauseAtEnd = False # pause when done
190  return di
191  lsstDebug.Info = DebugInfo
192  lsstDebug.frame = 1
193 
194  Note that if you want addional logging info, you may add to your scripts:
195 
196  .. code-block:: py
197 
198  import lsst.log.utils as logUtils
199  logUtils.traceSetAt("ip.diffim", 4)
200 
201  Examples
202  --------
203  A complete example of using ImagePsfMatchTask
204 
205  This code is imagePsfMatchTask.py in the examples directory, and can be run as e.g.
206 
207  .. code-block:: none
208 
209  examples/imagePsfMatchTask.py --debug
210  examples/imagePsfMatchTask.py --debug --mode="matchExposures"
211  examples/imagePsfMatchTask.py --debug --template /path/to/templateExp.fits
212  --science /path/to/scienceExp.fits
213 
214  Create a subclass of ImagePsfMatchTask that allows us to either match exposures, or subtract exposures:
215 
216  .. code-block:: none
217 
218  class MyImagePsfMatchTask(ImagePsfMatchTask):
219 
220  def __init__(self, args, kwargs):
221  ImagePsfMatchTask.__init__(self, args, kwargs)
222 
223  def run(self, templateExp, scienceExp, mode):
224  if mode == "matchExposures":
225  return self.matchExposures(templateExp, scienceExp)
226  elif mode == "subtractExposures":
227  return self.subtractExposures(templateExp, scienceExp)
228 
229  And allow the user the freedom to either run the script in default mode,
230  or point to their own images on disk.
231  Note that these images must be readable as an lsst.afw.image.Exposure.
232 
233  We have enabled some minor display debugging in this script via the --debug option. However, if you
234  have an lsstDebug debug.py in your PYTHONPATH you will get additional debugging displays. The following
235  block checks for this script:
236 
237  .. code-block:: py
238 
239  if args.debug:
240  try:
241  import debug
242  # Since I am displaying 2 images here, set the starting frame number for the LSST debug LSST
243  debug.lsstDebug.frame = 3
244  except ImportError as e:
245  print(e, file=sys.stderr)
246 
247  Finally, we call a run method that we define below.
248  First set up a Config and modify some of the parameters.
249  E.g. use an "Alard-Lupton" sum-of-Gaussian basis,
250  fit for a differential background, and use low order spatial
251  variation in the kernel and background:
252 
253  .. code-block:: py
254 
255  def run(args):
256  #
257  # Create the Config and use sum of gaussian basis
258  #
259  config = ImagePsfMatchTask.ConfigClass()
260  config.kernel.name = "AL"
261  config.kernel.active.fitForBackground = True
262  config.kernel.active.spatialKernelOrder = 1
263  config.kernel.active.spatialBgOrder = 0
264 
265  Make sure the images (if any) that were sent to the script exist on disk and are readable. If no images
266  are sent, make some fake data up for the sake of this example script (have a look at the code if you want
267  more details on generateFakeImages):
268 
269  .. code-block:: py
270 
271  # Run the requested method of the Task
272  if args.template is not None and args.science is not None:
273  if not os.path.isfile(args.template):
274  raise FileNotFoundError("Template image %s does not exist" % (args.template))
275  if not os.path.isfile(args.science):
276  raise FileNotFoundError("Science image %s does not exist" % (args.science))
277  try:
278  templateExp = afwImage.ExposureF(args.template)
279  except Exception as e:
280  raise RuntimeError("Cannot read template image %s" % (args.template))
281  try:
282  scienceExp = afwImage.ExposureF(args.science)
283  except Exception as e:
284  raise RuntimeError("Cannot read science image %s" % (args.science))
285  else:
286  templateExp, scienceExp = generateFakeImages()
287  config.kernel.active.sizeCellX = 128
288  config.kernel.active.sizeCellY = 128
289 
290  Create and run the Task:
291 
292  .. code-block:: py
293 
294  # Create the Task
295  psfMatchTask = MyImagePsfMatchTask(config=config)
296  # Run the Task
297  result = psfMatchTask.run(templateExp, scienceExp, args.mode)
298 
299  And finally provide some optional debugging displays:
300 
301  .. code-block:: py
302 
303  if args.debug:
304  # See if the LSST debug has incremented the frame number; if not start with frame 3
305  try:
306  frame = debug.lsstDebug.frame + 1
307  except Exception:
308  frame = 3
309  afwDisplay.Display(frame=frame).mtv(result.matchedExposure,
310  title="Example script: Matched Template Image")
311  if "subtractedExposure" in result.getDict():
312  afwDisplay.Display(frame=frame + 1).mtv(result.subtractedExposure,
313  title="Example script: Subtracted Image")
314  """
315 
316  ConfigClass = ImagePsfMatchConfig
317 
318  def __init__(self, *args, **kwargs):
319  """Create the ImagePsfMatchTask.
320  """
321  PsfMatchTask.__init__(self, *args, **kwargs)
322  self.kConfigkConfigkConfig = self.config.kernel.active
323  self._warper_warper = afwMath.Warper.fromConfig(self.kConfigkConfigkConfig.warpingConfig)
324  # the background subtraction task uses a config from an unusual location,
325  # so cannot easily be constructed with makeSubtask
326  self.backgroundbackground = SubtractBackgroundTask(config=self.kConfigkConfigkConfig.afwBackgroundConfig, name="background",
327  parentTask=self)
328  self.selectSchemaselectSchema = afwTable.SourceTable.makeMinimalSchema()
329  self.selectAlgMetadataselectAlgMetadata = dafBase.PropertyList()
330  self.makeSubtask("selectDetection", schema=self.selectSchemaselectSchema)
331  self.makeSubtask("selectMeasurement", schema=self.selectSchemaselectSchema, algMetadata=self.selectAlgMetadataselectAlgMetadata)
332 
333  def getFwhmPix(self, psf):
334  """Return the FWHM in pixels of a Psf.
335  """
336  sigPix = psf.computeShape().getDeterminantRadius()
337  return sigPix*sigma2fwhm
338 
339  @pipeBase.timeMethod
340  def matchExposures(self, templateExposure, scienceExposure,
341  templateFwhmPix=None, scienceFwhmPix=None,
342  candidateList=None, doWarping=True, convolveTemplate=True):
343  """Warp and PSF-match an exposure to the reference.
344 
345  Do the following, in order:
346 
347  - Warp templateExposure to match scienceExposure,
348  if doWarping True and their WCSs do not already match
349  - Determine a PSF matching kernel and differential background model
350  that matches templateExposure to scienceExposure
351  - Convolve templateExposure by PSF matching kernel
352 
353  Parameters
354  ----------
355  templateExposure : `lsst.afw.image.Exposure`
356  Exposure to warp and PSF-match to the reference masked image
357  scienceExposure : `lsst.afw.image.Exposure`
358  Exposure whose WCS and PSF are to be matched to
359  templateFwhmPix :`float`
360  FWHM (in pixels) of the Psf in the template image (image to convolve)
361  scienceFwhmPix : `float`
362  FWHM (in pixels) of the Psf in the science image
363  candidateList : `list`, optional
364  a list of footprints/maskedImages for kernel candidates;
365  if `None` then source detection is run.
366 
367  - Currently supported: list of Footprints or measAlg.PsfCandidateF
368 
369  doWarping : `bool`
370  what to do if ``templateExposure`` and ``scienceExposure`` WCSs do not match:
371 
372  - if `True` then warp ``templateExposure`` to match ``scienceExposure``
373  - if `False` then raise an Exception
374 
375  convolveTemplate : `bool`
376  Whether to convolve the template image or the science image:
377 
378  - if `True`, ``templateExposure`` is warped if doWarping,
379  ``templateExposure`` is convolved
380  - if `False`, ``templateExposure`` is warped if doWarping,
381  ``scienceExposure`` is convolved
382 
383  Returns
384  -------
385  results : `lsst.pipe.base.Struct`
386  An `lsst.pipe.base.Struct` containing these fields:
387 
388  - ``matchedImage`` : the PSF-matched exposure =
389  Warped ``templateExposure`` convolved by psfMatchingKernel. This has:
390 
391  - the same parent bbox, Wcs and PhotoCalib as scienceExposure
392  - the same filter as templateExposure
393  - no Psf (because the PSF-matching process does not compute one)
394 
395  - ``psfMatchingKernel`` : the PSF matching kernel
396  - ``backgroundModel`` : differential background model
397  - ``kernelCellSet`` : SpatialCellSet used to solve for the PSF matching kernel
398 
399  Raises
400  ------
401  RuntimeError
402  Raised if doWarping is False and ``templateExposure`` and
403  ``scienceExposure`` WCSs do not match
404  """
405  if not self._validateWcs_validateWcs(templateExposure, scienceExposure):
406  if doWarping:
407  self.log.info("Astrometrically registering template to science image")
408  templatePsf = templateExposure.getPsf()
409  # Warp PSF before overwriting exposure
410  xyTransform = afwGeom.makeWcsPairTransform(templateExposure.getWcs(),
411  scienceExposure.getWcs())
412  psfWarped = WarpedPsf(templatePsf, xyTransform)
413  templateExposure = self._warper_warper.warpExposure(scienceExposure.getWcs(),
414  templateExposure,
415  destBBox=scienceExposure.getBBox())
416  templateExposure.setPsf(psfWarped)
417  else:
418  self.log.error("ERROR: Input images not registered")
419  raise RuntimeError("Input images not registered")
420 
421  if templateFwhmPix is None:
422  if not templateExposure.hasPsf():
423  self.log.warning("No estimate of Psf FWHM for template image")
424  else:
425  templateFwhmPix = self.getFwhmPixgetFwhmPix(templateExposure.getPsf())
426  self.log.info("templateFwhmPix: %s", templateFwhmPix)
427 
428  if scienceFwhmPix is None:
429  if not scienceExposure.hasPsf():
430  self.log.warning("No estimate of Psf FWHM for science image")
431  else:
432  scienceFwhmPix = self.getFwhmPixgetFwhmPix(scienceExposure.getPsf())
433  self.log.info("scienceFwhmPix: %s", scienceFwhmPix)
434 
435  if convolveTemplate:
436  kernelSize = self.makeKernelBasisListmakeKernelBasisList(templateFwhmPix, scienceFwhmPix)[0].getWidth()
437  candidateList = self.makeCandidateListmakeCandidateList(
438  templateExposure, scienceExposure, kernelSize, candidateList)
439  results = self.matchMaskedImagesmatchMaskedImages(
440  templateExposure.getMaskedImage(), scienceExposure.getMaskedImage(), candidateList,
441  templateFwhmPix=templateFwhmPix, scienceFwhmPix=scienceFwhmPix)
442  else:
443  kernelSize = self.makeKernelBasisListmakeKernelBasisList(scienceFwhmPix, templateFwhmPix)[0].getWidth()
444  candidateList = self.makeCandidateListmakeCandidateList(
445  templateExposure, scienceExposure, kernelSize, candidateList)
446  results = self.matchMaskedImagesmatchMaskedImages(
447  scienceExposure.getMaskedImage(), templateExposure.getMaskedImage(), candidateList,
448  templateFwhmPix=scienceFwhmPix, scienceFwhmPix=templateFwhmPix)
449 
450  psfMatchedExposure = afwImage.makeExposure(results.matchedImage, scienceExposure.getWcs())
451  psfMatchedExposure.setFilterLabel(templateExposure.getFilterLabel())
452  psfMatchedExposure.setPhotoCalib(scienceExposure.getPhotoCalib())
453  results.warpedExposure = templateExposure
454  results.matchedExposure = psfMatchedExposure
455  return results
456 
457  @pipeBase.timeMethod
458  def matchMaskedImages(self, templateMaskedImage, scienceMaskedImage, candidateList,
459  templateFwhmPix=None, scienceFwhmPix=None):
460  """PSF-match a MaskedImage (templateMaskedImage) to a reference MaskedImage (scienceMaskedImage).
461 
462  Do the following, in order:
463 
464  - Determine a PSF matching kernel and differential background model
465  that matches templateMaskedImage to scienceMaskedImage
466  - Convolve templateMaskedImage by the PSF matching kernel
467 
468  Parameters
469  ----------
470  templateMaskedImage : `lsst.afw.image.MaskedImage`
471  masked image to PSF-match to the reference masked image;
472  must be warped to match the reference masked image
473  scienceMaskedImage : `lsst.afw.image.MaskedImage`
474  maskedImage whose PSF is to be matched to
475  templateFwhmPix : `float`
476  FWHM (in pixels) of the Psf in the template image (image to convolve)
477  scienceFwhmPix : `float`
478  FWHM (in pixels) of the Psf in the science image
479  candidateList : `list`, optional
480  A list of footprints/maskedImages for kernel candidates;
481  if `None` then source detection is run.
482 
483  - Currently supported: list of Footprints or measAlg.PsfCandidateF
484 
485  Returns
486  -------
487  result : `callable`
488  An `lsst.pipe.base.Struct` containing these fields:
489 
490  - psfMatchedMaskedImage: the PSF-matched masked image =
491  ``templateMaskedImage`` convolved with psfMatchingKernel.
492  This has the same xy0, dimensions and wcs as ``scienceMaskedImage``.
493  - psfMatchingKernel: the PSF matching kernel
494  - backgroundModel: differential background model
495  - kernelCellSet: SpatialCellSet used to solve for the PSF matching kernel
496 
497  Raises
498  ------
499  RuntimeError
500  Raised if input images have different dimensions
501  """
502  import lsstDebug
503  display = lsstDebug.Info(__name__).display
504  displayTemplate = lsstDebug.Info(__name__).displayTemplate
505  displaySciIm = lsstDebug.Info(__name__).displaySciIm
506  displaySpatialCells = lsstDebug.Info(__name__).displaySpatialCells
507  maskTransparency = lsstDebug.Info(__name__).maskTransparency
508  if not maskTransparency:
509  maskTransparency = 0
510  if display:
511  afwDisplay.setDefaultMaskTransparency(maskTransparency)
512 
513  if not candidateList:
514  raise RuntimeError("Candidate list must be populated by makeCandidateList")
515 
516  if not self._validateSize_validateSize(templateMaskedImage, scienceMaskedImage):
517  self.log.error("ERROR: Input images different size")
518  raise RuntimeError("Input images different size")
519 
520  if display and displayTemplate:
521  disp = afwDisplay.Display(frame=lsstDebug.frame)
522  disp.mtv(templateMaskedImage, title="Image to convolve")
523  lsstDebug.frame += 1
524 
525  if display and displaySciIm:
526  disp = afwDisplay.Display(frame=lsstDebug.frame)
527  disp.mtv(scienceMaskedImage, title="Image to not convolve")
528  lsstDebug.frame += 1
529 
530  kernelCellSet = self._buildCellSet_buildCellSet_buildCellSet(templateMaskedImage,
531  scienceMaskedImage,
532  candidateList)
533 
534  if display and displaySpatialCells:
535  diffimUtils.showKernelSpatialCells(scienceMaskedImage, kernelCellSet,
536  symb="o", ctype=afwDisplay.CYAN, ctypeUnused=afwDisplay.YELLOW,
537  ctypeBad=afwDisplay.RED, size=4, frame=lsstDebug.frame,
538  title="Image to not convolve")
539  lsstDebug.frame += 1
540 
541  if templateFwhmPix and scienceFwhmPix:
542  self.log.info("Matching Psf FWHM %.2f -> %.2f pix", templateFwhmPix, scienceFwhmPix)
543 
544  if self.kConfigkConfigkConfig.useBicForKernelBasis:
545  tmpKernelCellSet = self._buildCellSet_buildCellSet_buildCellSet(templateMaskedImage,
546  scienceMaskedImage,
547  candidateList)
548  nbe = diffimTools.NbasisEvaluator(self.kConfigkConfigkConfig, templateFwhmPix, scienceFwhmPix)
549  bicDegrees = nbe(tmpKernelCellSet, self.log)
550  basisList = self.makeKernelBasisListmakeKernelBasisList(templateFwhmPix, scienceFwhmPix,
551  basisDegGauss=bicDegrees[0], metadata=self.metadata)
552  del tmpKernelCellSet
553  else:
554  basisList = self.makeKernelBasisListmakeKernelBasisList(templateFwhmPix, scienceFwhmPix,
555  metadata=self.metadata)
556 
557  spatialSolution, psfMatchingKernel, backgroundModel = self._solve_solve(kernelCellSet, basisList)
558 
559  psfMatchedMaskedImage = afwImage.MaskedImageF(templateMaskedImage.getBBox())
560  convolutionControl = afwMath.ConvolutionControl()
561  convolutionControl.setDoNormalize(False)
562  afwMath.convolve(psfMatchedMaskedImage, templateMaskedImage, psfMatchingKernel, convolutionControl)
563  return pipeBase.Struct(
564  matchedImage=psfMatchedMaskedImage,
565  psfMatchingKernel=psfMatchingKernel,
566  backgroundModel=backgroundModel,
567  kernelCellSet=kernelCellSet,
568  )
569 
570  @pipeBase.timeMethod
571  def subtractExposures(self, templateExposure, scienceExposure,
572  templateFwhmPix=None, scienceFwhmPix=None,
573  candidateList=None, doWarping=True, convolveTemplate=True):
574  """Register, Psf-match and subtract two Exposures.
575 
576  Do the following, in order:
577 
578  - Warp templateExposure to match scienceExposure, if their WCSs do not already match
579  - Determine a PSF matching kernel and differential background model
580  that matches templateExposure to scienceExposure
581  - PSF-match templateExposure to scienceExposure
582  - Compute subtracted exposure (see return values for equation).
583 
584  Parameters
585  ----------
586  templateExposure : `lsst.afw.image.ExposureF`
587  Exposure to PSF-match to scienceExposure
588  scienceExposure : `lsst.afw.image.ExposureF`
589  Reference Exposure
590  templateFwhmPix : `float`
591  FWHM (in pixels) of the Psf in the template image (image to convolve)
592  scienceFwhmPix : `float`
593  FWHM (in pixels) of the Psf in the science image
594  candidateList : `list`, optional
595  A list of footprints/maskedImages for kernel candidates;
596  if `None` then source detection is run.
597 
598  - Currently supported: list of Footprints or measAlg.PsfCandidateF
599 
600  doWarping : `bool`
601  What to do if ``templateExposure``` and ``scienceExposure`` WCSs do
602  not match:
603 
604  - if `True` then warp ``templateExposure`` to match ``scienceExposure``
605  - if `False` then raise an Exception
606 
607  convolveTemplate : `bool`
608  Convolve the template image or the science image
609 
610  - if `True`, ``templateExposure`` is warped if doWarping,
611  ``templateExposure`` is convolved
612  - if `False`, ``templateExposure`` is warped if doWarping,
613  ``scienceExposure is`` convolved
614 
615  Returns
616  -------
617  result : `lsst.pipe.base.Struct`
618  An `lsst.pipe.base.Struct` containing these fields:
619 
620  - ``subtractedExposure`` : subtracted Exposure
621  scienceExposure - (matchedImage + backgroundModel)
622  - ``matchedImage`` : ``templateExposure`` after warping to match
623  ``templateExposure`` (if doWarping true),
624  and convolving with psfMatchingKernel
625  - ``psfMatchingKernel`` : PSF matching kernel
626  - ``backgroundModel`` : differential background model
627  - ``kernelCellSet`` : SpatialCellSet used to determine PSF matching kernel
628  """
629  results = self.matchExposuresmatchExposures(
630  templateExposure=templateExposure,
631  scienceExposure=scienceExposure,
632  templateFwhmPix=templateFwhmPix,
633  scienceFwhmPix=scienceFwhmPix,
634  candidateList=candidateList,
635  doWarping=doWarping,
636  convolveTemplate=convolveTemplate
637  )
638  # Always inherit WCS and photocalib from science exposure
639  subtractedExposure = afwImage.ExposureF(scienceExposure, deep=True)
640  # Note, the decorrelation afterburner re-calculates the variance plane
641  # from the variance planes of the original exposures.
642  # That recalculation code must be in accordance with the
643  # photometric level set here in ``subtractedMaskedImage``.
644  if convolveTemplate:
645  subtractedMaskedImage = subtractedExposure.maskedImage
646  subtractedMaskedImage -= results.matchedExposure.maskedImage
647  subtractedMaskedImage -= results.backgroundModel
648  else:
649  subtractedMaskedImage = subtractedExposure.maskedImage
650  subtractedMaskedImage[:, :] = results.warpedExposure.maskedImage
651  subtractedMaskedImage -= results.matchedExposure.maskedImage
652  subtractedMaskedImage -= results.backgroundModel
653 
654  # Preserve polarity of differences
655  subtractedMaskedImage *= -1
656 
657  # Place back on native photometric scale
658  subtractedMaskedImage /= results.psfMatchingKernel.computeImage(
659  afwImage.ImageD(results.psfMatchingKernel.getDimensions()), False)
660  # We matched to the warped template
661  subtractedExposure.setPsf(results.warpedExposure.getPsf())
662 
663  import lsstDebug
664  display = lsstDebug.Info(__name__).display
665  displayDiffIm = lsstDebug.Info(__name__).displayDiffIm
666  maskTransparency = lsstDebug.Info(__name__).maskTransparency
667  if not maskTransparency:
668  maskTransparency = 0
669  if display:
670  afwDisplay.setDefaultMaskTransparency(maskTransparency)
671  if display and displayDiffIm:
672  disp = afwDisplay.Display(frame=lsstDebug.frame)
673  disp.mtv(templateExposure, title="Template")
674  lsstDebug.frame += 1
675  disp = afwDisplay.Display(frame=lsstDebug.frame)
676  disp.mtv(results.matchedExposure, title="Matched template")
677  lsstDebug.frame += 1
678  disp = afwDisplay.Display(frame=lsstDebug.frame)
679  disp.mtv(scienceExposure, title="Science Image")
680  lsstDebug.frame += 1
681  disp = afwDisplay.Display(frame=lsstDebug.frame)
682  disp.mtv(subtractedExposure, title="Difference Image")
683  lsstDebug.frame += 1
684 
685  results.subtractedExposure = subtractedExposure
686  return results
687 
688  @pipeBase.timeMethod
689  def subtractMaskedImages(self, templateMaskedImage, scienceMaskedImage, candidateList,
690  templateFwhmPix=None, scienceFwhmPix=None):
691  """Psf-match and subtract two MaskedImages.
692 
693  Do the following, in order:
694 
695  - PSF-match templateMaskedImage to scienceMaskedImage
696  - Determine the differential background
697  - Return the difference: scienceMaskedImage
698  ((warped templateMaskedImage convolved with psfMatchingKernel) + backgroundModel)
699 
700  Parameters
701  ----------
702  templateMaskedImage : `lsst.afw.image.MaskedImage`
703  MaskedImage to PSF-match to ``scienceMaskedImage``
704  scienceMaskedImage : `lsst.afw.image.MaskedImage`
705  Reference MaskedImage
706  templateFwhmPix : `float`
707  FWHM (in pixels) of the Psf in the template image (image to convolve)
708  scienceFwhmPix : `float`
709  FWHM (in pixels) of the Psf in the science image
710  candidateList : `list`, optional
711  A list of footprints/maskedImages for kernel candidates;
712  if `None` then source detection is run.
713 
714  - Currently supported: list of Footprints or measAlg.PsfCandidateF
715 
716  Returns
717  -------
718  results : `lsst.pipe.base.Struct`
719  An `lsst.pipe.base.Struct` containing these fields:
720 
721  - ``subtractedMaskedImage`` : ``scienceMaskedImage`` - (matchedImage + backgroundModel)
722  - ``matchedImage`` : templateMaskedImage convolved with psfMatchingKernel
723  - `psfMatchingKernel`` : PSF matching kernel
724  - ``backgroundModel`` : differential background model
725  - ``kernelCellSet`` : SpatialCellSet used to determine PSF matching kernel
726 
727  """
728  if not candidateList:
729  raise RuntimeError("Candidate list must be populated by makeCandidateList")
730 
731  results = self.matchMaskedImagesmatchMaskedImages(
732  templateMaskedImage=templateMaskedImage,
733  scienceMaskedImage=scienceMaskedImage,
734  candidateList=candidateList,
735  templateFwhmPix=templateFwhmPix,
736  scienceFwhmPix=scienceFwhmPix,
737  )
738 
739  subtractedMaskedImage = afwImage.MaskedImageF(scienceMaskedImage, True)
740  subtractedMaskedImage -= results.matchedImage
741  subtractedMaskedImage -= results.backgroundModel
742  results.subtractedMaskedImage = subtractedMaskedImage
743 
744  import lsstDebug
745  display = lsstDebug.Info(__name__).display
746  displayDiffIm = lsstDebug.Info(__name__).displayDiffIm
747  maskTransparency = lsstDebug.Info(__name__).maskTransparency
748  if not maskTransparency:
749  maskTransparency = 0
750  if display:
751  afwDisplay.setDefaultMaskTransparency(maskTransparency)
752  if display and displayDiffIm:
753  disp = afwDisplay.Display(frame=lsstDebug.frame)
754  disp.mtv(subtractedMaskedImage, title="Subtracted masked image")
755  lsstDebug.frame += 1
756 
757  return results
758 
759  def getSelectSources(self, exposure, sigma=None, doSmooth=True, idFactory=None):
760  """Get sources to use for Psf-matching.
761 
762  This method runs detection and measurement on an exposure.
763  The returned set of sources will be used as candidates for
764  Psf-matching.
765 
766  Parameters
767  ----------
768  exposure : `lsst.afw.image.Exposure`
769  Exposure on which to run detection/measurement
770  sigma : `float`
771  Detection threshold
772  doSmooth : `bool`
773  Whether or not to smooth the Exposure with Psf before detection
774  idFactory :
775  Factory for the generation of Source ids
776 
777  Returns
778  -------
779  selectSources :
780  source catalog containing candidates for the Psf-matching
781  """
782  if idFactory:
783  table = afwTable.SourceTable.make(self.selectSchemaselectSchema, idFactory)
784  else:
785  table = afwTable.SourceTable.make(self.selectSchemaselectSchema)
786  mi = exposure.getMaskedImage()
787 
788  imArr = mi.getImage().getArray()
789  maskArr = mi.getMask().getArray()
790  miArr = np.ma.masked_array(imArr, mask=maskArr)
791  try:
792  fitBg = self.backgroundbackground.fitBackground(mi)
793  bkgd = fitBg.getImageF(self.backgroundbackground.config.algorithm,
794  self.backgroundbackground.config.undersampleStyle)
795  except Exception:
796  self.log.warning("Failed to get background model. Falling back to median background estimation")
797  bkgd = np.ma.median(miArr)
798 
799  # Take off background for detection
800  mi -= bkgd
801  try:
802  table.setMetadata(self.selectAlgMetadataselectAlgMetadata)
803  detRet = self.selectDetection.run(
804  table=table,
805  exposure=exposure,
806  sigma=sigma,
807  doSmooth=doSmooth
808  )
809  selectSources = detRet.sources
810  self.selectMeasurement.run(measCat=selectSources, exposure=exposure)
811  finally:
812  # Put back on the background in case it is needed down stream
813  mi += bkgd
814  del bkgd
815  return selectSources
816 
817  def makeCandidateList(self, templateExposure, scienceExposure, kernelSize, candidateList=None):
818  """Make a list of acceptable KernelCandidates.
819 
820  Accept or generate a list of candidate sources for
821  Psf-matching, and examine the Mask planes in both of the
822  images for indications of bad pixels
823 
824  Parameters
825  ----------
826  templateExposure : `lsst.afw.image.Exposure`
827  Exposure that will be convolved
828  scienceExposure : `lsst.afw.image.Exposure`
829  Exposure that will be matched-to
830  kernelSize : `float`
831  Dimensions of the Psf-matching Kernel, used to grow detection footprints
832  candidateList : `list`, optional
833  List of Sources to examine. Elements must be of type afw.table.Source
834  or a type that wraps a Source and has a getSource() method, such as
835  meas.algorithms.PsfCandidateF.
836 
837  Returns
838  -------
839  candidateList : `list` of `dict`
840  A list of dicts having a "source" and "footprint"
841  field for the Sources deemed to be appropriate for Psf
842  matching
843  """
844  if candidateList is None:
845  candidateList = self.getSelectSourcesgetSelectSources(scienceExposure)
846 
847  if len(candidateList) < 1:
848  raise RuntimeError("No candidates in candidateList")
849 
850  listTypes = set(type(x) for x in candidateList)
851  if len(listTypes) > 1:
852  raise RuntimeError("Candidate list contains mixed types: %s" % [t for t in listTypes])
853 
854  if not isinstance(candidateList[0], afwTable.SourceRecord):
855  try:
856  candidateList[0].getSource()
857  except Exception as e:
858  raise RuntimeError(f"Candidate List is of type: {type(candidateList[0])} "
859  "Can only make candidate list from list of afwTable.SourceRecords, "
860  f"measAlg.PsfCandidateF or other type with a getSource() method: {e}")
861  candidateList = [c.getSource() for c in candidateList]
862 
863  candidateList = diffimTools.sourceToFootprintList(candidateList,
864  templateExposure, scienceExposure,
865  kernelSize,
866  self.kConfigkConfigkConfig.detectionConfig,
867  self.log)
868  if len(candidateList) == 0:
869  raise RuntimeError("Cannot find any objects suitable for KernelCandidacy")
870 
871  return candidateList
872 
873  def makeKernelBasisList(self, targetFwhmPix=None, referenceFwhmPix=None,
874  basisDegGauss=None, basisSigmaGauss=None, metadata=None):
875  """Wrapper to set log messages for
876  `lsst.ip.diffim.makeKernelBasisList`.
877 
878  Parameters
879  ----------
880  targetFwhmPix : `float`, optional
881  Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
882  Not used for delta function basis sets.
883  referenceFwhmPix : `float`, optional
884  Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
885  Not used for delta function basis sets.
886  basisDegGauss : `list` of `int`, optional
887  Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
888  Not used for delta function basis sets.
889  basisSigmaGauss : `list` of `int`, optional
890  Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
891  Not used for delta function basis sets.
892  metadata : `lsst.daf.base.PropertySet`, optional
893  Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
894  Not used for delta function basis sets.
895 
896  Returns
897  -------
898  basisList: `list` of `lsst.afw.math.kernel.FixedKernel`
899  List of basis kernels.
900  """
901  basisList = makeKernelBasisList(self.kConfigkConfigkConfig,
902  targetFwhmPix=targetFwhmPix,
903  referenceFwhmPix=referenceFwhmPix,
904  basisDegGauss=basisDegGauss,
905  basisSigmaGauss=basisSigmaGauss,
906  metadata=metadata)
907  if targetFwhmPix == referenceFwhmPix:
908  self.log.info("Target and reference psf fwhms are equal, falling back to config values")
909  elif referenceFwhmPix > targetFwhmPix:
910  self.log.info("Reference psf fwhm is the greater, normal convolution mode")
911  else:
912  self.log.info("Target psf fwhm is the greater, deconvolution mode")
913 
914  return basisList
915 
916  def _adaptCellSize(self, candidateList):
917  """NOT IMPLEMENTED YET.
918  """
919  return self.kConfigkConfigkConfig.sizeCellX, self.kConfigkConfigkConfig.sizeCellY
920 
921  def _buildCellSet(self, templateMaskedImage, scienceMaskedImage, candidateList):
922  """Build a SpatialCellSet for use with the solve method.
923 
924  Parameters
925  ----------
926  templateMaskedImage : `lsst.afw.image.MaskedImage`
927  MaskedImage to PSF-matched to scienceMaskedImage
928  scienceMaskedImage : `lsst.afw.image.MaskedImage`
929  Reference MaskedImage
930  candidateList : `list`
931  A list of footprints/maskedImages for kernel candidates;
932 
933  - Currently supported: list of Footprints or measAlg.PsfCandidateF
934 
935  Returns
936  -------
937  kernelCellSet : `lsst.afw.math.SpatialCellSet`
938  a SpatialCellSet for use with self._solve
939  """
940  if not candidateList:
941  raise RuntimeError("Candidate list must be populated by makeCandidateList")
942 
943  sizeCellX, sizeCellY = self._adaptCellSize_adaptCellSize(candidateList)
944 
945  # Object to store the KernelCandidates for spatial modeling
946  kernelCellSet = afwMath.SpatialCellSet(templateMaskedImage.getBBox(),
947  sizeCellX, sizeCellY)
948 
949  ps = pexConfig.makePropertySet(self.kConfigkConfigkConfig)
950  # Place candidates within the spatial grid
951  for cand in candidateList:
952  if isinstance(cand, afwDetect.Footprint):
953  bbox = cand.getBBox()
954  else:
955  bbox = cand['footprint'].getBBox()
956  tmi = afwImage.MaskedImageF(templateMaskedImage, bbox)
957  smi = afwImage.MaskedImageF(scienceMaskedImage, bbox)
958 
959  if not isinstance(cand, afwDetect.Footprint):
960  if 'source' in cand:
961  cand = cand['source']
962  xPos = cand.getCentroid()[0]
963  yPos = cand.getCentroid()[1]
964  cand = diffimLib.makeKernelCandidate(xPos, yPos, tmi, smi, ps)
965 
966  self.log.debug("Candidate %d at %f, %f", cand.getId(), cand.getXCenter(), cand.getYCenter())
967  kernelCellSet.insertCandidate(cand)
968 
969  return kernelCellSet
970 
971  def _validateSize(self, templateMaskedImage, scienceMaskedImage):
972  """Return True if two image-like objects are the same size.
973  """
974  return templateMaskedImage.getDimensions() == scienceMaskedImage.getDimensions()
975 
976  def _validateWcs(self, templateExposure, scienceExposure):
977  """Return True if the WCS of the two Exposures have the same origin and extent.
978  """
979  templateWcs = templateExposure.getWcs()
980  scienceWcs = scienceExposure.getWcs()
981  templateBBox = templateExposure.getBBox()
982  scienceBBox = scienceExposure.getBBox()
983 
984  # LLC
985  templateOrigin = templateWcs.pixelToSky(geom.Point2D(templateBBox.getBegin()))
986  scienceOrigin = scienceWcs.pixelToSky(geom.Point2D(scienceBBox.getBegin()))
987 
988  # URC
989  templateLimit = templateWcs.pixelToSky(geom.Point2D(templateBBox.getEnd()))
990  scienceLimit = scienceWcs.pixelToSky(geom.Point2D(scienceBBox.getEnd()))
991 
992  self.log.info("Template Wcs : %f,%f -> %f,%f",
993  templateOrigin[0], templateOrigin[1],
994  templateLimit[0], templateLimit[1])
995  self.log.info("Science Wcs : %f,%f -> %f,%f",
996  scienceOrigin[0], scienceOrigin[1],
997  scienceLimit[0], scienceLimit[1])
998 
999  templateBBox = geom.Box2D(templateOrigin.getPosition(geom.degrees),
1000  templateLimit.getPosition(geom.degrees))
1001  scienceBBox = geom.Box2D(scienceOrigin.getPosition(geom.degrees),
1002  scienceLimit.getPosition(geom.degrees))
1003  if not (templateBBox.overlaps(scienceBBox)):
1004  raise RuntimeError("Input images do not overlap at all")
1005 
1006  if ((templateOrigin != scienceOrigin)
1007  or (templateLimit != scienceLimit)
1008  or (templateExposure.getDimensions() != scienceExposure.getDimensions())):
1009  return False
1010  return True
1011 
1012 
1013 subtractAlgorithmRegistry = pexConfig.makeRegistry(
1014  doc="A registry of subtraction algorithms for use as a subtask in imageDifference",
1015 )
1016 
1017 subtractAlgorithmRegistry.register('al', ImagePsfMatchTask)
table::Key< int > type
Definition: Detector.cc:163
Class to describe the properties of a detected object from an image.
Definition: Footprint.h:63
Parameters to control convolution.
Definition: ConvolveImage.h:50
A collection of SpatialCells covering an entire image.
Definition: SpatialCell.h:383
Record class that contains measurements made on a single exposure.
Definition: Source.h:78
Class for storing ordered metadata with comments.
Definition: PropertyList.h:68
A floating-point coordinate rectangle geometry.
Definition: Box.h:413
def _validateWcs(self, templateExposure, scienceExposure)
def _buildCellSet(self, templateMaskedImage, scienceMaskedImage, candidateList)
def _validateSize(self, templateMaskedImage, scienceMaskedImage)
def subtractMaskedImages(self, templateMaskedImage, scienceMaskedImage, candidateList, templateFwhmPix=None, scienceFwhmPix=None)
def matchMaskedImages(self, templateMaskedImage, scienceMaskedImage, candidateList, templateFwhmPix=None, scienceFwhmPix=None)
def getSelectSources(self, exposure, sigma=None, doSmooth=True, idFactory=None)
def subtractExposures(self, templateExposure, scienceExposure, templateFwhmPix=None, scienceFwhmPix=None, candidateList=None, doWarping=True, convolveTemplate=True)
def matchExposures(self, templateExposure, scienceExposure, templateFwhmPix=None, scienceFwhmPix=None, candidateList=None, doWarping=True, convolveTemplate=True)
def makeKernelBasisList(self, targetFwhmPix=None, referenceFwhmPix=None, basisDegGauss=None, basisSigmaGauss=None, metadata=None)
def makeCandidateList(self, templateExposure, scienceExposure, kernelSize, candidateList=None)
def _solve(self, kernelCellSet, basisList, returnOnExcept=False)
Definition: psfMatch.py:878
A Psf class that maps an arbitrary Psf through a coordinate transformation.
Definition: WarpedPsf.h:52
daf::base::PropertySet * set
Definition: fits.cc:912
std::shared_ptr< TransformPoint2ToPoint2 > makeWcsPairTransform(SkyWcs const &src, SkyWcs const &dst)
A Transform obtained by putting two SkyWcs objects "back to back".
Definition: SkyWcs.cc:146
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
std::shared_ptr< Exposure< ImagePixelT, MaskPixelT, VariancePixelT > > makeExposure(MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > &mimage, std::shared_ptr< geom::SkyWcs const > wcs=std::shared_ptr< geom::SkyWcs const >())
A function to return an Exposure of the correct type (cf.
Definition: Exposure.h:462
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.
int warpExposure(DestExposureT &destExposure, SrcExposureT const &srcExposure, WarpingControl const &control, typename DestExposureT::MaskedImageT::SinglePixel padValue=lsst::afw::math::edgePixel< typename DestExposureT::MaskedImageT >(typename lsst::afw::image::detail::image_traits< typename DestExposureT::MaskedImageT >::image_category()))
Warp (remap) one exposure to another.
def run(self, coaddExposures, bbox, wcs)
Definition: getTemplate.py:603
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations.