def setUp(self): self.imgVal1, self.varVal1 = 100.0, 10.0 self.imgVal2, self.varVal2 = 200.0, 15.0 self.mimage = afwImage.MaskedImageF(100, 200) self.mimage.getImage().set(self.imgVal1) # # Set center of mask to 0, with 2 pixel border set to EDGE # self.BAD = afwImage.MaskU_getPlaneBitMask("BAD") self.EDGE = afwImage.MaskU_getPlaneBitMask("EDGE") self.mimage.getMask().set(self.EDGE) centre = afwImage.MaskU( self.mimage.getMask(), afwGeom.Box2I(afwGeom.Point2I(2, 2), self.mimage.getDimensions() - afwGeom.Extent2I(4)), afwImage.LOCAL) centre.set(0x0) # self.mimage.getVariance().set(self.varVal1) # # Second MaskedImage # self.mimage2 = afwImage.MaskedImageF(self.mimage.getDimensions()) self.mimage2.getImage().set(self.imgVal2) self.mimage2.getVariance().set(self.varVal2) # # a Function2 # self.function = afwMath.PolynomialFunction2D(2) self.function.setParameters(range(self.function.getNParameters()))
def get_inverse_variance(self, masked_image): mask_bits = afwImage.MaskU_getPlaneBitMask("BAD") mask_bits = mask_bits | afwImage.MaskU_getPlaneBitMask("CR") mask_bits = mask_bits | afwImage.MaskU_getPlaneBitMask("INTRP") iv_img = afwImage.ImageD(masked_image.getWidth(), masked_image.getHeight()) iv_img.setXY0(masked_image.getXY0()) iv_img.getArray()[:, :] = np.where( (masked_image.getMask().getArray() & mask_bits) == 0, 1.0 / masked_image.getVariance().getArray(), 0.0) return iv_img
def __init__(self, config): self.config = config self.bitMask = 0 srcBadMaskPlanes = self.config.srcBadMaskPlanes for maskPlane in srcBadMaskPlanes: self.bitMask |= afwImage.MaskU_getPlaneBitMask(maskPlane)
def testStackBadPixels(self): """Check that we properly ignore masked pixels, and set noGoodPixelsMask where there are no good pixels""" mimgVec = afwImage.vectorMaskedImageF() DETECTED = afwImage.MaskU_getPlaneBitMask("DETECTED") EDGE = afwImage.MaskU_getPlaneBitMask("EDGE") INTRP = afwImage.MaskU_getPlaneBitMask("INTRP") SAT = afwImage.MaskU_getPlaneBitMask("SAT") sctrl = afwMath.StatisticsControl() sctrl.setNanSafe(False) sctrl.setAndMask(INTRP | SAT) sctrl.setNoGoodPixelsMask(EDGE) edgeBBox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I( 20, 20)) # set these pixels to EDGE width, height = 512, 512 dim = afwGeom.Extent2I(width, height) val, maskVal = 10, DETECTED for i in range(4): mimg = afwImage.MaskedImageF(dim) mimg.set(val, maskVal, 1) # # Set part of the image to NaN (with the INTRP bit set) # llc = afwGeom.Point2I(width // 2 * (i // 2), height // 2 * (i % 2)) bbox = afwGeom.Box2I(llc, dim // 2) smimg = mimg.Factory(mimg, bbox, afwImage.LOCAL) del smimg # # And the bottom corner to SAT # smask = mimg.getMask().Factory(mimg.getMask(), edgeBBox, afwImage.LOCAL) smask |= SAT del smask mimgVec.push_back(mimg) if display > 1: ds9.mtv(mimg, frame=i, title=str(i)) mimgStack = afwMath.statisticsStack(mimgVec, afwMath.MEAN, sctrl) if display: i += 1 ds9.mtv(mimgStack, frame=i, title="Stack") i += 1 ds9.mtv(mimgStack.getVariance(), frame=i, title="var(Stack)") # # Check the output, ignoring EDGE pixels # sctrl = afwMath.StatisticsControl() sctrl.setAndMask(afwImage.MaskU_getPlaneBitMask("EDGE")) stats = afwMath.makeStatistics(mimgStack, afwMath.MIN | afwMath.MAX, sctrl) self.assertEqual(stats.getValue(afwMath.MIN), val) self.assertEqual(stats.getValue(afwMath.MAX), val) # # We have to clear EDGE in the known bad corner to check the mask # smask = mimgStack.getMask().Factory(mimgStack.getMask(), edgeBBox, afwImage.LOCAL) self.assertEqual(smask.get(edgeBBox.getMinX(), edgeBBox.getMinY()), EDGE) smask &= ~EDGE del smask self.assertEqual( afwMath.makeStatistics(mimgStack.getMask(), afwMath.SUM, sctrl).getValue(), maskVal)
def fitPsf(self, psfCandidateList): print >> sys.stderr, 'FIXME: resolve issue of proper bitmask (also in evalPsfDeterminer?)' mask_bits = afwImage.MaskU_getPlaneBitMask("BAD") mask_bits = mask_bits | afwImage.MaskU_getPlaneBitMask("CR") mask_bits = mask_bits | afwImage.MaskU_getPlaneBitMask("INTRP") cs = hscpsfLib.HscCandidateSet(mask_bits, self.kernelSize, self.kernelSize) for (i, cand) in enumerate(psfCandidateList): cs.add( cand, i, 0.0, 0.0 ) # FIXME use real values of flux/size here, for completeness # FIXME rethink this for i in xrange(cs.getNcand()): (x0, y0) = (cs.getX0(i), cs.getY0(i)) cs.setXY(i, x0 + 0.5 * (cs.getNx() - 1), y0 + 0.5 * (cs.getNy() - 1)) clipPsf = hscpsfLib.HscClipPsf(cs, 15, 1.0) for n in xrange(5): clipPsf.optimize() cs = clipPsf.getTrimmedCandidateSet() gsPsf = hscpsfLib.HscGlobalSplinePsf(cs, 15, 1.0, 1.0) for n in xrange(5): gsPsf.optimize() for icand in xrange(gsPsf.getNcand()): if gsPsf.displacement_is_maximized( icand) or gsPsf.gamma_is_maximized( icand) or gsPsf.kappa_is_maximized(icand): gsPsf.setBad(icand) cs = gsPsf.getTrimmedCandidateSet() assert self.kernelSize % 2 == 1 nside = (self.kernelSize - 1) // 2 pcaPsf = hscpsfLib.HscPcaPsfNoSM(cs, nside, self.config.nEigenComponents, self.config.lanczosInterpolationOrder) for n in xrange(5): pcaPsf.optimize() if self.config.nEigenComponents > 1: xvec = [pcaPsf.getX(icand) for icand in xrange(pcaPsf.getNcand())] yvec = [pcaPsf.getY(icand) for icand in xrange(pcaPsf.getNcand())] spatialModel = hscpsfLib.HscSpatialModelPolynomial( self.config.spatialOrder, min(xvec), max(xvec), min(yvec), max(yvec)) pcaPsf = hscpsfLib.HscPcaPsf(pcaPsf, spatialModel) for n in xrange(5): pcaPsf.optimize() # The next 2 loops mark bad candidates bad = np.ones(len(psfCandidateList), dtype=bool) for icand in xrange(cs.getNcand()): bad[cs.getId(icand)] = False for i in xrange(len(psfCandidateList)): status = afwMath.SpatialCellCandidate.BAD if bad[ i] else afwMath.SpatialCellCandidate.UNKNOWN psfCandidateList[i].setStatus(status) return pcaPsf
class PolypixPsfDeterminer(object): ConfigClass = PolypixPsfDeterminerConfig def __init__(self, config): """ @param[in] config: instance of PolypixPsfDeterminerConfig """ self.config = config # N.b. name of component is meas.algorithms.psfDeterminer so you can turn on psf debugging # independent of which determiner is active self.debugLog = pexLog.Debug("meas.algorithms.psfDeterminer") self.warnLog = pexLog.Log(pexLog.getDefaultLog(), "meas.algorithms.psfDeterminer") def determinePsf(self, exposure, psfCandidateList, metadata=None, flagKey=None): """ @param[in] exposure: exposure containing the psf candidates (lsst.afw.image.Exposure) @param[in] psfCandidateList: a sequence of PSF candidates (each an lsst.meas.algorithms.PsfCandidate); typically obtained by detecting sources and then running them through a star selector @param[in,out] metadata a home for interesting tidbits of information @param[in] flagKey: schema key used to mark sources actually used in PSF determination @return psf """ import lsstDebug display = lsstDebug.Info(__name__).display displayExposure = display and \ lsstDebug.Info(__name__).displayExposure # display the Exposure + spatialCells displayPsfCandidates = display and \ lsstDebug.Info(__name__).displayPsfCandidates # show the viable candidates displayPsfComponents = display and \ lsstDebug.Info(__name__).displayPsfComponents # show the basis functions showBadCandidates = display and \ lsstDebug.Info(__name__).showBadCandidates # Include bad candidates (meaningless, methinks) displayResiduals = display and \ lsstDebug.Info(__name__).displayResiduals # show residuals displayPsfMosaic = display and \ lsstDebug.Info(__name__).displayPsfMosaic # show mosaic of reconstructed PSF(x,y) matchKernelAmplitudes = lsstDebug.Info(__name__).matchKernelAmplitudes # match Kernel amplitudes for spatial plots normalizeResiduals = lsstDebug.Info(__name__).normalizeResiduals # Normalise residuals by object amplitude mi = exposure.getMaskedImage() nCand = len(psfCandidateList) if nCand == 0: raise RuntimeError("No PSF candidates supplied.") # # How big should our PSF models be? # if display: # only needed for debug plots # construct and populate a spatial cell set bbox = mi.getBBox(afwImage.PARENT) psfCellSet = afwMath.SpatialCellSet(bbox, self.config.sizeCellX, self.config.sizeCellY) else: psfCellSet = None sizes = np.empty(nCand) for i, psfCandidate in enumerate(psfCandidateList): try: if psfCellSet: psfCellSet.insertCandidate(psfCandidate) except Exception, e: self.debugLog.debug(2, "Skipping PSF candidate %d of %d: %s" % (i, len(psfCandidateList), e)) continue source = psfCandidate.getSource() quad = afwEll.Quadrupole(source.getIxx(), source.getIyy(), source.getIxy()) rmsSize = quad.getTraceRadius() sizes[i] = rmsSize if self.config.kernelSize >= 15: self.debugLog.debug(1, \ "WARNING: NOT scaling kernelSize by stellar quadrupole moment, but using absolute value") actualKernelSize = int(self.config.kernelSize) else: actualKernelSize = 2 * int(self.config.kernelSize * np.sqrt(np.median(sizes)) + 0.5) + 1 if actualKernelSize < self.config.kernelSizeMin: actualKernelSize = self.config.kernelSizeMin if actualKernelSize > self.config.kernelSizeMax: actualKernelSize = self.config.kernelSizeMax if display: rms = np.median(sizes) print "Median PSF RMS size=%.2f pixels (\"FWHM\"=%.2f)" % (rms, 2*np.sqrt(2*np.log(2))*rms) # If we manually set the resolution then we need the size in pixel units pixKernelSize = actualKernelSize if self.config.samplingSize > 0: pixKernelSize = int(actualKernelSize*self.config.samplingSize) if pixKernelSize % 2 == 0: pixKernelSize += 1 self.debugLog.debug(3, "PSF Kernel size=%.2f, Image Kernel Size=%.2f" % (actualKernelSize,pixKernelSize)) nside = pixKernelSize // 2 assert pixKernelSize == (2*nside+1) # Set size of image returned around candidate psfCandidateList[0].setHeight(pixKernelSize) psfCandidateList[0].setWidth(pixKernelSize) mask_bits = afwImage.MaskU_getPlaneBitMask(self.config.badMaskBits) fluxName = 'initial.flux.sinc' # FIXME should be in config? (meas_extensions_psfex has it in a config file) fluxFlagName = fluxName + ".flags" cs = hscpsfLib.HscCandidateSet(mask_bits, pixKernelSize, pixKernelSize) with ds9.Buffering(): xpos = []; ypos = [] for i, psfCandidate in enumerate(psfCandidateList): source = psfCandidate.getSource() xc, yc = source.getX(), source.getY() if fluxFlagName in source.schema and source.get(fluxFlagName): continue flux = source.get(fluxName) if flux < 0 or np.isnan(flux): continue cs.add(psfCandidate, i, flux, sizes[i]) xpos.append(xc); ypos.append(yc) # for QA if displayExposure: ds9.dot("o", xc, yc, ctype=ds9.CYAN, size=4, frame=frame) if cs.getNcand() == 0: raise RuntimeError("No good PSF candidates") # Calculate fwhm, backnoise2 and gain fwhm = 2*np.sqrt(2*np.log(2))*np.median(sizes) backnoise2 = afwMath.makeStatistics(mi.getImage(), afwMath.VARIANCECLIP).getValue() ccd = afwCG.cast_Ccd(exposure.getDetector()) if ccd: gain = np.mean(np.array([a.getElectronicParams().getGain() for a in ccd])) else: gain = 1.0 self.warnLog.log(pexLog.Log.WARN, "Setting gain to %g" % gain) xvec = np.array([ cand.getSource().get('initial.centroid.sdss.x') for cand in psfCandidateList ]) yvec = np.array([ cand.getSource().get('initial.centroid.sdss.y') for cand in psfCandidateList ]) spatialModel = hscpsfLib.HscSpatialModelPolynomial(self.config.spatialOrder, min(xvec), max(xvec), min(yvec), max(yvec)) # # This sequence of PSF fits, including "magic numbers" such as psf_make(0.2, 1000.0) # matches internal logic in psfex! # psf = hscpsfLib.PolypixPsf(cs, nside, actualKernelSize, self.config.samplingSize, spatialModel, fwhm, backnoise2, gain) psf.psf_make(0.2, 1000.0) cs = psf.psf_clean(0.2) psf = hscpsfLib.PolypixPsf(cs, psf) psf.psf_make(0.1, 1000.0) cs = psf.psf_clean(0.1) psf = hscpsfLib.PolypixPsf(cs, psf) psf.psf_make(0.05, 1000.0) cs = psf.psf_clean(0.05) psf = hscpsfLib.PolypixPsf(cs, psf) psf.psf_make(0.01, 1000.0) psf.psf_clip() cs = psf.psf_clean(0.01) good_indices = [ cs.getId(icand) for icand in xrange(cs.getNcand()) ] if flagKey is not None: for (icand, cand) in enumerate(psfCandidateList): if icand in good_indices: cand.getSource().set(flagKey, True) numGoodStars = len(good_indices) avgX, avgY = np.mean(xpos), np.mean(ypos) # # Generate some QA information # # Count PSF stars # if metadata != None: metadata.set("spatialFitChi2", np.nan) metadata.set("numAvailStars", nCand) metadata.set("numGoodStars", numGoodStars) metadata.set("avgX", avgX) metadata.set("avgY", avgY) psfCellSet = None return psf, psfCellSet
def countDetected(self, mask): idxP = num.where(mask & afwImage.MaskU_getPlaneBitMask("DETECTED")) idxN = num.where(mask & afwImage.MaskU_getPlaneBitMask("DETECTED_NEGATIVE")) return len(idxP[0]), len(idxN[0])