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