22 __all__ = [
"backgroundSubtract",
"writeKernelCellSet",
"sourceToFootprintList",
"NbasisEvaluator"]
27 from collections
import Counter
31 from .
import diffimLib
41 from .makeKernelBasisList
import makeKernelBasisList
55 rdmImage = img.Factory(img.getDimensions())
61 """Return a Poisson noise image based on im 65 im : `lsst.afw.image.Image` 66 image; the output image has the same dimensions and shape 67 and its expectation value is the value of ``im`` at each pixel 71 noiseIm : `lsst.afw.image.Image` 76 - Warning: This uses an undocumented numpy API (the documented API 77 uses a single float expectation value instead of an array). 79 - Uses numpy.random; you may wish to call numpy.random.seed first. 81 import numpy.random
as rand
83 noiseIm = im.Factory(im.getBBox())
84 noiseArr = noiseIm.getArray()
86 with np.errstate(invalid=
'ignore'):
87 intNoiseArr = rand.poisson(imArr)
89 noiseArr[:, :] = intNoiseArr.astype(noiseArr.dtype)
100 kCoeffs = ((1.0, 0.0, 0.0),
101 (0.005, -0.000001, 0.000001),
102 (0.005, 0.000004, 0.000004),
103 (-0.001, -0.000030, 0.000030),
104 (-0.001, 0.000015, 0.000015),
105 (-0.005, -0.000050, 0.000050))
110 deltaFunctionCounts=1.e4, tGaussianWidth=1.0,
111 addNoise=True, bgValue=100., display=False):
116 sizeCell : `int`, optional 118 nCell : `int`, optional 120 deltaFunctionCounts : `float`, optional 122 tGaussianWidth : `float`, optional 124 addNoise : `bool`, optional 126 bgValue : `float`, optional 128 display : `bool`, optional 136 from .
import imagePsfMatch
138 configFake.kernel.name =
"AL" 139 subconfigFake = configFake.kernel.active
140 subconfigFake.alardNGauss = 1
141 subconfigFake.alardSigGauss = [2.5, ]
142 subconfigFake.alardDegGauss = [2, ]
143 subconfigFake.sizeCellX = sizeCell
144 subconfigFake.sizeCellY = sizeCell
145 subconfigFake.spatialKernelOrder = 1
146 subconfigFake.spatialModelType =
"polynomial" 147 subconfigFake.singleKernelClipping =
False 148 subconfigFake.spatialKernelClipping =
False 150 subconfigFake.fitForBackground =
True 152 policyFake = pexConfig.makePolicy(subconfigFake)
155 kSize = subconfigFake.kernelSize
158 gaussKernelWidth = sizeCell//2
163 spatialKernelWidth = kSize
166 border = (gaussKernelWidth + spatialKernelWidth)//2
169 totalSize = nCell*sizeCell + 2*border
170 tim = afwImage.ImageF(afwGeom.Extent2I(totalSize, totalSize))
171 for x
in range(nCell):
172 for y
in range(nCell):
173 tim[x*sizeCell + sizeCell//2 + border - 1,
174 y*sizeCell + sizeCell//2 + border - 1,
175 afwImage.LOCAL] = deltaFunctionCounts
178 gaussFunction = afwMath.GaussianFunction2D(tGaussianWidth, tGaussianWidth)
180 cim = afwImage.ImageF(tim.getDimensions())
185 bbox = gaussKernel.shrinkBBox(tim.getBBox(afwImage.LOCAL))
186 tim = afwImage.ImageF(tim, bbox, afwImage.LOCAL)
190 polyFunc = afwMath.PolynomialFunction2D(1)
192 nToUse = min(len(kCoeffs), len(basisList))
196 sKernel.setSpatialParameters(kCoeffs[:nToUse])
197 sim = afwImage.ImageF(tim.getDimensions())
201 bbox = sKernel.shrinkBBox(sim.getBBox(afwImage.LOCAL))
207 tim += 2*np.abs(np.min(tim.getArray()))
215 sim = afwImage.ImageF(sim, bbox, afwImage.LOCAL)
216 svar = afwImage.ImageF(sim,
True)
219 sMi = afwImage.MaskedImageF(sim, smask, svar)
221 tim = afwImage.ImageF(tim, bbox, afwImage.LOCAL)
222 tvar = afwImage.ImageF(tim,
True)
225 tMi = afwImage.MaskedImageF(tim, tmask, tvar)
229 afwDisplay.Display(frame=1).mtv(tMi)
230 afwDisplay.Display(frame=2).mtv(sMi)
234 afwGeom.Extent2I(sizeCell*nCell,
238 stampHalfWidth = 2*kSize
239 for x
in range(nCell):
240 for y
in range(nCell):
241 xCoord = x*sizeCell + sizeCell//2
242 yCoord = y*sizeCell + sizeCell//2
243 p0 = afwGeom.Point2I(xCoord - stampHalfWidth,
244 yCoord - stampHalfWidth)
245 p1 = afwGeom.Point2I(xCoord + stampHalfWidth,
246 yCoord + stampHalfWidth)
247 bbox = afwGeom.Box2I(p0, p1)
248 tsi = afwImage.MaskedImageF(tMi, bbox, origin=afwImage.LOCAL)
249 ssi = afwImage.MaskedImageF(sMi, bbox, origin=afwImage.LOCAL)
251 kc = diffimLib.makeKernelCandidate(xCoord, yCoord, tsi, ssi, policyFake)
252 kernelCellSet.insertCandidate(kc)
256 return tMi, sMi, sKernel, kernelCellSet, configFake
264 """Subtract the background from masked images. 268 config : TODO: DM-17458 270 maskedImages : `list` of `lsst.afw.image.MaskedImage` 280 algorithm = config.algorithm
281 binsize = config.binSize
282 undersample = config.undersampleStyle
284 bctrl.setUndersampleStyle(undersample)
285 for maskedImage
in maskedImages:
286 bctrl.setNxSample(maskedImage.getWidth()//binsize + 1)
287 bctrl.setNySample(maskedImage.getHeight()//binsize + 1)
288 image = maskedImage.getImage()
291 image -= backobj.getImageF()
292 backgrounds.append(backobj.getImageF())
296 logger = Log.getLogger(
"ip.diffim.backgroundSubtract")
297 logger.debug(
"Total time for background subtraction : %.2f s", (t1 - t0))
310 kernelCellSet : TODO: DM-17458 312 psfMatchingKernel : TODO: DM-17458 314 backgroundModel : TODO: DM-17458 316 outdir : TODO: DM-17458 319 if not os.path.isdir(outdir):
322 for cell
in kernelCellSet.getCellList():
323 for cand
in cell.begin(
False):
324 if cand.getStatus() == afwMath.SpatialCellCandidate.GOOD:
325 xCand = int(cand.getXCenter())
326 yCand = int(cand.getYCenter())
327 idCand = cand.getId()
328 diffIm = cand.getDifferenceImage(diffimLib.KernelCandidateF.ORIG)
329 kernel = cand.getKernelImage(diffimLib.KernelCandidateF.ORIG)
330 diffIm.writeFits(os.path.join(outdir,
'diffim_c%d_x%d_y%d.fits' % (idCand, xCand, yCand)))
331 kernel.writeFits(os.path.join(outdir,
'kernel_c%d_x%d_y%d.fits' % (idCand, xCand, yCand)))
334 ski = afwImage.ImageD(kernel.getDimensions())
335 psfMatchingKernel.computeImage(ski,
False, xCand, yCand)
337 sbg = backgroundModel(xCand, yCand)
338 sdmi = cand.getDifferenceImage(sk, sbg)
339 sdmi.writeFits(os.path.join(outdir,
'sdiffim_c%d_x%d_y%d.fits' % (idCand, xCand, yCand)))
347 """Convert a list of sources for the PSF-matching Kernel to Footprints. 351 candidateInList : TODO: DM-17458 352 Input list of Sources 353 templateExposure : TODO: DM-17458 354 Template image, to be checked for Mask bits in Source Footprint 355 scienceExposure : TODO: DM-17458 356 Science image, to be checked for Mask bits in Source Footprint 357 kernelSize : TODO: DM-17458 359 config : TODO: DM-17458 360 Config that defines the Mask planes that indicate an invalid Source and Bbox grow radius 366 candidateOutList : `list` 367 a list of dicts having a "source" and "footprint" field, to be used for Psf-matching 376 Takes an input list of Sources that were selected to constrain 377 the Psf-matching Kernel and turns them into a List of Footprints, 378 which are used to seed a set of KernelCandidates. The function 379 checks both the template and science image for masked pixels, 380 rejecting the Source if certain Mask bits (defined in config) are 381 set within the Footprint. 384 candidateOutList = []
385 fsb = diffimLib.FindSetBitsU()
387 for mp
in config.badMaskPlanes:
388 badBitMask |= afwImage.Mask.getPlaneBitMask(mp)
389 bbox = scienceExposure.getBBox()
392 if config.scaleByFwhm:
393 fpGrowPix = int(config.fpGrowKernelScaling*kernelSize + 0.5)
395 fpGrowPix = config.fpGrowPix
396 log.info(
"Growing %d kernel candidate stars by %d pixels", len(candidateInList), fpGrowPix)
398 for kernelCandidate
in candidateInList:
399 if not type(kernelCandidate) == afwTable.SourceRecord:
400 raise RuntimeError(
"Candiate not of type afwTable.SourceRecord")
403 center = afwGeom.Point2I(scienceExposure.getWcs().skyToPixel(kernelCandidate.getCoord()))
404 if center[0] < bbox.getMinX()
or center[0] > bbox.getMaxX():
406 if center[1] < bbox.getMinY()
or center[1] > bbox.getMaxY():
409 xmin = center[0] - fpGrowPix
410 xmax = center[0] + fpGrowPix
411 ymin = center[1] - fpGrowPix
412 ymax = center[1] + fpGrowPix
415 if (xmin - bbox.getMinX()) < 0:
416 xmax += (xmin - bbox.getMinX())
417 xmin -= (xmin - bbox.getMinX())
418 if (ymin - bbox.getMinY()) < 0:
419 ymax += (ymin - bbox.getMinY())
420 ymin -= (ymin - bbox.getMinY())
421 if (bbox.getMaxX() - xmax) < 0:
422 xmin -= (bbox.getMaxX() - xmax)
423 xmax += (bbox.getMaxX() - xmax)
424 if (bbox.getMaxY() - ymax) < 0:
425 ymin -= (bbox.getMaxY() - ymax)
426 ymax += (bbox.getMaxY() - ymax)
427 if xmin > xmax
or ymin > ymax:
430 kbbox = afwGeom.Box2I(afwGeom.Point2I(xmin, ymin), afwGeom.Point2I(xmax, ymax))
432 fsb.apply(afwImage.MaskedImageF(templateExposure.getMaskedImage(), kbbox, deep=
False).getMask())
434 fsb.apply(afwImage.MaskedImageF(scienceExposure.getMaskedImage(), kbbox, deep=
False).getMask())
439 if not((bm1 & badBitMask)
or (bm2 & badBitMask)):
440 candidateOutList.append({
'source': kernelCandidate,
442 log.info(
"Selected %d / %d sources for KernelCandidacy", len(candidateOutList), len(candidateInList))
443 return candidateOutList
447 basisList, doBuild=False):
448 """Convert a list of Sources into KernelCandidates. 450 The KernelCandidates are used for fitting the Psf-matching kernel. 454 sourceTable : TODO: DM-17458 456 templateExposure : TODO: DM-17458 458 scienceExposure : TODO: DM-17458 460 kConfig : TODO: DM-17458 462 dConfig : TODO: DM-17458 466 basisList : TODO: DM-17458 468 doBuild : `bool`, optional 476 kernelSize = basisList[0].getWidth()
478 kernelSize, dConfig, log)
481 if doBuild
and not basisList:
484 policy = pexConfig.makePolicy(kConfig)
485 visitor = diffimLib.BuildSingleKernelVisitorF(basisList, policy)
487 policy = pexConfig.makePolicy(kConfig)
488 for cand
in footprintList:
489 bbox = cand[
'footprint'].getBBox()
490 tmi = afwImage.MaskedImageF(templateExposure.getMaskedImage(), bbox)
491 smi = afwImage.MaskedImageF(scienceExposure.getMaskedImage(), bbox)
492 kCand = diffimLib.makeKernelCandidate(cand[
'source'], tmi, smi, policy)
494 visitor.processCandidate(kCand)
495 kCand.setStatus(afwMath.SpatialCellCandidate.UNKNOWN)
496 candList.append(kCand)
506 """A functor to evaluate the Bayesian Information Criterion for the number of basis sets 507 going into the kernel fitting""" 509 def __init__(self, psfMatchConfig, psfFwhmPixTc, psfFwhmPixTnc):
514 raise RuntimeError(
"BIC only implemnted for AL (alard lupton) basis")
519 for d1i
in range(1, d1 + 1):
520 for d2i
in range(1, d2 + 1):
521 for d3i
in range(1, d3 + 1):
522 dList = [d1i, d2i, d3i]
526 visitor = diffimLib.BuildSingleKernelVisitorF(kList, pexConfig.makePolicy(bicConfig))
527 visitor.setSkipBuilt(
False)
528 kernelCellSet.visitCandidates(visitor, bicConfig.nStarPerCell)
530 for cell
in kernelCellSet.getCellList():
531 for cand
in cell.begin(
False):
532 if cand.getStatus() != afwMath.SpatialCellCandidate.GOOD:
534 diffIm = cand.getDifferenceImage(diffimLib.KernelCandidateF.RECENT)
535 bbox = cand.getKernel(diffimLib.KernelCandidateF.RECENT).shrinkBBox(
536 diffIm.getBBox(afwImage.LOCAL))
537 diffIm = type(diffIm)(diffIm, bbox,
True)
538 chi2 = diffIm.getImage().getArray()**2/diffIm.getVariance().getArray()
539 n = chi2.shape[0]*chi2.shape[1]
540 bic = np.sum(chi2) + k*np.log(n)
541 if cand.getId()
not in bicArray:
542 bicArray[cand.getId()] = {}
543 bicArray[cand.getId()][(d1i, d2i, d3i)] = bic
546 for candId
in bicArray:
547 cconfig, cvals = list(bicArray[candId].keys()), list(bicArray[candId].values())
548 idx = np.argsort(cvals)
549 bestConfig = cconfig[idx[0]]
550 bestConfigs.append(bestConfig)
552 counter = Counter(bestConfigs).most_common(3)
553 log.info(
"B.I.C. prefers basis complexity %s %d times; %s %d times; %s %d times",
554 counter[0][0], counter[0][1],
555 counter[1][0], counter[1][1],
556 counter[2][0], counter[2][1])
557 return counter[0][0], counter[1][0], counter[2][0]
def makeKernelBasisList(config, targetFwhmPix=None, referenceFwhmPix=None, basisDegGauss=None, metadata=None)
std::shared_ptr< Background > makeBackground(ImageT const &img, BackgroundControl const &bgCtrl)
Statistics makeStatistics(lsst::afw::math::MaskedVector< EntryT > const &mv, std::vector< WeightPixel > const &vweights, int const flags, StatisticsControl const &sctrl=StatisticsControl())
void randomGaussianImage(ImageT *image, Random &rand)
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, bool doNormalize, bool doCopyEdge=false)