22 __all__ = [
"backgroundSubtract", 
"writeKernelCellSet", 
"sourceToFootprintList", 
"NbasisEvaluator"]
 
   27 from collections 
import Counter
 
   31 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 dtype, dimensions, and shape 
   68         and its expectation value is the value of ``im`` at each pixel 
   72     noiseIm : `lsst.afw.image.Image` 
   73         Newly constructed image instance, same type as ``im``. 
   77     - Warning: This uses an undocumented numpy API (the documented API 
   78         uses a single float expectation value instead of an array). 
   80     - Uses numpy.random; you may wish to call numpy.random.seed first. 
   82     import numpy.random 
as rand
 
   84     noiseIm = im.Factory(im.getBBox())
 
   85     noiseArr = noiseIm.getArray()
 
   87     intNoiseArr = rand.poisson(np.where(np.isfinite(imArr), imArr, 0.0))
 
   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):
 
  112     """Generate test template and science images with sources. 
  116     sizeCell : `int`, optional 
  117         Size of the square spatial cells in pixels. 
  118     nCell : `int`, optional 
  119         Number of adjacent spatial cells in both direction in both images. 
  120     deltaFunctionCounts : `float`, optional 
  121         Flux value for the template image sources. 
  122     tGaussianWidth : `float`, optional 
  123         Sigma of the generated Gaussian PSF sources in the template image. 
  124     addNoise : `bool`, optional 
  125         If `True`, Poisson noise is added to both the generated template 
  127     bgValue : `float`, optional 
  128         Background level to be added to the generated science image. 
  129     display : `bool`, optional 
  130         If `True` displays the generated template and science images by 
  131         `lsst.afw.display.Display`. 
  135     - The generated images consist of adjacent ``nCell x nCell`` cells, each 
  136       of pixel size ``sizeCell x sizeCell``. 
  137     - The sources in the science image are generated by convolving the 
  138       template by ``sKernel``. ``sKernel`` is a spatial `LinearCombinationKernel` 
  139       of hard wired kernel bases functions. The linear combination has first 
  140       order polynomial spatial dependence with polynomial parameters from ``fakeCoeffs()``. 
  141     - The template image sources are generated in the center of each spatial 
  142       cell from one pixel, set to `deltaFunctionCounts` counts, then convolved 
  143       by a 2D Gaussian with sigma of `tGaussianWidth` along each axis. 
  144     - The sources are also returned in ``kernelCellSet`` each source is "detected" 
  145       exactly at the center of a cell. 
  149     tMi : `lsst.afw.image.MaskedImage` 
  150         Generated template image. 
  151     sMi : `lsst.afw.image.MaskedImage` 
  152         Generated science image. 
  153     sKernel : `lsst.afw.math.LinearCombinationKernel` 
  154         The spatial kernel used to generate the sources in the science image. 
  155     kernelCellSet : `lsst.afw.math.SpatialCellSet` 
  156         Cell grid of `lsst.afw.math.SpatialCell` instances, containing 
  157         `lsst.ip.diffim.KernelCandidate` instances around all the generated sources 
  158         in the science image. 
  159     configFake : `lsst.ip.diffim.ImagePsfMatchConfig` 
  160         Config instance used in the image generation. 
  162     from . 
import imagePsfMatch
 
  164     configFake.kernel.name = 
"AL" 
  165     subconfigFake = configFake.kernel.active
 
  166     subconfigFake.alardNGauss = 1
 
  167     subconfigFake.alardSigGauss = [2.5, ]
 
  168     subconfigFake.alardDegGauss = [2, ]
 
  169     subconfigFake.sizeCellX = sizeCell
 
  170     subconfigFake.sizeCellY = sizeCell
 
  171     subconfigFake.spatialKernelOrder = 1
 
  172     subconfigFake.spatialModelType = 
"polynomial" 
  173     subconfigFake.singleKernelClipping = 
False    
  174     subconfigFake.spatialKernelClipping = 
False   
  176         subconfigFake.fitForBackground = 
True 
  178     psFake = pexConfig.makePropertySet(subconfigFake)
 
  181     kSize = subconfigFake.kernelSize
 
  184     gaussKernelWidth = sizeCell//2
 
  189     spatialKernelWidth = kSize
 
  192     border = (gaussKernelWidth + spatialKernelWidth)//2
 
  195     totalSize = nCell*sizeCell + 2*border
 
  197     for x 
in range(nCell):
 
  198         for y 
in range(nCell):
 
  199             tim[x*sizeCell + sizeCell//2 + border - 1,
 
  200                 y*sizeCell + sizeCell//2 + border - 1,
 
  201                 afwImage.LOCAL] = deltaFunctionCounts
 
  204     gaussFunction = afwMath.GaussianFunction2D(tGaussianWidth, tGaussianWidth)
 
  206     cim = afwImage.ImageF(tim.getDimensions())
 
  208     convolutionControl.setDoNormalize(
True)
 
  213     bbox = gaussKernel.shrinkBBox(tim.getBBox(afwImage.LOCAL))
 
  214     tim = afwImage.ImageF(tim, bbox, afwImage.LOCAL)
 
  218     polyFunc = afwMath.PolynomialFunction2D(1)
 
  220     nToUse = 
min(len(kCoeffs), len(basisList))
 
  224     sKernel.setSpatialParameters(kCoeffs[:nToUse])
 
  225     sim = afwImage.ImageF(tim.getDimensions())
 
  227     convolutionControl.setDoNormalize(
True)
 
  231     bbox = sKernel.shrinkBBox(sim.getBBox(afwImage.LOCAL))
 
  237     tim += 2*np.abs(np.min(tim.getArray()))
 
  245     sim = afwImage.ImageF(sim, bbox, afwImage.LOCAL)
 
  246     svar = afwImage.ImageF(sim, 
True)
 
  249     sMi = afwImage.MaskedImageF(sim, smask, svar)
 
  251     tim = afwImage.ImageF(tim, bbox, afwImage.LOCAL)
 
  252     tvar = afwImage.ImageF(tim, 
True)
 
  255     tMi = afwImage.MaskedImageF(tim, tmask, tvar)
 
  259         afwDisplay.Display(frame=1).
mtv(tMi)
 
  260         afwDisplay.Display(frame=2).
mtv(sMi)
 
  268     stampHalfWidth = 2*kSize
 
  269     for x 
in range(nCell):
 
  270         for y 
in range(nCell):
 
  271             xCoord = x*sizeCell + sizeCell//2
 
  272             yCoord = y*sizeCell + sizeCell//2
 
  274                               yCoord - stampHalfWidth)
 
  276                               yCoord + stampHalfWidth)
 
  278             tsi = afwImage.MaskedImageF(tMi, bbox, origin=afwImage.LOCAL)
 
  279             ssi = afwImage.MaskedImageF(sMi, bbox, origin=afwImage.LOCAL)
 
  281             kc = diffimLib.makeKernelCandidate(xCoord, yCoord, tsi, ssi, psFake)
 
  282             kernelCellSet.insertCandidate(kc)
 
  286     return tMi, sMi, sKernel, kernelCellSet, configFake
 
  294     """Subtract the background from masked images. 
  298     config : TODO: DM-17458 
  300     maskedImages : `list` of `lsst.afw.image.MaskedImage` 
  310     algorithm = config.algorithm
 
  311     binsize = config.binSize
 
  312     undersample = config.undersampleStyle
 
  314     bctrl.setUndersampleStyle(undersample)
 
  315     for maskedImage 
in maskedImages:
 
  316         bctrl.setNxSample(maskedImage.getWidth()//binsize + 1)
 
  317         bctrl.setNySample(maskedImage.getHeight()//binsize + 1)
 
  318         image = maskedImage.getImage()
 
  321         image -= backobj.getImageF()
 
  322         backgrounds.append(backobj.getImageF())
 
  326     logger = Log.getLogger(
"lsst.ip.diffim.backgroundSubtract")
 
  327     logger.debug(
"Total time for background subtraction : %.2f s", (t1 - t0))
 
  340     kernelCellSet : TODO: DM-17458 
  342     psfMatchingKernel : TODO: DM-17458 
  344     backgroundModel : TODO: DM-17458 
  346     outdir : TODO: DM-17458 
  349     if not os.path.isdir(outdir):
 
  352     for cell 
in kernelCellSet.getCellList():
 
  353         for cand 
in cell.begin(
False):  
 
  354             if cand.getStatus() == afwMath.SpatialCellCandidate.GOOD:
 
  355                 xCand = int(cand.getXCenter())
 
  356                 yCand = int(cand.getYCenter())
 
  357                 idCand = cand.getId()
 
  358                 diffIm = cand.getDifferenceImage(diffimLib.KernelCandidateF.ORIG)
 
  359                 kernel = cand.getKernelImage(diffimLib.KernelCandidateF.ORIG)
 
  360                 diffIm.writeFits(os.path.join(outdir, 
'diffim_c%d_x%d_y%d.fits' % (idCand, xCand, yCand)))
 
  361                 kernel.writeFits(os.path.join(outdir, 
'kernel_c%d_x%d_y%d.fits' % (idCand, xCand, yCand)))
 
  364                 ski = afwImage.ImageD(kernel.getDimensions())
 
  365                 psfMatchingKernel.computeImage(ski, 
False, xCand, yCand)
 
  367                 sbg = backgroundModel(xCand, yCand)
 
  368                 sdmi = cand.getDifferenceImage(sk, sbg)
 
  369                 sdmi.writeFits(os.path.join(outdir, 
'sdiffim_c%d_x%d_y%d.fits' % (idCand, xCand, yCand)))
 
  377     """Convert a list of sources for the PSF-matching Kernel to Footprints. 
  381     candidateInList : TODO: DM-17458 
  382         Input list of Sources 
  383     templateExposure : TODO: DM-17458 
  384         Template image, to be checked for Mask bits in Source Footprint 
  385     scienceExposure : TODO: DM-17458 
  386         Science image, to be checked for Mask bits in Source Footprint 
  387     kernelSize : TODO: DM-17458 
  389     config : TODO: DM-17458 
  390         Config that defines the Mask planes that indicate an invalid Source and Bbox grow radius 
  396     candidateOutList : `list` 
  397         a list of dicts having a "source" and "footprint" field, to be used for Psf-matching 
  406     Takes an input list of Sources that were selected to constrain 
  407     the Psf-matching Kernel and turns them into a List of Footprints, 
  408     which are used to seed a set of KernelCandidates.  The function 
  409     checks both the template and science image for masked pixels, 
  410     rejecting the Source if certain Mask bits (defined in config) are 
  411     set within the Footprint. 
  414     candidateOutList = []
 
  415     fsb = diffimLib.FindSetBitsU()
 
  417     for mp 
in config.badMaskPlanes:
 
  418         badBitMask |= afwImage.Mask.getPlaneBitMask(mp)
 
  419     bbox = scienceExposure.getBBox()
 
  422     if config.scaleByFwhm:
 
  423         fpGrowPix = int(config.fpGrowKernelScaling*kernelSize + 0.5)
 
  425         fpGrowPix = config.fpGrowPix
 
  426     log.info(
"Growing %d kernel candidate stars by %d pixels", len(candidateInList), fpGrowPix)
 
  428     for kernelCandidate 
in candidateInList:
 
  430             raise RuntimeError(
"Candiate not of type afwTable.SourceRecord")
 
  433         center = 
geom.Point2I(scienceExposure.getWcs().skyToPixel(kernelCandidate.getCoord()))
 
  434         if center[0] < bbox.getMinX() 
or center[0] > bbox.getMaxX():
 
  436         if center[1] < bbox.getMinY() 
or center[1] > bbox.getMaxY():
 
  439         xmin = center[0] - fpGrowPix
 
  440         xmax = center[0] + fpGrowPix
 
  441         ymin = center[1] - fpGrowPix
 
  442         ymax = center[1] + fpGrowPix
 
  445         if (xmin - bbox.getMinX()) < 0:
 
  446             xmax += (xmin - bbox.getMinX())
 
  447             xmin -= (xmin - bbox.getMinX())
 
  448         if (ymin - bbox.getMinY()) < 0:
 
  449             ymax += (ymin - bbox.getMinY())
 
  450             ymin -= (ymin - bbox.getMinY())
 
  451         if (bbox.getMaxX() - xmax) < 0:
 
  452             xmin -= (bbox.getMaxX() - xmax)
 
  453             xmax += (bbox.getMaxX() - xmax)
 
  454         if (bbox.getMaxY() - ymax) < 0:
 
  455             ymin -= (bbox.getMaxY() - ymax)
 
  456             ymax += (bbox.getMaxY() - ymax)
 
  457         if xmin > xmax 
or ymin > ymax:
 
  462             fsb.apply(afwImage.MaskedImageF(templateExposure.getMaskedImage(), kbbox, deep=
False).getMask())
 
  464             fsb.apply(afwImage.MaskedImageF(scienceExposure.getMaskedImage(), kbbox, deep=
False).getMask())
 
  469             if not((bm1 & badBitMask) 
or (bm2 & badBitMask)):
 
  470                 candidateOutList.append({
'source': kernelCandidate,
 
  472     log.info(
"Selected %d / %d sources for KernelCandidacy", len(candidateOutList), len(candidateInList))
 
  473     return candidateOutList
 
  477                                basisList, doBuild=False):
 
  478     """Convert a list of Sources into KernelCandidates. 
  480     The KernelCandidates are used for fitting the Psf-matching kernel. 
  484     sourceTable : TODO: DM-17458 
  486     templateExposure : TODO: DM-17458 
  488     scienceExposure : TODO: DM-17458 
  490     kConfig : TODO: DM-17458 
  492     dConfig : TODO: DM-17458 
  496     basisList : TODO: DM-17458 
  498     doBuild : `bool`, optional 
  506     kernelSize = basisList[0].getWidth()
 
  508                                           kernelSize, dConfig, log)
 
  511     if doBuild 
and not basisList:
 
  514         ps = pexConfig.makePropertySet(kConfig)
 
  515         visitor = diffimLib.BuildSingleKernelVisitorF(basisList, ps)
 
  517     ps = pexConfig.makePropertySet(kConfig)
 
  518     for cand 
in footprintList:
 
  519         bbox = cand[
'footprint'].getBBox()
 
  520         tmi = afwImage.MaskedImageF(templateExposure.getMaskedImage(), bbox)
 
  521         smi = afwImage.MaskedImageF(scienceExposure.getMaskedImage(), bbox)
 
  522         kCand = diffimLib.makeKernelCandidate(cand[
'source'], tmi, smi, ps)
 
  524             visitor.processCandidate(kCand)
 
  525             kCand.setStatus(afwMath.SpatialCellCandidate.UNKNOWN)
 
  526         candList.append(kCand)
 
  536     """A functor to evaluate the Bayesian Information Criterion for the number of basis sets 
  537     going into the kernel fitting""" 
  539     def __init__(self, psfMatchConfig, psfFwhmPixTc, psfFwhmPixTnc):
 
  543         if not self.
psfMatchConfigpsfMatchConfig.kernelBasisSet == 
"alard-lupton":
 
  544             raise RuntimeError(
"BIC only implemnted for AL (alard lupton) basis")
 
  549         for d1i 
in range(1, d1 + 1):
 
  550             for d2i 
in range(1, d2 + 1):
 
  551                 for d3i 
in range(1, d3 + 1):
 
  552                     dList = [d1i, d2i, d3i]
 
  556                     visitor = diffimLib.BuildSingleKernelVisitorF(kList,
 
  557                                                                   pexConfig.makePropertySet(bicConfig))
 
  558                     visitor.setSkipBuilt(
False)
 
  559                     kernelCellSet.visitCandidates(visitor, bicConfig.nStarPerCell)
 
  561                     for cell 
in kernelCellSet.getCellList():
 
  562                         for cand 
in cell.begin(
False):  
 
  563                             if cand.getStatus() != afwMath.SpatialCellCandidate.GOOD:
 
  565                             diffIm = cand.getDifferenceImage(diffimLib.KernelCandidateF.RECENT)
 
  566                             bbox = cand.getKernel(diffimLib.KernelCandidateF.RECENT).shrinkBBox(
 
  567                                 diffIm.getBBox(afwImage.LOCAL))
 
  568                             diffIm = 
type(diffIm)(diffIm, bbox, 
True)
 
  569                             chi2 = diffIm.getImage().getArray()**2/diffIm.getVariance().getArray()
 
  570                             n = chi2.shape[0]*chi2.shape[1]
 
  571                             bic = np.sum(chi2) + k*np.log(n)
 
  572                             if cand.getId() 
not in bicArray:
 
  573                                 bicArray[cand.getId()] = {}
 
  574                             bicArray[cand.getId()][(d1i, d2i, d3i)] = bic
 
  577         for candId 
in bicArray:
 
  578             cconfig, cvals = 
list(bicArray[candId].
keys()), 
list(bicArray[candId].values())
 
  579             idx = np.argsort(cvals)
 
  580             bestConfig = cconfig[idx[0]]
 
  581             bestConfigs.append(bestConfig)
 
  583         counter = Counter(bestConfigs).most_common(3)
 
  584         log.info(
"B.I.C. prefers basis complexity %s %d times; %s %d times; %s %d times",
 
  585                  counter[0][0], counter[0][1],
 
  586                  counter[1][0], counter[1][1],
 
  587                  counter[2][0], counter[2][1])
 
  588         return counter[0][0], counter[1][0], counter[2][0]
 
A compact representation of a collection of pixels.
 
Represent a 2-dimensional array of bitmask pixels.
 
A kernel described by a function.
 
Pass parameters to a Background object.
 
Parameters to control convolution.
 
A kernel created from an Image.
 
A kernel that is a linear combination of fixed basis kernels.
 
A class that can be used to generate sequences of random numbers according to a number of different a...
 
A collection of SpatialCells covering an entire image.
 
Record class that contains measurements made on a single exposure.
 
An integer coordinate rectangle.
 
daf::base::PropertyList * list
 
def mtv(data, frame=None, title="", wcs=None, *args, **kwargs)
 
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
 
void randomGaussianImage(ImageT *image, Random &rand)
Set image to random numbers with a gaussian N(0, 1) distribution.
 
Statistics makeStatistics(lsst::afw::image::Image< Pixel > const &img, lsst::afw::image::Mask< image::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl=StatisticsControl())
Handle a watered-down front-end to the constructor (no variance)
 
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.
 
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.
 
def makeKernelBasisList(config, targetFwhmPix=None, referenceFwhmPix=None, basisDegGauss=None, basisSigmaGauss=None, metadata=None)