LSST Applications g0b6bd0c080+a72a5dd7e6,g1182afd7b4+2a019aa3bb,g17e5ecfddb+2b8207f7de,g1d67935e3f+06cf436103,g38293774b4+ac198e9f13,g396055baef+6a2097e274,g3b44f30a73+6611e0205b,g480783c3b1+98f8679e14,g48ccf36440+89c08d0516,g4b93dc025c+98f8679e14,g5c4744a4d9+a302e8c7f0,g613e996a0d+e1c447f2e0,g6c8d09e9e7+25247a063c,g7271f0639c+98f8679e14,g7a9cd813b8+124095ede6,g9d27549199+a302e8c7f0,ga1cf026fa3+ac198e9f13,ga32aa97882+7403ac30ac,ga786bb30fb+7a139211af,gaa63f70f4e+9994eb9896,gabf319e997+ade567573c,gba47b54d5d+94dc90c3ea,gbec6a3398f+06cf436103,gc6308e37c7+07dd123edb,gc655b1545f+ade567573c,gcc9029db3c+ab229f5caf,gd01420fc67+06cf436103,gd877ba84e5+06cf436103,gdb4cecd868+6f279b5b48,ge2d134c3d5+cc4dbb2e3f,ge448b5faa6+86d1ceac1d,gecc7e12556+98f8679e14,gf3ee170dca+25247a063c,gf4ac96e456+ade567573c,gf9f5ea5b4d+ac198e9f13,gff490e6085+8c2580be5c,w.2022.27
LSST Data Management Base Package
modelPsfMatch.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
22import numpy as np
23
24from . import diffimLib
25import lsst.afw.display as afwDisplay
26import lsst.afw.image as afwImage
27import lsst.afw.math as afwMath
28import lsst.geom as geom
29import lsst.pex.config as pexConfig
30import lsst.pipe.base as pipeBase
31from lsst.utils.logging import getTraceLogger
32from lsst.utils.timer import timeMethod
33from .makeKernelBasisList import makeKernelBasisList
34from .psfMatch import PsfMatchTask, PsfMatchConfigAL
35from . import utils as dituils
36
37__all__ = ("ModelPsfMatchTask", "ModelPsfMatchConfig")
38
39sigma2fwhm = 2.*np.sqrt(2.*np.log(2.))
40
41
43 nextInt = int(np.ceil(x))
44 return nextInt + 1 if nextInt%2 == 0 else nextInt
45
46
47class ModelPsfMatchConfig(pexConfig.Config):
48 """Configuration for model-to-model Psf matching"""
49
50 kernel = pexConfig.ConfigChoiceField(
51 doc="kernel type",
52 typemap=dict(
53 AL=PsfMatchConfigAL,
54 ),
55 default="AL",
56 )
57 doAutoPadPsf = pexConfig.Field(
58 dtype=bool,
59 doc=("If too small, automatically pad the science Psf? "
60 "Pad to smallest dimensions appropriate for the matching kernel dimensions, "
61 "as specified by autoPadPsfTo. If false, pad by the padPsfBy config."),
62 default=True,
63 )
64 autoPadPsfTo = pexConfig.RangeField(
65 dtype=float,
66 doc=("Minimum Science Psf dimensions as a fraction of matching kernel dimensions. "
67 "If the dimensions of the Psf to be matched are less than the "
68 "matching kernel dimensions * autoPadPsfTo, pad Science Psf to this size. "
69 "Ignored if doAutoPadPsf=False."),
70 default=1.4,
71 min=1.0,
72 max=2.0
73 )
74 padPsfBy = pexConfig.Field(
75 dtype=int,
76 doc="Pixels (even) to pad Science Psf by before matching. Ignored if doAutoPadPsf=True",
77 default=0,
78 )
79
80 def setDefaults(self):
81 # No sigma clipping
82 self.kernelkernel.active.singleKernelClipping = False
83 self.kernelkernel.active.kernelSumClipping = False
84 self.kernelkernel.active.spatialKernelClipping = False
85 self.kernelkernel.active.checkConditionNumber = False
86
87 # Variance is ill defined
88 self.kernelkernel.active.constantVarianceWeighting = True
89
90 # Do not change specified kernel size
91 self.kernelkernel.active.scaleByFwhm = False
92
93
95 """Matching of two model Psfs, and application of the Psf-matching kernel to an input Exposure
96
97 Notes
98 -----
99
100 This Task differs from ImagePsfMatchTask in that it matches two Psf _models_, by realizing
101 them in an Exposure-sized SpatialCellSet and then inserting each Psf-image pair into KernelCandidates.
102 Because none of the pairs of sources that are to be matched should be invalid, all sigma clipping is
103 turned off in ModelPsfMatchConfig. And because there is no tracked _variance_ in the Psf images, the
104 debugging and logging QA info should be interpreted with caution.
105
106 One item of note is that the sizes of Psf models are fixed (e.g. its defined as a 21x21 matrix). When the
107 Psf-matching kernel is being solved for, the Psf "image" is convolved with each kernel basis function,
108 leading to a loss of information around the borders.
109 This pixel loss will be problematic for the numerical
110 stability of the kernel solution if the size of the convolution kernel
111 (set by ModelPsfMatchConfig.kernelSize) is much bigger than: psfSize//2.
112 Thus the sizes of Psf-model matching kernels are typically smaller
113 than their image-matching counterparts. If the size of the kernel is too small, the convolved stars will
114 look "boxy"; if the kernel is too large, the kernel solution will be "noisy". This is a trade-off that
115 needs careful attention for a given dataset.
116
117 The primary use case for this Task is in matching an Exposure to a
118 constant-across-the-sky Psf model for the purposes of image coaddition.
119 It is important to note that in the code, the "template" Psf is the Psf
120 that the science image gets matched to. In this sense the order of template and science image are
121 reversed, compared to ImagePsfMatchTask, which operates on the template image.
122
123 Debug variables
124
125 The `lsst.pipe.base.cmdLineTask.CmdLineTask` command line task interface supports a
126 flag -d/--debug to import debug.py from your PYTHONPATH. The relevant contents of debug.py
127 for this Task include:
128
129 .. code-block:: py
130
131 import sys
132 import lsstDebug
133 def DebugInfo(name):
134 di = lsstDebug.getInfo(name)
135 if name == "lsst.ip.diffim.psfMatch":
136 di.display = True # global
137 di.maskTransparency = 80 # mask transparency
138 di.displayCandidates = True # show all the candidates and residuals
139 di.displayKernelBasis = False # show kernel basis functions
140 di.displayKernelMosaic = True # show kernel realized across the image
141 di.plotKernelSpatialModel = False # show coefficients of spatial model
142 di.showBadCandidates = True # show the bad candidates (red) along with good (green)
143 elif name == "lsst.ip.diffim.modelPsfMatch":
144 di.display = True # global
145 di.maskTransparency = 30 # mask transparency
146 di.displaySpatialCells = True # show spatial cells before the fit
147 return di
148 lsstDebug.Info = DebugInfo
149 lsstDebug.frame = 1
150
151 Note that if you want addional logging info, you may add to your scripts:
152
153 .. code-block:: py
154
155 import lsst.utils.logging as logUtils
156 logUtils.trace_set_at("lsst.ip.diffim", 4)
157
158 Examples
159 --------
160 A complete example of using ModelPsfMatchTask
161
162 This code is modelPsfMatchTask.py in the examples directory, and can be run as e.g.
163
164 .. code-block :: none
165
166 examples/modelPsfMatchTask.py
167 examples/modelPsfMatchTask.py --debug
168 examples/modelPsfMatchTask.py --debug --template /path/to/templateExp.fits
169 --science /path/to/scienceExp.fits
170
171 Create a subclass of ModelPsfMatchTask that accepts two exposures.
172 Note that the "template" exposure contains the Psf that will get matched to,
173 and the "science" exposure is the one that will be convolved:
174
175 .. code-block :: none
176
177 class MyModelPsfMatchTask(ModelPsfMatchTask):
178 def __init__(self, *args, **kwargs):
179 ModelPsfMatchTask.__init__(self, *args, **kwargs)
180 def run(self, templateExp, scienceExp):
181 return ModelPsfMatchTask.run(self, scienceExp, templateExp.getPsf())
182
183 And allow the user the freedom to either run the script in default mode,
184 or point to their own images on disk. Note that these
185 images must be readable as an lsst.afw.image.Exposure:
186
187 .. code-block :: none
188
189 if __name__ == "__main__":
190 import argparse
191 parser = argparse.ArgumentParser(description="Demonstrate the use of ModelPsfMatchTask")
192 parser.add_argument("--debug", "-d", action="store_true", help="Load debug.py?", default=False)
193 parser.add_argument("--template", "-t", help="Template Exposure to use", default=None)
194 parser.add_argument("--science", "-s", help="Science Exposure to use", default=None)
195 args = parser.parse_args()
196
197 We have enabled some minor display debugging in this script via the –debug option.
198 However, if you have an lsstDebug debug.py in your PYTHONPATH you will get additional
199 debugging displays. The following block checks for this script:
200
201 .. code-block :: none
202
203 if args.debug:
204 try:
205 import debug
206 # Since I am displaying 2 images here, set the starting frame number for the LSST debug LSST
207 debug.lsstDebug.frame = 3
208 except ImportError as e:
209 print(e, file=sys.stderr)
210
211 Finally, we call a run method that we define below.
212 First set up a Config and modify some of the parameters.
213 In particular we don't want to "grow" the sizes of the kernel or KernelCandidates,
214 since we are operating with fixed–size images (i.e. the size of the input Psf models).
215
216 .. code-block :: none
217
218 def run(args):
219 #
220 # Create the Config and use sum of gaussian basis
221 #
222 config = ModelPsfMatchTask.ConfigClass()
223 config.kernel.active.scaleByFwhm = False
224
225 Make sure the images (if any) that were sent to the script exist on disk and are readable.
226 If no images are sent, make some fake data up for the sake of this example script
227 (have a look at the code if you want more details on generateFakeData):
228
229 .. code-block :: none
230
231 # Run the requested method of the Task
232 if args.template is not None and args.science is not None:
233 if not os.path.isfile(args.template):
234 raise FileNotFoundError("Template image %s does not exist" % (args.template))
235 if not os.path.isfile(args.science):
236 raise FileNotFoundError("Science image %s does not exist" % (args.science))
237 try:
238 templateExp = afwImage.ExposureF(args.template)
239 except Exception as e:
240 raise RuntimeError("Cannot read template image %s" % (args.template))
241 try:
242 scienceExp = afwImage.ExposureF(args.science)
243 except Exception as e:
244 raise RuntimeError("Cannot read science image %s" % (args.science))
245 else:
246 templateExp, scienceExp = generateFakeData()
247 config.kernel.active.sizeCellX = 128
248 config.kernel.active.sizeCellY = 128
249
250 .. code-block :: none
251
252 if args.debug:
253 afwDisplay.Display(frame=1).mtv(templateExp, title="Example script: Input Template")
254 afwDisplay.Display(frame=2).mtv(scienceExp, title="Example script: Input Science Image")
255
256 Create and run the Task:
257
258 .. code-block :: none
259
260 # Create the Task
261 psfMatchTask = MyModelPsfMatchTask(config=config)
262 # Run the Task
263 result = psfMatchTask.run(templateExp, scienceExp)
264
265 And finally provide optional debugging display of the Psf-matched (via the Psf models) science image:
266
267 .. code-block :: none
268
269 if args.debug:
270 # See if the LSST debug has incremented the frame number; if not start with frame 3
271 try:
272 frame = debug.lsstDebug.frame + 1
273 except Exception:
274 frame = 3
275 afwDisplay.Display(frame=frame).mtv(result.psfMatchedExposure,
276 title="Example script: Matched Science Image")
277
278 """
279 ConfigClass = ModelPsfMatchConfig
280
281 def __init__(self, *args, **kwargs):
282 """Create a ModelPsfMatchTask
283
284 Parameters
285 ----------
286 *args
287 arguments to be passed to lsst.ip.diffim.PsfMatchTask.__init__
288 **kwargs
289 keyword arguments to be passed to lsst.ip.diffim.PsfMatchTask.__init__
290
291 Notes
292 -----
293 Upon initialization, the kernel configuration is defined by self.config.kernel.active. This Task
294 does have a run() method, which is the default way to call the Task.
295 """
296 PsfMatchTask.__init__(self, *args, **kwargs)
297 self.kConfigkConfigkConfig = self.config.kernel.active
298
299 @timeMethod
300 def run(self, exposure, referencePsfModel, kernelSum=1.0):
301 """Psf-match an exposure to a model Psf
302
303 Parameters
304 ----------
305 exposure : `lsst.afw.image.Exposure`
306 Exposure to Psf-match to the reference Psf model;
307 it must return a valid PSF model via exposure.getPsf()
308 referencePsfModel : `lsst.afw.detection.Psf`
309 The Psf model to match to
310 kernelSum : `float`, optional
311 A multipicative factor to apply to the kernel sum (default=1.0)
312
313 Returns
314 -------
315 result : `struct`
316 - ``psfMatchedExposure`` : the Psf-matched Exposure.
317 This has the same parent bbox, Wcs, PhotoCalib and
318 Filter as the input Exposure but no Psf.
319 In theory the Psf should equal referencePsfModel but
320 the match is likely not exact.
321 - ``psfMatchingKernel`` : the spatially varying Psf-matching kernel
322 - ``kernelCellSet`` : SpatialCellSet used to solve for the Psf-matching kernel
323 - ``referencePsfModel`` : Validated and/or modified reference model used
324
325 Raises
326 ------
327 RuntimeError
328 if the Exposure does not contain a Psf model
329 """
330 if not exposure.hasPsf():
331 raise RuntimeError("exposure does not contain a Psf model")
332
333 maskedImage = exposure.getMaskedImage()
334
335 self.log.info("compute Psf-matching kernel")
336 result = self._buildCellSet_buildCellSet_buildCellSet(exposure, referencePsfModel)
337 kernelCellSet = result.kernelCellSet
338 referencePsfModel = result.referencePsfModel
339 # TODO: This should be evaluated at (or close to) the center of the
340 # exposure's bounding box in DM-32756.
341 sciAvgPos = exposure.getPsf().getAveragePosition()
342 modelAvgPos = referencePsfModel.getAveragePosition()
343 fwhmScience = exposure.getPsf().computeShape(sciAvgPos).getDeterminantRadius()*sigma2fwhm
344 fwhmModel = referencePsfModel.computeShape(modelAvgPos).getDeterminantRadius()*sigma2fwhm
345
346 basisList = makeKernelBasisList(self.kConfigkConfigkConfig, fwhmScience, fwhmModel, metadata=self.metadata)
347 spatialSolution, psfMatchingKernel, backgroundModel = self._solve_solve(kernelCellSet, basisList)
348
349 if psfMatchingKernel.isSpatiallyVarying():
350 sParameters = np.array(psfMatchingKernel.getSpatialParameters())
351 sParameters[0][0] = kernelSum
352 psfMatchingKernel.setSpatialParameters(sParameters)
353 else:
354 kParameters = np.array(psfMatchingKernel.getKernelParameters())
355 kParameters[0] = kernelSum
356 psfMatchingKernel.setKernelParameters(kParameters)
357
358 self.log.info("Psf-match science exposure to reference")
359 psfMatchedExposure = afwImage.ExposureF(exposure.getBBox(), exposure.getWcs())
360 psfMatchedExposure.info.id = exposure.info.id
361 psfMatchedExposure.setFilter(exposure.getFilter())
362 psfMatchedExposure.setPhotoCalib(exposure.getPhotoCalib())
363 psfMatchedExposure.getInfo().setVisitInfo(exposure.getInfo().getVisitInfo())
364 psfMatchedExposure.setPsf(referencePsfModel)
365 psfMatchedMaskedImage = psfMatchedExposure.getMaskedImage()
366
367 # Normalize the psf-matching kernel while convolving since its magnitude is meaningless
368 # when PSF-matching one model to another.
369 convolutionControl = afwMath.ConvolutionControl()
370 convolutionControl.setDoNormalize(True)
371 afwMath.convolve(psfMatchedMaskedImage, maskedImage, psfMatchingKernel, convolutionControl)
372
373 self.log.info("done")
374 return pipeBase.Struct(psfMatchedExposure=psfMatchedExposure,
375 psfMatchingKernel=psfMatchingKernel,
376 kernelCellSet=kernelCellSet,
377 metadata=self.metadata,
378 )
379
380 def _diagnostic(self, kernelCellSet, spatialSolution, spatialKernel, spatialBg):
381 """Print diagnostic information on spatial kernel and background fit
382
383 The debugging diagnostics are not really useful here, since the images we are matching have
384 no variance. Thus override the _diagnostic method to generate no logging information"""
385 return
386
387 def _buildCellSet(self, exposure, referencePsfModel):
388 """Build a SpatialCellSet for use with the solve method
389
390 Parameters
391 ----------
392 exposure : `lsst.afw.image.Exposure`
393 The science exposure that will be convolved; must contain a Psf
394 referencePsfModel : `lsst.afw.detection.Psf`
395 Psf model to match to
396
397 Returns
398 -------
399 result : `struct`
400 - ``kernelCellSet`` : a SpatialCellSet to be used by self._solve_solve
401 - ``referencePsfModel`` : Validated and/or modified
402 reference model used to populate the SpatialCellSet
403
404 Notes
405 -----
406 If the reference Psf model and science Psf model have different dimensions,
407 adjust the referencePsfModel (the model to which the exposure PSF will be matched)
408 to match that of the science Psf. If the science Psf dimensions vary across the image,
409 as is common with a WarpedPsf, either pad or clip (depending on config.padPsf)
410 the dimensions to be constant.
411 """
412 sizeCellX = self.kConfigkConfigkConfig.sizeCellX
413 sizeCellY = self.kConfigkConfigkConfig.sizeCellY
414
415 scienceBBox = exposure.getBBox()
416 # Extend for proper spatial matching kernel all the way to edge, especially for narrow strips
417 scienceBBox.grow(geom.Extent2I(sizeCellX, sizeCellY))
418
419 sciencePsfModel = exposure.getPsf()
420
421 dimenR = referencePsfModel.getLocalKernel(scienceBBox.getCenter()).getDimensions()
422
423 regionSizeX, regionSizeY = scienceBBox.getDimensions()
424 scienceX0, scienceY0 = scienceBBox.getMin()
425
426 kernelCellSet = afwMath.SpatialCellSet(geom.Box2I(scienceBBox), sizeCellX, sizeCellY)
427
428 nCellX = regionSizeX//sizeCellX
429 nCellY = regionSizeY//sizeCellY
430
431 if nCellX == 0 or nCellY == 0:
432 raise ValueError("Exposure dimensions=%s and sizeCell=(%s, %s). Insufficient area to match" %
433 (scienceBBox.getDimensions(), sizeCellX, sizeCellY))
434
435 # Survey the PSF dimensions of the Spatial Cell Set
436 # to identify the minimum enclosed or maximum bounding square BBox.
437 widthList = []
438 heightList = []
439 for row in range(nCellY):
440 posY = sizeCellY*row + sizeCellY//2 + scienceY0
441 for col in range(nCellX):
442 posX = sizeCellX*col + sizeCellX//2 + scienceX0
443 widthS, heightS = sciencePsfModel.computeBBox(geom.Point2D(posX, posY)).getDimensions()
444 widthList.append(widthS)
445 heightList.append(heightS)
446
447 psfSize = max(max(heightList), max(widthList))
448
449 if self.config.doAutoPadPsf:
450 minPsfSize = nextOddInteger(self.kConfigkConfigkConfig.kernelSize*self.config.autoPadPsfTo)
451 paddingPix = max(0, minPsfSize - psfSize)
452 else:
453 if self.config.padPsfBy % 2 != 0:
454 raise ValueError("Config padPsfBy (%i pixels) must be even number." %
455 self.config.padPsfBy)
456 paddingPix = self.config.padPsfBy
457
458 if paddingPix > 0:
459 self.log.debug("Padding Science PSF from (%d, %d) to (%d, %d) pixels",
460 psfSize, psfSize, paddingPix + psfSize, paddingPix + psfSize)
461 psfSize += paddingPix
462
463 # Check that PSF is larger than the matching kernel
464 maxKernelSize = psfSize - 1
465 if maxKernelSize % 2 == 0:
466 maxKernelSize -= 1
467 if self.kConfigkConfigkConfig.kernelSize > maxKernelSize:
468 message = """
469 Kernel size (%d) too big to match Psfs of size %d.
470 Please reconfigure by setting one of the following:
471 1) kernel size to <= %d
472 2) doAutoPadPsf=True
473 3) padPsfBy to >= %s
474 """ % (self.kConfig.kernelSize, psfSize,
475 maxKernelSize, self.kConfigkConfigkConfig.kernelSize - maxKernelSize)
476 raise ValueError(message)
477
478 dimenS = geom.Extent2I(psfSize, psfSize)
479
480 if (dimenR != dimenS):
481 try:
482 referencePsfModel = referencePsfModel.resized(psfSize, psfSize)
483 self.log.info("Adjusted dimensions of reference PSF model from %s to %s", dimenR, dimenS)
484 except Exception as e:
485 self.log.warning("Zero padding or clipping the reference PSF model of type %s and dimensions"
486 " %s to the science Psf dimensions %s because: %s",
487 referencePsfModel.__class__.__name__, dimenR, dimenS, e)
488 dimenR = dimenS
489
490 ps = pexConfig.makePropertySet(self.kConfigkConfigkConfig)
491 for row in range(nCellY):
492 # place at center of cell
493 posY = sizeCellY*row + sizeCellY//2 + scienceY0
494
495 for col in range(nCellX):
496 # place at center of cell
497 posX = sizeCellX*col + sizeCellX//2 + scienceX0
498
499 getTraceLogger(self.log, 4).debug("Creating Psf candidate at %.1f %.1f", posX, posY)
500
501 # reference kernel image, at location of science subimage
502 referenceMI = self._makePsfMaskedImage_makePsfMaskedImage(referencePsfModel, posX, posY, dimensions=dimenR)
503
504 # kernel image we are going to convolve
505 scienceMI = self._makePsfMaskedImage_makePsfMaskedImage(sciencePsfModel, posX, posY, dimensions=dimenR)
506
507 # The image to convolve is the science image, to the reference Psf.
508 kc = diffimLib.makeKernelCandidate(posX, posY, scienceMI, referenceMI, ps)
509 kernelCellSet.insertCandidate(kc)
510
511 import lsstDebug
512 display = lsstDebug.Info(__name__).display
513 displaySpatialCells = lsstDebug.Info(__name__).displaySpatialCells
514 maskTransparency = lsstDebug.Info(__name__).maskTransparency
515 if not maskTransparency:
516 maskTransparency = 0
517 if display:
518 afwDisplay.setDefaultMaskTransparency(maskTransparency)
519 if display and displaySpatialCells:
520 dituils.showKernelSpatialCells(exposure.getMaskedImage(), kernelCellSet,
521 symb="o", ctype=afwDisplay.CYAN, ctypeUnused=afwDisplay.YELLOW,
522 ctypeBad=afwDisplay.RED, size=4, frame=lsstDebug.frame,
523 title="Image to be convolved")
524 lsstDebug.frame += 1
525 return pipeBase.Struct(kernelCellSet=kernelCellSet,
526 referencePsfModel=referencePsfModel,
527 )
528
529 def _makePsfMaskedImage(self, psfModel, posX, posY, dimensions=None):
530 """Return a MaskedImage of the a PSF Model of specified dimensions
531 """
532 rawKernel = psfModel.computeKernelImage(geom.Point2D(posX, posY)).convertF()
533 if dimensions is None:
534 dimensions = rawKernel.getDimensions()
535 if rawKernel.getDimensions() == dimensions:
536 kernelIm = rawKernel
537 else:
538 # make image of proper size
539 kernelIm = afwImage.ImageF(dimensions)
540 bboxToPlace = geom.Box2I(geom.Point2I((dimensions.getX() - rawKernel.getWidth())//2,
541 (dimensions.getY() - rawKernel.getHeight())//2),
542 rawKernel.getDimensions())
543 kernelIm.assign(rawKernel, bboxToPlace)
544
545 kernelMask = afwImage.Mask(dimensions, 0x0)
546 kernelVar = afwImage.ImageF(dimensions, 1.0)
547 return afwImage.MaskedImageF(kernelIm, kernelMask, kernelVar)
int max
A polymorphic base class for representing an image's Point Spread Function.
Definition: Psf.h:76
A class to contain the data, WCS, and other information needed to describe an image of the sky.
Definition: Exposure.h:72
Represent a 2-dimensional array of bitmask pixels.
Definition: Mask.h:77
Parameters to control convolution.
Definition: ConvolveImage.h:50
A collection of SpatialCells covering an entire image.
Definition: SpatialCell.h:383
An integer coordinate rectangle.
Definition: Box.h:55
def _makePsfMaskedImage(self, psfModel, posX, posY, dimensions=None)
def run(self, exposure, referencePsfModel, kernelSum=1.0)
def _buildCellSet(self, exposure, referencePsfModel)
def _solve(self, kernelCellSet, basisList, returnOnExcept=False)
Definition: psfMatch.py:881
def mtv(data, frame=None, title="", wcs=None, *args, **kwargs)
Definition: ds9.py:92
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
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.
def makeKernelBasisList(config, targetFwhmPix=None, referenceFwhmPix=None, basisDegGauss=None, basisSigmaGauss=None, metadata=None)