23 __all__ = [
"backgroundSubtract",
"writeKernelCellSet",
"sourceToFootprintList",
"NbasisEvaluator"]
28 from collections
import Counter
32 from .
import diffimLib
42 from .makeKernelBasisList
import makeKernelBasisList
56 rdmImage = img.Factory(img.getDimensions())
62 """Return a Poisson noise image based on im 66 im : `lsst.afw.image.Image` 67 image; the output image has the same dimensions and shape 68 and its expectation value is the value of im at each pixel 72 noiseIm : 'lsst.afw.image.Image' 78 - Warning: This uses an undocumented numpy API (the documented API 79 uses a single float expectation value instead of an array). 81 - Uses numpy.random; you may wish to call numpy.random.seed first. 83 import numpy.random
as rand
85 noiseIm = im.Factory(im.getBBox())
86 noiseArr = noiseIm.getArray()
88 with np.errstate(invalid=
'ignore'):
89 intNoiseArr = rand.poisson(imArr)
91 noiseArr[:, :] = intNoiseArr.astype(noiseArr.dtype)
102 kCoeffs = ((1.0, 0.0, 0.0),
103 (0.005, -0.000001, 0.000001),
104 (0.005, 0.000004, 0.000004),
105 (-0.001, -0.000030, 0.000030),
106 (-0.001, 0.000015, 0.000015),
107 (-0.005, -0.000050, 0.000050))
112 deltaFunctionCounts=1.e4, tGaussianWidth=1.0,
113 addNoise=True, bgValue=100., display=False):
118 sizeCell : `int`, optional 120 nCell : `int`, optional 122 deltaFunctionCounts : `float`, optional 124 tGaussianWidth : `float`, optional 126 addNoise : `bool`, optional 128 bgValue : `float`, optional 130 display : `bool`, optional 138 from .
import imagePsfMatch
140 configFake.kernel.name =
"AL" 141 subconfigFake = configFake.kernel.active
142 subconfigFake.alardNGauss = 1
143 subconfigFake.alardSigGauss = [2.5, ]
144 subconfigFake.alardDegGauss = [2, ]
145 subconfigFake.sizeCellX = sizeCell
146 subconfigFake.sizeCellY = sizeCell
147 subconfigFake.spatialKernelOrder = 1
148 subconfigFake.spatialModelType =
"polynomial" 149 subconfigFake.singleKernelClipping =
False 150 subconfigFake.spatialKernelClipping =
False 152 subconfigFake.fitForBackground =
True 154 policyFake = pexConfig.makePolicy(subconfigFake)
157 kSize = subconfigFake.kernelSize
160 gaussKernelWidth = sizeCell//2
165 spatialKernelWidth = kSize
168 border = (gaussKernelWidth + spatialKernelWidth)//2
171 totalSize = nCell * sizeCell + 2*border
173 for x
in range(nCell):
174 for y
in range(nCell):
175 tim[x*sizeCell + sizeCell//2 + border - 1,
176 y*sizeCell + sizeCell//2 + border - 1,
177 afwImage.LOCAL] = deltaFunctionCounts
180 gaussFunction = afwMath.GaussianFunction2D(tGaussianWidth, tGaussianWidth)
182 cim = afwImage.ImageF(tim.getDimensions())
187 bbox = gaussKernel.shrinkBBox(tim.getBBox(afwImage.LOCAL))
188 tim = afwImage.ImageF(tim, bbox, afwImage.LOCAL)
192 polyFunc = afwMath.PolynomialFunction2D(1)
194 nToUse =
min(len(kCoeffs), len(basisList))
198 sKernel.setSpatialParameters(kCoeffs[:nToUse])
199 sim = afwImage.ImageF(tim.getDimensions())
203 bbox = sKernel.shrinkBBox(sim.getBBox(afwImage.LOCAL))
209 tim += 2 * np.abs(np.min(tim.getArray()))
217 sim = afwImage.ImageF(sim, bbox, afwImage.LOCAL)
218 svar = afwImage.ImageF(sim,
True)
221 sMi = afwImage.MaskedImageF(sim, smask, svar)
223 tim = afwImage.ImageF(tim, bbox, afwImage.LOCAL)
224 tvar = afwImage.ImageF(tim,
True)
227 tMi = afwImage.MaskedImageF(tim, tmask, tvar)
231 ds9.mtv(tMi, frame=1)
232 ds9.mtv(sMi, frame=2)
240 stampHalfWidth = 2 * kSize
241 for x
in range(nCell):
242 for y
in range(nCell):
243 xCoord = x * sizeCell + sizeCell // 2
244 yCoord = y * sizeCell + sizeCell // 2
246 yCoord - stampHalfWidth)
248 yCoord + stampHalfWidth)
250 tsi = afwImage.MaskedImageF(tMi, bbox, origin=afwImage.LOCAL)
251 ssi = afwImage.MaskedImageF(sMi, bbox, origin=afwImage.LOCAL)
253 kc = diffimLib.makeKernelCandidate(xCoord, yCoord, tsi, ssi, policyFake)
254 kernelCellSet.insertCandidate(kc)
258 return tMi, sMi, sKernel, kernelCellSet, configFake
266 """Subtract the background from masked images. 270 config : TODO: DM-17458 272 maskedImages : `list` of `lsst.afw.image.MaskedImage` 282 algorithm = config.algorithm
283 binsize = config.binSize
284 undersample = config.undersampleStyle
286 bctrl.setUndersampleStyle(undersample)
287 for maskedImage
in maskedImages:
288 bctrl.setNxSample(maskedImage.getWidth()//binsize + 1)
289 bctrl.setNySample(maskedImage.getHeight()//binsize + 1)
290 image = maskedImage.getImage()
293 image -= backobj.getImageF()
294 backgrounds.append(backobj.getImageF())
298 logger = Log.getLogger(
"ip.diffim.backgroundSubtract")
299 logger.debug(
"Total time for background subtraction : %.2f s", (t1-t0))
312 kernelCellSet : TODO: DM-17458 314 psfMatchingKernel : TODO: DM-17458 316 backgroundModel : TODO: DM-17458 318 outdir : TODO: DM-17458 321 if not os.path.isdir(outdir):
324 for cell
in kernelCellSet.getCellList():
325 for cand
in cell.begin(
False):
326 if cand.getStatus() == afwMath.SpatialCellCandidate.GOOD:
327 xCand =
int(cand.getXCenter())
328 yCand =
int(cand.getYCenter())
329 idCand = cand.getId()
330 diffIm = cand.getDifferenceImage(diffimLib.KernelCandidateF.ORIG)
331 kernel = cand.getKernelImage(diffimLib.KernelCandidateF.ORIG)
332 diffIm.writeFits(os.path.join(outdir,
'diffim_c%d_x%d_y%d.fits' % (idCand, xCand, yCand)))
333 kernel.writeFits(os.path.join(outdir,
'kernel_c%d_x%d_y%d.fits' % (idCand, xCand, yCand)))
336 ski = afwImage.ImageD(kernel.getDimensions())
337 psfMatchingKernel.computeImage(ski,
False, xCand, yCand)
339 sbg = backgroundModel(xCand, yCand)
340 sdmi = cand.getDifferenceImage(sk, sbg)
341 sdmi.writeFits(os.path.join(outdir,
'sdiffim_c%d_x%d_y%d.fits' % (idCand, xCand, yCand)))
349 """Convert a list of sources for the PSF-matching Kernel to Footprints. 353 candidateInList : TODO: DM-17458 354 Input list of Sources 355 templateExposure : TODO: DM-17458 356 Template image, to be checked for Mask bits in Source Footprint 357 scienceExposure : TODO: DM-17458 358 Science image, to be checked for Mask bits in Source Footprint 359 kernelSize : TODO: DM-17458 361 config : TODO: DM-17458 362 Config that defines the Mask planes that indicate an invalid Source and Bbox grow radius 368 candidateOutList : `list` 369 a list of dicts having a "source" and "footprint" field, to be used for Psf-matching 378 Takes an input list of Sources that were selected to constrain 379 the Psf-matching Kernel and turns them into a List of Footprints, 380 which are used to seed a set of KernelCandidates. The function 381 checks both the template and science image for masked pixels, 382 rejecting the Source if certain Mask bits (defined in config) are 383 set within the Footprint. 386 candidateOutList = []
387 fsb = diffimLib.FindSetBitsU()
389 for mp
in config.badMaskPlanes:
390 badBitMask |= afwImage.Mask.getPlaneBitMask(mp)
391 bbox = scienceExposure.getBBox()
394 if config.scaleByFwhm:
395 fpGrowPix =
int(config.fpGrowKernelScaling * kernelSize + 0.5)
397 fpGrowPix = config.fpGrowPix
398 log.info(
"Growing %d kernel candidate stars by %d pixels", len(candidateInList), fpGrowPix)
400 for kernelCandidate
in candidateInList:
402 raise RuntimeError(
"Candiate not of type afwTable.SourceRecord")
405 center =
afwGeom.Point2I(scienceExposure.getWcs().skyToPixel(kernelCandidate.getCoord()))
406 if center[0] < bbox.getMinX()
or center[0] > bbox.getMaxX():
408 if center[1] < bbox.getMinY()
or center[1] > bbox.getMaxY():
411 xmin = center[0] - fpGrowPix
412 xmax = center[0] + fpGrowPix
413 ymin = center[1] - fpGrowPix
414 ymax = center[1] + fpGrowPix
417 if (xmin - bbox.getMinX()) < 0:
418 xmax += (xmin - bbox.getMinX())
419 xmin -= (xmin - bbox.getMinX())
420 if (ymin - bbox.getMinY()) < 0:
421 ymax += (ymin - bbox.getMinY())
422 ymin -= (ymin - bbox.getMinY())
423 if (bbox.getMaxX() - xmax) < 0:
424 xmin -= (bbox.getMaxX() - xmax)
425 xmax += (bbox.getMaxX() - xmax)
426 if (bbox.getMaxY() - ymax) < 0:
427 ymin -= (bbox.getMaxY() - ymax)
428 ymax += (bbox.getMaxY() - ymax)
429 if xmin > xmax
or ymin > ymax:
434 fsb.apply(afwImage.MaskedImageF(templateExposure.getMaskedImage(), kbbox, deep=
False).getMask())
436 fsb.apply(afwImage.MaskedImageF(scienceExposure.getMaskedImage(), kbbox, deep=
False).getMask())
441 if not((bm1 & badBitMask)
or (bm2 & badBitMask)):
442 candidateOutList.append({
'source': kernelCandidate,
444 log.info(
"Selected %d / %d sources for KernelCandidacy", len(candidateOutList), len(candidateInList))
445 return candidateOutList
449 basisList, doBuild=False):
450 """Convert a list of Sources into KernelCandidates. 452 The KernelCandidates are used for fitting the Psf-matching kernel. 456 sourceTable : TODO: DM-17458 458 templateExposure : TODO: DM-17458 460 scienceExposure : TODO: DM-17458 462 kConfig : TODO: DM-17458 464 dConfig : TODO: DM-17458 468 basisList : TODO: DM-17458 470 doBuild : `bool`, optional 478 kernelSize = basisList[0].getWidth()
480 kernelSize, dConfig, log)
483 if doBuild
and not basisList:
486 policy = pexConfig.makePolicy(kConfig)
487 visitor = diffimLib.BuildSingleKernelVisitorF(basisList, policy)
489 policy = pexConfig.makePolicy(kConfig)
490 for cand
in footprintList:
491 bbox = cand[
'footprint'].getBBox()
492 tmi = afwImage.MaskedImageF(templateExposure.getMaskedImage(), bbox)
493 smi = afwImage.MaskedImageF(scienceExposure.getMaskedImage(), bbox)
494 kCand = diffimLib.makeKernelCandidate(cand[
'source'], tmi, smi, policy)
496 visitor.processCandidate(kCand)
497 kCand.setStatus(afwMath.SpatialCellCandidate.UNKNOWN)
498 candList.append(kCand)
508 """A functor to evaluate the Bayesian Information Criterion for the number of basis sets 509 going into the kernel fitting""" 511 def __init__(self, psfMatchConfig, psfFwhmPixTc, psfFwhmPixTnc):
516 raise RuntimeError(
"BIC only implemnted for AL (alard lupton) basis")
521 for d1i
in range(1, d1+1):
522 for d2i
in range(1, d2+1):
523 for d3i
in range(1, d3+1):
524 dList = [d1i, d2i, d3i]
528 visitor = diffimLib.BuildSingleKernelVisitorF(kList, pexConfig.makePolicy(bicConfig))
529 visitor.setSkipBuilt(
False)
530 kernelCellSet.visitCandidates(visitor, bicConfig.nStarPerCell)
532 for cell
in kernelCellSet.getCellList():
533 for cand
in cell.begin(
False):
534 if cand.getStatus() != afwMath.SpatialCellCandidate.GOOD:
536 diffIm = cand.getDifferenceImage(diffimLib.KernelCandidateF.RECENT)
537 bbox = cand.getKernel(diffimLib.KernelCandidateF.RECENT).shrinkBBox(
538 diffIm.getBBox(afwImage.LOCAL))
539 diffIm =
type(diffIm)(diffIm, bbox,
True)
540 chi2 = diffIm.getImage().getArray()**2 / diffIm.getVariance().getArray()
541 n = chi2.shape[0] * chi2.shape[1]
542 bic = np.sum(chi2) + k * np.log(n)
543 if cand.getId()
not in bicArray:
544 bicArray[cand.getId()] = {}
545 bicArray[cand.getId()][(d1i, d2i, d3i)] = bic
548 for candId
in bicArray:
549 cconfig, cvals =
list(bicArray[candId].
keys()),
list(bicArray[candId].values())
550 idx = np.argsort(cvals)
551 bestConfig = cconfig[idx[0]]
552 bestConfigs.append(bestConfig)
554 counter = Counter(bestConfigs).most_common(3)
555 log.info(
"B.I.C. prefers basis complexity %s %d times; %s %d times; %s %d times",
556 counter[0][0], counter[0][1],
557 counter[1][0], counter[1][1],
558 counter[2][0], counter[2][1])
559 return counter[0][0], counter[1][0], counter[2][0]
def makeKernelBasisList(config, targetFwhmPix=None, referenceFwhmPix=None, basisDegGauss=None, metadata=None)
A compact representation of a collection of pixels.
std::shared_ptr< Background > makeBackground(ImageT const &img, BackgroundControl const &bgCtrl)
A convenience function that uses function overloading to make the correct type of Background...
Pass parameters to a Background object.
Statistics makeStatistics(lsst::afw::math::MaskedVector< EntryT > const &mv, std::vector< WeightPixel > const &vweights, int const flags, StatisticsControl const &sctrl=StatisticsControl())
The makeStatistics() overload to handle lsst::afw::math::MaskedVector<>
A collection of SpatialCells covering an entire image.
Represent a 2-dimensional array of bitmask pixels.
A kernel that is a linear combination of fixed basis kernels.
void randomGaussianImage(ImageT *image, Random &rand)
Set image to random numbers with a gaussian N(0, 1) distribution.
Record class that contains measurements made on a single exposure.
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, bool doNormalize, bool doCopyEdge=false)
Old, deprecated version of convolve.
A kernel described by a function.
An integer coordinate rectangle.
daf::base::PropertyList * list
A class that can be used to generate sequences of random numbers according to a number of different a...
A kernel created from an Image.