LSSTApplications  19.0.0-14-gb0260a2+72efe9b372,20.0.0+7927753e06,20.0.0+8829bf0056,20.0.0+995114c5d2,20.0.0+b6f4b2abd1,20.0.0+bddc4f4cbe,20.0.0-1-g253301a+8829bf0056,20.0.0-1-g2b7511a+0d71a2d77f,20.0.0-1-g5b95a8c+7461dd0434,20.0.0-12-g321c96ea+23efe4bbff,20.0.0-16-gfab17e72e+fdf35455f6,20.0.0-2-g0070d88+ba3ffc8f0b,20.0.0-2-g4dae9ad+ee58a624b3,20.0.0-2-g61b8584+5d3db074ba,20.0.0-2-gb780d76+d529cf1a41,20.0.0-2-ged6426c+226a441f5f,20.0.0-2-gf072044+8829bf0056,20.0.0-2-gf1f7952+ee58a624b3,20.0.0-20-geae50cf+e37fec0aee,20.0.0-25-g3dcad98+544a109665,20.0.0-25-g5eafb0f+ee58a624b3,20.0.0-27-g64178ef+f1f297b00a,20.0.0-3-g4cc78c6+e0676b0dc8,20.0.0-3-g8f21e14+4fd2c12c9a,20.0.0-3-gbd60e8c+187b78b4b8,20.0.0-3-gbecbe05+48431fa087,20.0.0-38-ge4adf513+a12e1f8e37,20.0.0-4-g97dc21a+544a109665,20.0.0-4-gb4befbc+087873070b,20.0.0-4-gf910f65+5d3db074ba,20.0.0-5-gdfe0fee+199202a608,20.0.0-5-gfbfe500+d529cf1a41,20.0.0-6-g64f541c+d529cf1a41,20.0.0-6-g9a5b7a1+a1cd37312e,20.0.0-68-ga3f3dda+5fca18c6a4,20.0.0-9-g4aef684+e18322736b,w.2020.45
LSSTDataManagementBasePackage
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.selectDetection.reEstimateBackground = False
70  self.selectDetection.thresholdValue = 10.0
71 
72  # Minimal set of measurments for star selection
73  self.selectMeasurement.algorithms.names.clear()
74  self.selectMeasurement.algorithms.names = ('base_SdssCentroid', 'base_PsfFlux', 'base_PixelFlags',
75  'base_SdssShape', 'base_GaussianFlux', 'base_SkyCoord')
76  self.selectMeasurement.slots.modelFlux = None
77  self.selectMeasurement.slots.apFlux = None
78  self.selectMeasurement.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.kConfig = self.config.kernel.active
323  self._warper = afwMath.Warper.fromConfig(self.kConfig.warpingConfig)
324  # the background subtraction task uses a config from an unusual location,
325  # so cannot easily be constructed with makeSubtask
326  self.background = SubtractBackgroundTask(config=self.kConfig.afwBackgroundConfig, name="background",
327  parentTask=self)
328  self.selectSchema = afwTable.SourceTable.makeMinimalSchema()
330  self.makeSubtask("selectDetection", schema=self.selectSchema)
331  self.makeSubtask("selectMeasurement", schema=self.selectSchema, algMetadata=self.selectAlgMetadata)
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(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.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.warn("No estimate of Psf FWHM for template image")
424  else:
425  templateFwhmPix = self.getFwhmPix(templateExposure.getPsf())
426  self.log.info("templateFwhmPix: {}".format(templateFwhmPix))
427 
428  if scienceFwhmPix is None:
429  if not scienceExposure.hasPsf():
430  self.log.warn("No estimate of Psf FWHM for science image")
431  else:
432  scienceFwhmPix = self.getFwhmPix(scienceExposure.getPsf())
433  self.log.info("scienceFwhmPix: {}".format(scienceFwhmPix))
434 
435  if convolveTemplate:
436  kernelSize = makeKernelBasisList(self.kConfig, templateFwhmPix, scienceFwhmPix)[0].getWidth()
437  candidateList = self.makeCandidateList(
438  templateExposure, scienceExposure, kernelSize, candidateList)
439  results = self.matchMaskedImages(
440  templateExposure.getMaskedImage(), scienceExposure.getMaskedImage(), candidateList,
441  templateFwhmPix=templateFwhmPix, scienceFwhmPix=scienceFwhmPix)
442  else:
443  kernelSize = makeKernelBasisList(self.kConfig, scienceFwhmPix, templateFwhmPix)[0].getWidth()
444  candidateList = self.makeCandidateList(
445  templateExposure, scienceExposure, kernelSize, candidateList)
446  results = self.matchMaskedImages(
447  scienceExposure.getMaskedImage(), templateExposure.getMaskedImage(), candidateList,
448  templateFwhmPix=scienceFwhmPix, scienceFwhmPix=templateFwhmPix)
449 
450  psfMatchedExposure = afwImage.makeExposure(results.matchedImage, scienceExposure.getWcs())
451  psfMatchedExposure.setFilter(templateExposure.getFilter())
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(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(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.kConfig.useBicForKernelBasis:
545  tmpKernelCellSet = self._buildCellSet(templateMaskedImage,
546  scienceMaskedImage,
547  candidateList)
548  nbe = diffimTools.NbasisEvaluator(self.kConfig, templateFwhmPix, scienceFwhmPix)
549  bicDegrees = nbe(tmpKernelCellSet, self.log)
550  basisList = makeKernelBasisList(self.kConfig, templateFwhmPix, scienceFwhmPix,
551  alardDegGauss=bicDegrees[0], metadata=self.metadata)
552  del tmpKernelCellSet
553  else:
554  basisList = makeKernelBasisList(self.kConfig, templateFwhmPix, scienceFwhmPix,
555  metadata=self.metadata)
556 
557  spatialSolution, psfMatchingKernel, backgroundModel = self._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.Exposure`
587  Exposure to PSF-match to scienceExposure
588  scienceExposure : `lsst.afw.image.Exposure`
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.matchExposures(
630  templateExposure=templateExposure,
631  scienceExposure=scienceExposure,
632  templateFwhmPix=templateFwhmPix,
633  scienceFwhmPix=scienceFwhmPix,
634  candidateList=candidateList,
635  doWarping=doWarping,
636  convolveTemplate=convolveTemplate
637  )
638 
639  subtractedExposure = afwImage.ExposureF(scienceExposure, True)
640  if convolveTemplate:
641  subtractedMaskedImage = subtractedExposure.getMaskedImage()
642  subtractedMaskedImage -= results.matchedExposure.getMaskedImage()
643  subtractedMaskedImage -= results.backgroundModel
644  else:
645  subtractedExposure.setMaskedImage(results.warpedExposure.getMaskedImage())
646  subtractedMaskedImage = subtractedExposure.getMaskedImage()
647  subtractedMaskedImage -= results.matchedExposure.getMaskedImage()
648  subtractedMaskedImage -= results.backgroundModel
649 
650  # Preserve polarity of differences
651  subtractedMaskedImage *= -1
652 
653  # Place back on native photometric scale
654  subtractedMaskedImage /= results.psfMatchingKernel.computeImage(
655  afwImage.ImageD(results.psfMatchingKernel.getDimensions()), False)
656 
657  import lsstDebug
658  display = lsstDebug.Info(__name__).display
659  displayDiffIm = lsstDebug.Info(__name__).displayDiffIm
660  maskTransparency = lsstDebug.Info(__name__).maskTransparency
661  if not maskTransparency:
662  maskTransparency = 0
663  if display:
664  afwDisplay.setDefaultMaskTransparency(maskTransparency)
665  if display and displayDiffIm:
666  disp = afwDisplay.Display(frame=lsstDebug.frame)
667  disp.mtv(templateExposure, title="Template")
668  lsstDebug.frame += 1
669  disp = afwDisplay.Display(frame=lsstDebug.frame)
670  disp.mtv(results.matchedExposure, title="Matched template")
671  lsstDebug.frame += 1
672  disp = afwDisplay.Display(frame=lsstDebug.frame)
673  disp.mtv(scienceExposure, title="Science Image")
674  lsstDebug.frame += 1
675  disp = afwDisplay.Display(frame=lsstDebug.frame)
676  disp.mtv(subtractedExposure, title="Difference Image")
677  lsstDebug.frame += 1
678 
679  results.subtractedExposure = subtractedExposure
680  return results
681 
682  @pipeBase.timeMethod
683  def subtractMaskedImages(self, templateMaskedImage, scienceMaskedImage, candidateList,
684  templateFwhmPix=None, scienceFwhmPix=None):
685  """Psf-match and subtract two MaskedImages.
686 
687  Do the following, in order:
688 
689  - PSF-match templateMaskedImage to scienceMaskedImage
690  - Determine the differential background
691  - Return the difference: scienceMaskedImage
692  ((warped templateMaskedImage convolved with psfMatchingKernel) + backgroundModel)
693 
694  Parameters
695  ----------
696  templateMaskedImage : `lsst.afw.image.MaskedImage`
697  MaskedImage to PSF-match to ``scienceMaskedImage``
698  scienceMaskedImage : `lsst.afw.image.MaskedImage`
699  Reference MaskedImage
700  templateFwhmPix : `float`
701  FWHM (in pixels) of the Psf in the template image (image to convolve)
702  scienceFwhmPix : `float`
703  FWHM (in pixels) of the Psf in the science image
704  candidateList : `list`, optional
705  A list of footprints/maskedImages for kernel candidates;
706  if `None` then source detection is run.
707 
708  - Currently supported: list of Footprints or measAlg.PsfCandidateF
709 
710  Returns
711  -------
712  results : `lsst.pipe.base.Struct`
713  An `lsst.pipe.base.Struct` containing these fields:
714 
715  - ``subtractedMaskedImage`` : ``scienceMaskedImage`` - (matchedImage + backgroundModel)
716  - ``matchedImage`` : templateMaskedImage convolved with psfMatchingKernel
717  - `psfMatchingKernel`` : PSF matching kernel
718  - ``backgroundModel`` : differential background model
719  - ``kernelCellSet`` : SpatialCellSet used to determine PSF matching kernel
720 
721  """
722  if not candidateList:
723  raise RuntimeError("Candidate list must be populated by makeCandidateList")
724 
725  results = self.matchMaskedImages(
726  templateMaskedImage=templateMaskedImage,
727  scienceMaskedImage=scienceMaskedImage,
728  candidateList=candidateList,
729  templateFwhmPix=templateFwhmPix,
730  scienceFwhmPix=scienceFwhmPix,
731  )
732 
733  subtractedMaskedImage = afwImage.MaskedImageF(scienceMaskedImage, True)
734  subtractedMaskedImage -= results.matchedImage
735  subtractedMaskedImage -= results.backgroundModel
736  results.subtractedMaskedImage = subtractedMaskedImage
737 
738  import lsstDebug
739  display = lsstDebug.Info(__name__).display
740  displayDiffIm = lsstDebug.Info(__name__).displayDiffIm
741  maskTransparency = lsstDebug.Info(__name__).maskTransparency
742  if not maskTransparency:
743  maskTransparency = 0
744  if display:
745  afwDisplay.setDefaultMaskTransparency(maskTransparency)
746  if display and displayDiffIm:
747  disp = afwDisplay.Display(frame=lsstDebug.frame)
748  disp.mtv(subtractedMaskedImage, title="Subtracted masked image")
749  lsstDebug.frame += 1
750 
751  return results
752 
753  def getSelectSources(self, exposure, sigma=None, doSmooth=True, idFactory=None):
754  """Get sources to use for Psf-matching.
755 
756  This method runs detection and measurement on an exposure.
757  The returned set of sources will be used as candidates for
758  Psf-matching.
759 
760  Parameters
761  ----------
762  exposure : `lsst.afw.image.Exposure`
763  Exposure on which to run detection/measurement
764  sigma : `float`
765  Detection threshold
766  doSmooth : `bool`
767  Whether or not to smooth the Exposure with Psf before detection
768  idFactory :
769  Factory for the generation of Source ids
770 
771  Returns
772  -------
773  selectSources :
774  source catalog containing candidates for the Psf-matching
775  """
776  if idFactory:
777  table = afwTable.SourceTable.make(self.selectSchema, idFactory)
778  else:
779  table = afwTable.SourceTable.make(self.selectSchema)
780  mi = exposure.getMaskedImage()
781 
782  imArr = mi.getImage().getArray()
783  maskArr = mi.getMask().getArray()
784  miArr = np.ma.masked_array(imArr, mask=maskArr)
785  try:
786  fitBg = self.background.fitBackground(mi)
787  bkgd = fitBg.getImageF(self.background.config.algorithm,
788  self.background.config.undersampleStyle)
789  except Exception:
790  self.log.warn("Failed to get background model. Falling back to median background estimation")
791  bkgd = np.ma.extras.median(miArr)
792 
793  # Take off background for detection
794  mi -= bkgd
795  try:
796  table.setMetadata(self.selectAlgMetadata)
797  detRet = self.selectDetection.run(
798  table=table,
799  exposure=exposure,
800  sigma=sigma,
801  doSmooth=doSmooth
802  )
803  selectSources = detRet.sources
804  self.selectMeasurement.run(measCat=selectSources, exposure=exposure)
805  finally:
806  # Put back on the background in case it is needed down stream
807  mi += bkgd
808  del bkgd
809  return selectSources
810 
811  def makeCandidateList(self, templateExposure, scienceExposure, kernelSize, candidateList=None):
812  """Make a list of acceptable KernelCandidates.
813 
814  Accept or generate a list of candidate sources for
815  Psf-matching, and examine the Mask planes in both of the
816  images for indications of bad pixels
817 
818  Parameters
819  ----------
820  templateExposure : `lsst.afw.image.Exposure`
821  Exposure that will be convolved
822  scienceExposure : `lsst.afw.image.Exposure`
823  Exposure that will be matched-to
824  kernelSize : `float`
825  Dimensions of the Psf-matching Kernel, used to grow detection footprints
826  candidateList : `list`, optional
827  List of Sources to examine. Elements must be of type afw.table.Source
828  or a type that wraps a Source and has a getSource() method, such as
829  meas.algorithms.PsfCandidateF.
830 
831  Returns
832  -------
833  candidateList : `list` of `dict`
834  A list of dicts having a "source" and "footprint"
835  field for the Sources deemed to be appropriate for Psf
836  matching
837  """
838  if candidateList is None:
839  candidateList = self.getSelectSources(scienceExposure)
840 
841  if len(candidateList) < 1:
842  raise RuntimeError("No candidates in candidateList")
843 
844  listTypes = set(type(x) for x in candidateList)
845  if len(listTypes) > 1:
846  raise RuntimeError("Candidate list contains mixed types: %s" % [l for l in listTypes])
847 
848  if not isinstance(candidateList[0], afwTable.SourceRecord):
849  try:
850  candidateList[0].getSource()
851  except Exception as e:
852  raise RuntimeError(f"Candidate List is of type: {type(candidateList[0])} "
853  "Can only make candidate list from list of afwTable.SourceRecords, "
854  f"measAlg.PsfCandidateF or other type with a getSource() method: {e}")
855  candidateList = [c.getSource() for c in candidateList]
856 
857  candidateList = diffimTools.sourceToFootprintList(candidateList,
858  templateExposure, scienceExposure,
859  kernelSize,
860  self.kConfig.detectionConfig,
861  self.log)
862  if len(candidateList) == 0:
863  raise RuntimeError("Cannot find any objects suitable for KernelCandidacy")
864 
865  return candidateList
866 
867  def _adaptCellSize(self, candidateList):
868  """NOT IMPLEMENTED YET.
869  """
870  return self.kConfig.sizeCellX, self.kConfig.sizeCellY
871 
872  def _buildCellSet(self, templateMaskedImage, scienceMaskedImage, candidateList):
873  """Build a SpatialCellSet for use with the solve method.
874 
875  Parameters
876  ----------
877  templateMaskedImage : `lsst.afw.image.MaskedImage`
878  MaskedImage to PSF-matched to scienceMaskedImage
879  scienceMaskedImage : `lsst.afw.image.MaskedImage`
880  Reference MaskedImage
881  candidateList : `list`
882  A list of footprints/maskedImages for kernel candidates;
883 
884  - Currently supported: list of Footprints or measAlg.PsfCandidateF
885 
886  Returns
887  -------
888  kernelCellSet : `lsst.afw.math.SpatialCellSet`
889  a SpatialCellSet for use with self._solve
890  """
891  if not candidateList:
892  raise RuntimeError("Candidate list must be populated by makeCandidateList")
893 
894  sizeCellX, sizeCellY = self._adaptCellSize(candidateList)
895 
896  # Object to store the KernelCandidates for spatial modeling
897  kernelCellSet = afwMath.SpatialCellSet(templateMaskedImage.getBBox(),
898  sizeCellX, sizeCellY)
899 
900  ps = pexConfig.makePropertySet(self.kConfig)
901  # Place candidates within the spatial grid
902  for cand in candidateList:
903  if isinstance(cand, afwDetect.Footprint):
904  bbox = cand.getBBox()
905  else:
906  bbox = cand['footprint'].getBBox()
907  tmi = afwImage.MaskedImageF(templateMaskedImage, bbox)
908  smi = afwImage.MaskedImageF(scienceMaskedImage, bbox)
909 
910  if not isinstance(cand, afwDetect.Footprint):
911  if 'source' in cand:
912  cand = cand['source']
913  xPos = cand.getCentroid()[0]
914  yPos = cand.getCentroid()[1]
915  cand = diffimLib.makeKernelCandidate(xPos, yPos, tmi, smi, ps)
916 
917  self.log.debug("Candidate %d at %f, %f", cand.getId(), cand.getXCenter(), cand.getYCenter())
918  kernelCellSet.insertCandidate(cand)
919 
920  return kernelCellSet
921 
922  def _validateSize(self, templateMaskedImage, scienceMaskedImage):
923  """Return True if two image-like objects are the same size.
924  """
925  return templateMaskedImage.getDimensions() == scienceMaskedImage.getDimensions()
926 
927  def _validateWcs(self, templateExposure, scienceExposure):
928  """Return True if the WCS of the two Exposures have the same origin and extent.
929  """
930  templateWcs = templateExposure.getWcs()
931  scienceWcs = scienceExposure.getWcs()
932  templateBBox = templateExposure.getBBox()
933  scienceBBox = scienceExposure.getBBox()
934 
935  # LLC
936  templateOrigin = templateWcs.pixelToSky(geom.Point2D(templateBBox.getBegin()))
937  scienceOrigin = scienceWcs.pixelToSky(geom.Point2D(scienceBBox.getBegin()))
938 
939  # URC
940  templateLimit = templateWcs.pixelToSky(geom.Point2D(templateBBox.getEnd()))
941  scienceLimit = scienceWcs.pixelToSky(geom.Point2D(scienceBBox.getEnd()))
942 
943  self.log.info("Template Wcs : %f,%f -> %f,%f",
944  templateOrigin[0], templateOrigin[1],
945  templateLimit[0], templateLimit[1])
946  self.log.info("Science Wcs : %f,%f -> %f,%f",
947  scienceOrigin[0], scienceOrigin[1],
948  scienceLimit[0], scienceLimit[1])
949 
950  templateBBox = geom.Box2D(templateOrigin.getPosition(geom.degrees),
951  templateLimit.getPosition(geom.degrees))
952  scienceBBox = geom.Box2D(scienceOrigin.getPosition(geom.degrees),
953  scienceLimit.getPosition(geom.degrees))
954  if not (templateBBox.overlaps(scienceBBox)):
955  raise RuntimeError("Input images do not overlap at all")
956 
957  if ((templateOrigin != scienceOrigin)
958  or (templateLimit != scienceLimit)
959  or (templateExposure.getDimensions() != scienceExposure.getDimensions())):
960  return False
961  return True
962 
963 
964 subtractAlgorithmRegistry = pexConfig.makeRegistry(
965  doc="A registry of subtraction algorithms for use as a subtask in imageDifference",
966 )
967 
968 subtractAlgorithmRegistry.register('al', ImagePsfMatchTask)
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchTask._adaptCellSize
def _adaptCellSize(self, candidateList)
Definition: imagePsfMatch.py:867
lsst::afw::image
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
Definition: imageAlgorithm.dox:1
lsst::ip::diffim.makeKernelBasisList.makeKernelBasisList
def makeKernelBasisList(config, targetFwhmPix=None, referenceFwhmPix=None, basisDegGauss=None, metadata=None)
Definition: makeKernelBasisList.py:32
lsst::log.log.logContinued.warn
def warn(fmt, *args)
Definition: logContinued.py:205
lsst::log.log.logContinued.info
def info(fmt, *args)
Definition: logContinued.py:201
lsst::ip::diffim.diffimTools.NbasisEvaluator
Definition: diffimTools.py:535
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchTask.background
background
Definition: imagePsfMatch.py:326
lsst::log.log.logContinued.error
def error(fmt, *args)
Definition: logContinued.py:213
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchTask.selectAlgMetadata
selectAlgMetadata
Definition: imagePsfMatch.py:329
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchTask.matchExposures
def matchExposures(self, templateExposure, scienceExposure, templateFwhmPix=None, scienceFwhmPix=None, candidateList=None, doWarping=True, convolveTemplate=True)
Definition: imagePsfMatch.py:340
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchConfig.selectMeasurement
selectMeasurement
Definition: imagePsfMatch.py:62
lsst::ip::diffim.psfMatch.PsfMatchTask
Definition: psfMatch.py:527
lsst::afw::table::SourceRecord
Record class that contains measurements made on a single exposure.
Definition: Source.h:80
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchTask.selectSchema
selectSchema
Definition: imagePsfMatch.py:328
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchTask.makeCandidateList
def makeCandidateList(self, templateExposure, scienceExposure, kernelSize, candidateList=None)
Definition: imagePsfMatch.py:811
lsst.gdb.afw.printers.debug
bool debug
Definition: printers.py:9
lsst::afw::image::makeExposure
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:442
warpExposure
lsst::afw.display
Definition: __init__.py:1
lsst::daf::base::PropertyList
Class for storing ordered metadata with comments.
Definition: PropertyList.h:68
lsst.pex.config.history.format
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchConfig.setDefaults
def setDefaults(self)
Definition: imagePsfMatch.py:67
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchTask.kConfig
kConfig
Definition: imagePsfMatch.py:322
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchTask.getSelectSources
def getSelectSources(self, exposure, sigma=None, doSmooth=True, idFactory=None)
Definition: imagePsfMatch.py:753
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchConfig
Definition: imagePsfMatch.py:47
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchTask.subtractMaskedImages
def subtractMaskedImages(self, templateMaskedImage, scienceMaskedImage, candidateList, templateFwhmPix=None, scienceFwhmPix=None)
Definition: imagePsfMatch.py:683
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchTask._validateWcs
def _validateWcs(self, templateExposure, scienceExposure)
Definition: imagePsfMatch.py:927
lsst.pipe.tasks.assembleCoadd.run
def run(self, skyInfo, tempExpRefList, imageScalerList, weightList, altMaskList=None, mask=None, supplementaryData=None)
Definition: assembleCoadd.py:720
lsst::meas::algorithms.subtractBackground.SubtractBackgroundTask
Subtract the background from an exposure.
Definition: subtractBackground.py:126
lsstDebug.Info
Definition: lsstDebug.py:28
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchTask.subtractExposures
def subtractExposures(self, templateExposure, scienceExposure, templateFwhmPix=None, scienceFwhmPix=None, candidateList=None, doWarping=True, convolveTemplate=True)
Definition: imagePsfMatch.py:571
lsst.pex.config
Definition: __init__.py:1
lsst::meas::base
Definition: Algorithm.h:37
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchTask.__init__
def __init__(self, *args, **kwargs)
Definition: imagePsfMatch.py:318
lsst::afw::table
Definition: table.dox:3
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchTask._buildCellSet
def _buildCellSet(self, templateMaskedImage, scienceMaskedImage, candidateList)
Definition: imagePsfMatch.py:872
lsst::meas::algorithms::WarpedPsf
A Psf class that maps an arbitrary Psf through a coordinate transformation.
Definition: WarpedPsf.h:50
lsst::afw::detection
Definition: Footprint.h:50
lsst::geom
Definition: AffineTransform.h:36
lsst::daf::base
Definition: Utils.h:47
lsst::afw::math::ConvolutionControl
Parameters to control convolution.
Definition: ConvolveImage.h:50
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchTask
Definition: imagePsfMatch.py:81
lsst::afw::geom::makeWcsPairTransform
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:151
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchTask._validateSize
def _validateSize(self, templateMaskedImage, scienceMaskedImage)
Definition: imagePsfMatch.py:922
type
table::Key< int > type
Definition: Detector.cc:163
lsst::afw::math
Definition: statistics.dox:6
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchTask._warper
_warper
Definition: imagePsfMatch.py:323
lsst::geom::Point< double, 2 >
lsst::afw::math::SpatialCellSet
A collection of SpatialCells covering an entire image.
Definition: SpatialCell.h:387
lsst::ip::diffim.psfMatch.PsfMatchTask._solve
def _solve(self, kernelCellSet, basisList, returnOnExcept=False)
Definition: psfMatch.py:880
lsst::geom::Box2D
A floating-point coordinate rectangle geometry.
Definition: Box.h:413
lsst::afw::detection::Footprint
Class to describe the properties of a detected object from an image.
Definition: Footprint.h:63
lsst.pipe.base
Definition: __init__.py:1
lsst::afw::math::convolve
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, bool doNormalize, bool doCopyEdge)
Definition: ConvolveImage.cc:199
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchTask.matchMaskedImages
def matchMaskedImages(self, templateMaskedImage, scienceMaskedImage, candidateList, templateFwhmPix=None, scienceFwhmPix=None)
Definition: imagePsfMatch.py:458
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchConfig.selectDetection
selectDetection
Definition: imagePsfMatch.py:58
lsst::meas::algorithms
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations.
Definition: CoaddBoundedField.h:34
set
daf::base::PropertySet * set
Definition: fits.cc:912
lsst::ip::diffim.imagePsfMatch.ImagePsfMatchTask.getFwhmPix
def getFwhmPix(self, psf)
Definition: imagePsfMatch.py:333
lsst::afw::geom
Definition: frameSetUtils.h:40