def main(): butils = measDeblend.BaselineUtilsF foot = buildExample2() fbb = foot.getBBox() mask1 = afwImg.MaskU(fbb.getWidth(), fbb.getHeight()) mask1.setXY0(fbb.getMinX(), fbb.getMinY()) afwDet.setMaskFromFootprint(mask1, foot, 1) if plt: plt.clf() plt.imshow(mask1.getArray(), origin='lower', interpolation='nearest', extent=(fbb.getMinX(), fbb.getMaxX(), fbb.getMinY(), fbb.getMaxY())) plt.gray() plt.savefig('foot2.png') sfoot = butils.symmetrizeFootprint(foot, 355, 227) mask2 = afwImg.MaskU(fbb.getWidth(), fbb.getHeight()) mask2.setXY0(fbb.getMinX(), fbb.getMinY()) afwDet.setMaskFromFootprint(mask2, sfoot, 1) plt.clf() plt.imshow(mask2.getArray(), origin='lower', interpolation='nearest', extent=(fbb.getMinX(), fbb.getMaxX(), fbb.getMinY(), fbb.getMaxY())) plt.gray() plt.savefig('sfoot3.png')
def removeSource(self, id): """! Remove the heavy footprint of a given source and replace with previous noise @param[in] id id for current source to insert from original footprint dict Also restore the mask plane. """ # remove a single source # (Replace this source's pixels by noise again.) # Do this by finding the source's top-level ancestor mi = self.exposure.getMaskedImage() im = mi.getImage() mask = mi.getMask() # use the same algorithm as in remove Source to find the heavy noise footprint # which will undo what insertSource(id) does usedid = id while self.footprints[usedid][ 0] != 0 and not usedid in self.heavies.keys(): usedid = self.footprints[usedid][0] # Re-insert the noise pixels fp = self.heavyNoise[usedid] fp.insert(im) # Clear the THISDET mask plane. afwDet.clearMaskFromFootprint(mask, fp, self.thisbitmask) afwDet.setMaskFromFootprint(mask, fp, self.otherbitmask)
def removeSource(self, id): """! Remove the heavy footprint of a given source and replace with previous noise @param[in] id id for current source to insert from original footprint dict Also restore the mask plane. """ # remove a single source # (Replace this source's pixels by noise again.) # Do this by finding the source's top-level ancestor mi = self.exposure.getMaskedImage() im = mi.getImage() mask = mi.getMask() # use the same algorithm as in remove Source to find the heavy noise footprint # which will undo what insertSource(id) does usedid = id while self.footprints[usedid][0] != 0 and not usedid in self.heavies.keys(): usedid = self.footprints[usedid][0] # Re-insert the noise pixels fp = self.heavyNoise[usedid] fp.insert(im) # Clear the THISDET mask plane. afwDet.clearMaskFromFootprint(mask, fp, self.thisbitmask) afwDet.setMaskFromFootprint(mask, fp, self.otherbitmask)
def insertSource(self, exposure, sourcei): # Copy this source's pixels into the image mi = exposure.getMaskedImage() im = mi.getImage() mask = mi.getMask() fp = self.heavies[sourcei] fp.insert(im) afwDet.setMaskFromFootprint(mask, fp, self.thisbitmask) afwDet.clearMaskFromFootprint(mask, fp, self.otherbitmask)
def countMaskFromFootprint(mask, footprint, bitmask, ignoreMask): """Function to count the number of pixels with a specific mask in a footprint """ bbox = footprint.getBBox() bbox.clip(mask.getBBox(afwImage.PARENT)) fp = afwImage.MaskU(bbox) subMask = mask.Factory(mask, bbox, afwImage.PARENT) afwDet.setMaskFromFootprint(fp, footprint, bitmask) return numpy.logical_and((subMask.getArray() & fp.getArray()) > 0, (subMask.getArray() & ignoreMask) == 0).sum()
def getMaskFromFootprint(mask, footprint, bitmask): """Function to get which of pixels have a specific mask in footprint """ bbox = footprint.getBBox() bbox.clip(mask.getBBox(afwImage.PARENT)) fp = afwImage.Mask(bbox) subMask = mask.Factory(mask, bbox, afwImage.PARENT) #fp.getFootprint().span.setMask( afwDet.setMaskFromFootprint(fp, footprint, 0x1) return ((subMask.getArray()&bitmask==0) & (fp.getArray())) > 0
def maskPixelsFromDefectList(maskedImage, defectList, maskName='BAD'): """Set mask plane based on a defect list @param[in,out] maskedImage afw.image.MaskedImage to process; mask plane is updated @param[in] defectList meas.algorithms.DefectListT @param[in] maskName mask plane name """ # mask bad pixels mask = maskedImage.getMask() bitmask = mask.getPlaneBitMask(maskName) for defect in defectList: bbox = defect.getBBox() afwDetection.setMaskFromFootprint(mask, afwDetection.Footprint(bbox), bitmask)
def skipParent(self, source, mask): """Indicate that the parent source is not being deblended We set the appropriate flags and mask. @param source The source to flag as skipped @param mask The mask to update """ fp = source.getFootprint() source.set(self.deblendSkippedKey, True) source.set(self.nChildKey, len(fp.getPeaks())) # It would have this many if we deblended them all if self.config.notDeblendedMask: mask.addMaskPlane(self.config.notDeblendedMask) afwDet.setMaskFromFootprint(mask, fp, mask.getPlaneBitMask(self.config.notDeblendedMask))
def testInclude(self): """Test that we can expand a Footprint to include the union of itself and all others provided (must be non-disjoint). """ region = afwGeom.Box2I(afwGeom.Point2I(-6, -6), afwGeom.Point2I(6, 6)) parent = afwDetect.Footprint(afwGeom.Box2I(afwGeom.Point2I(-2, -2), afwGeom.Point2I(2, 2)), region) parent.addPeak(0, 0, float("NaN")) child1 = afwDetect.Footprint(afwGeom.Box2I(afwGeom.Point2I(-3, 0), afwGeom.Point2I(0, 3)), region) child1.addPeak(-1, 1, float("NaN")) child2 = afwDetect.Footprint(afwGeom.Box2I(afwGeom.Point2I(-4, -3), afwGeom.Point2I(-1, 0)), region) child3 = afwDetect.Footprint(afwGeom.Box2I(afwGeom.Point2I(4, -1), afwGeom.Point2I(6, 1))) merge12 = afwDetect.Footprint(parent) merge12.include([child1, child2]) self.assertTrue(merge12.getBBox().contains(parent.getBBox())) self.assertTrue(merge12.getBBox().contains(child1.getBBox())) self.assertTrue(merge12.getBBox().contains(child2.getBBox())) mask12a = afwImage.MaskU(region) mask12b = afwImage.MaskU(region) afwDetect.setMaskFromFootprint(mask12a, parent, 1) afwDetect.setMaskFromFootprint(mask12a, child1, 1) afwDetect.setMaskFromFootprint(mask12a, child2, 1) afwDetect.setMaskFromFootprint(mask12b, merge12, 1) self.assertEqual(mask12a.getArray().sum(), merge12.getArea()) self.assertClose(mask12a.getArray(), mask12b.getArray(), rtol=0, atol=0) self.assertRaisesLsstCpp(pexExcept.RuntimeError, parent.include, [child1, child2, child3])
def skipParent(self, source, mask): """Indicate that the parent source is not being deblended We set the appropriate flags and mask. @param source The source to flag as skipped @param mask The mask to update """ fp = source.getFootprint() source.set(self.deblendSkippedKey, True) source.set(self.nChildKey, len( fp.getPeaks())) # It would have this many if we deblended them all if self.config.notDeblendedMask: mask.addMaskPlane(self.config.notDeblendedMask) afwDet.setMaskFromFootprint( mask, fp, mask.getPlaneBitMask(self.config.notDeblendedMask))
def removeSource(self, exposure, sources, source): # remove a single source # (Replace this source's pixels by noise again.) # Do this by finding the source's top-level ancestor mi = exposure.getMaskedImage() im = mi.getImage() mask = mi.getMask() ancestor = source j = 0 while ancestor.getParent(): ancestor = sources.find(ancestor.getParent()) j += 1 if not ancestor or j == 100: raise RuntimeError('Source hierarchy too deep, or (more likely) your Source table is botched.') # Re-insert the noise pixels fp = self.heavyNoise[ancestor.getId()] fp.insert(im) # Clear the THISDET mask plane. afwDet.clearMaskFromFootprint(mask, fp, self.thisbitmask) afwDet.setMaskFromFootprint(mask, fp, self.otherbitmask)
def insertSource(self, id): """! Insert the heavy footprint of a given source into the exposure @param[in] id id for current source to insert from original footprint dict Also adjusts the mask plane to show the source of this footprint. """ # Copy this source's pixels into the image mi = self.exposure.getMaskedImage() im = mi.getImage() mask = mi.getMask() # usedid can point either to this source, or to the first parent in the # parent chain which has a heavy footprint (or to the topmost parent, # which always has one) usedid = id while self.footprints[usedid][0] != 0 and not usedid in self.heavies.keys(): usedid = self.footprints[usedid][0] fp = self.heavies[usedid] fp.insert(im) afwDet.setMaskFromFootprint(mask, fp, self.thisbitmask) afwDet.clearMaskFromFootprint(mask, fp, self.otherbitmask)
def removeSource(self, exposure, sources, source): # remove a single source # (Replace this source's pixels by noise again.) # Do this by finding the source's top-level ancestor mi = exposure.getMaskedImage() im = mi.getImage() mask = mi.getMask() ancestor = source j = 0 while ancestor.getParent(): ancestor = sources.find(ancestor.getParent()) j += 1 if not ancestor or j == 100: raise RuntimeError( 'Source hierarchy too deep, or (more likely) your Source table is botched.' ) # Re-insert the noise pixels fp = self.heavyNoise[ancestor.getId()] fp.insert(im) # Clear the THISDET mask plane. afwDet.clearMaskFromFootprint(mask, fp, self.thisbitmask) afwDet.setMaskFromFootprint(mask, fp, self.otherbitmask)
def insertSource(self, id): """! Insert the heavy footprint of a given source into the exposure @param[in] id id for current source to insert from original footprint dict Also adjusts the mask plane to show the source of this footprint. """ # Copy this source's pixels into the image mi = self.exposure.getMaskedImage() im = mi.getImage() mask = mi.getMask() # usedid can point either to this source, or to the first parent in the # parent chain which has a heavy footprint (or to the topmost parent, # which always has one) usedid = id while self.footprints[usedid][ 0] != 0 and not usedid in self.heavies.keys(): usedid = self.footprints[usedid][0] fp = self.heavies[usedid] fp.insert(im) afwDet.setMaskFromFootprint(mask, fp, self.thisbitmask) afwDet.clearMaskFromFootprint(mask, fp, self.otherbitmask)
def __init__(self, config, exposure, footprints, noiseImage=None, exposureId=None, log=None): """! Initialize the NoiseReplacer. @param[in] config instance of NoiseReplacerConfig @param[in,out] exposure Exposure to be noise replaced. (All sources replaced on return) @param[in] footprints dict of {id: (parent, footprint)}; @param[in] noiseImage an afw.image.ImageF used as a predictable noise replacement source (for tests only) @param[in] log pex.logging.Log object to use for status messages; no status messages will be printed if None 'footprints' is a dict of {id: (parent, footprint)}; when used in SFM, the ID will be the source ID, but in forced photometry, this will be the reference ID, as that's what we used to determine the deblend families. This routine should create HeavyFootprints for any non-Heavy Footprints, and replace them in the dict. It should then create a dict of HeavyFootprints containing noise, but only for parent objects, then replace all sources with noise. This should ignore any footprints that lay outside the bounding box of the exposure, and clip those that lie on the border. NOTE: as the code currently stands, the heavy footprint for a deblended object must be available from the input catalog. If it is not, it cannot be reproduced here. In that case, the topmost parent in the objects parent chain must be used. The heavy footprint for that source is created in this class from the masked image. """ noiseMeanVar = None self.noiseSource = config.noiseSource self.noiseOffset = config.noiseOffset self.noiseSeedMultiplier = config.noiseSeedMultiplier self.noiseGenMean = None self.noiseGenStd = None self.log = log # creates heavies, replaces all footprints with noise # We need the source table to be sorted by ID to do the parent lookups self.exposure = exposure self.footprints = footprints mi = exposure.getMaskedImage() im = mi.getImage() mask = mi.getMask() # Add temporary Mask planes for THISDET and OTHERDET self.removeplanes = [] bitmasks = [] for maskname in ['THISDET', 'OTHERDET']: try: # does it already exist? plane = mask.getMaskPlane(maskname) if self.log: self.log.logdebug('Mask plane "%s" already existed' % maskname) except: # if not, add it; we should delete it when done. plane = mask.addMaskPlane(maskname) self.removeplanes.append(maskname) mask.clearMaskPlane(plane) bitmask = mask.getPlaneBitMask(maskname) bitmasks.append(bitmask) if self.log: self.log.logdebug( 'Mask plane "%s": plane %i, bitmask %i = 0x%x' % (maskname, plane, bitmask, bitmask)) self.thisbitmask, self.otherbitmask = bitmasks del bitmasks self.heavies = {} # Start by creating HeavyFootprints for each source which has no parent # and just use them for children which do not already have heavy footprints. # If a heavy footprint is available for a child, we will use it. Otherwise, # we use the first parent in the parent chain which has a heavy footprint, # which with the one level deblender will alway be the topmost parent # NOTE: heavy footprints get destroyed by the transform process in forcedPhotImage.py, # so they are never available for forced measurements. # Create in the dict heavies = {id:heavyfootprint} for id in footprints.keys(): fp = footprints[id] if fp[1].isHeavy(): self.heavies[id] = afwDet.cast_HeavyFootprintF(fp[1]) elif fp[0] == 0: self.heavies[id] = afwDet.makeHeavyFootprint(fp[1], mi) ### FIXME: the heavy footprint includes the mask ### and variance planes, which we shouldn't need ### (I don't think we ever want to modify them in ### the input image). Copying them around is ### wasteful. # We now create a noise HeavyFootprint for each source with has a heavy footprint. # We'll put the noise footprints in a dict heavyNoise = {id:heavyNoiseFootprint} self.heavyNoise = {} noisegen = self.getNoiseGenerator(exposure, noiseImage, noiseMeanVar, exposureId=exposureId) # The noiseGenMean and Std are used by the unit tests self.noiseGenMean = noisegen.mean self.noiseGenStd = noisegen.std if self.log: self.log.logdebug('Using noise generator: %s' % (str(noisegen))) for id in self.heavies.keys(): fp = footprints[id][1] noiseFp = noisegen.getHeavyFootprint(fp) self.heavyNoise[id] = noiseFp # Also insert the noisy footprint into the image now. # Notice that we're just inserting it into "im", ie, # the Image, not the MaskedImage. noiseFp.insert(im) # Also set the OTHERDET bit afwDet.setMaskFromFootprint(mask, fp, self.otherbitmask)
def detectClip(self, exp, tempExpRefList): """Detect clipped regions on an exposure and set the mask on the individual tempExp masks @param exp: Exposure to run detection on @param tempExpRefList: List of data reference to tempExp @return struct containg: - clippedFootprints: list of clipped footprints - clippedIndices: indices for each clippedFootprint in tempExpRefList - tempExpClipList: list of new masks for tempExp """ mask = exp.getMaskedImage().getMask() maskClipValue = mask.getPlaneBitMask("CLIPPED") maskDetValue = mask.getPlaneBitMask("DETECTED") | mask.getPlaneBitMask("DETECTED_NEGATIVE") fpSet = self.clipDetection.detectFootprints(exp, doSmooth=True, clearMask=True) # Merge positive and negative together footprints together fpSet.positive.merge(fpSet.negative) footprints = fpSet.positive self.log.info('Found %d potential clipped objects' % len(footprints.getFootprints())) ignoreMask = self.getBadPixelMask() clipFootprints = [] clipIndices = [] # build a list with a mask for each visit which can be modified with clipping information tempExpClipList = [tmpExpRef.get(self.getTempExpDatasetName(), immediate=True).getMaskedImage().getMask() for tmpExpRef in tempExpRefList] for footprint in footprints.getFootprints(): nPixel = footprint.getArea() overlap = [] # hold the overlap with each visit maskList = [] # which visit mask match indexList = []# index of visit in global list for i, tmpExpMask in enumerate(tempExpClipList): # Determine the overlap with the footprint ignore = countMaskFromFootprint(tmpExpMask, footprint, ignoreMask, 0x0) overlapDet = countMaskFromFootprint(tmpExpMask, footprint, maskDetValue, ignoreMask) totPixel = nPixel - ignore # If we have more bad pixels than detection skip if ignore > overlapDet or totPixel <= 0.5*nPixel or overlapDet == 0: continue overlap.append(overlapDet/float(totPixel)) maskList.append(tmpExpMask) indexList.append(i) overlap = numpy.array(overlap) if not len(overlap): continue keep = False # Should this footprint be marked as clipped? keepIndex = [] # Which tempExps does the clipped footprint belong to # If footprint only has one overlap use a lower threshold if len(overlap) == 1: if overlap[0] > self.config.minClipFootOverlapSingle: keep = True keepIndex = [0] else: # This is the general case where only visit should be clipped clipIndex = numpy.where(overlap > self.config.minClipFootOverlap)[0] if len(clipIndex) == 1: keep=True keepIndex = [clipIndex[0]] # Test if there are clipped objects that overlap two different visits clipIndex = numpy.where(overlap > self.config.minClipFootOverlapDouble)[0] if len(clipIndex) == 2 and len(overlap) > 3: clipIndexComp = numpy.where(overlap < self.config.minClipFootOverlapDouble)[0] if numpy.max(overlap[clipIndexComp]) < self.config.maxClipFootOverlapDouble: keep=True keepIndex = clipIndex if not keep: continue for index in keepIndex: afwDet.setMaskFromFootprint(maskList[index], footprint, maskClipValue) clipIndices.append(numpy.array(indexList)[keepIndex]) clipFootprints.append(footprint) return pipeBase.Struct(clipFootprints=clipFootprints, clipIndices=clipIndices, tempExpClipList=tempExpClipList)
def test1(self): # circle fp = afwDet.Footprint(afwGeom.Point2I(50,50), 45.) # psfsig = 1.5 psffwhm = psfsig * 2.35 psf1 = measAlg.DoubleGaussianPsf(11, 11, psfsig) psf2 = measAlg.DoubleGaussianPsf(100, 100, psfsig) fbb = fp.getBBox() print 'fbb', fbb.getMinX(), fbb.getMaxX(), fbb.getMinY(), fbb.getMaxY() fmask = afwImage.MaskU(fbb) fmask.setXY0(fbb.getMinX(), fbb.getMinY()) afwDet.setMaskFromFootprint(fmask, fp, 1) sig1 = 10. img = afwImage.ImageF(fbb) A = img.getArray() A += np.random.normal(0, sig1, size=(fbb.getHeight(), fbb.getWidth())) print 'img x0,y0', img.getX0(), img.getY0() print 'BBox', img.getBBox() peaks = afwDet.PeakCatalog(afwDet.PeakTable.makeMinimalSchema()) def makePeak(x, y): p = peaks.addNew() p.setFx(x) p.setFy(y) p.setIx(int(x)) p.setIy(int(y)) return p pk1 = makePeak(20., 30.) pk2 = makePeak(23., 33.) pk3 = makePeak(92., 50.) ibb = img.getBBox() iext = [ibb.getMinX(), ibb.getMaxX(), ibb.getMinY(), ibb.getMaxY()] ix0,iy0 = iext[0], iext[2] pbbs = [] pxys = [] fluxes = [10000., 5000., 5000.] for pk,f in zip(peaks, fluxes): psfim = psf1.computeImage(afwGeom.Point2D(pk.getFx(), pk.getFy())) print 'psfim x0,y0', psfim.getX0(), psfim.getY0() pbb = psfim.getBBox() print 'pbb', pbb.getMinX(), pbb.getMaxX(), pbb.getMinY(), pbb.getMaxY() pbb.clip(ibb) print 'clipped pbb', pbb.getMinX(), pbb.getMaxX(), pbb.getMinY(), pbb.getMaxY() psfim = psfim.Factory(psfim, pbb) psfa = psfim.getArray() psfa /= psfa.sum() img.getArray()[pbb.getMinY() - iy0: pbb.getMaxY()+1 - iy0, pbb.getMinX() - ix0: pbb.getMaxX()+1 - ix0] += f * psfa pbbs.append((pbb.getMinX(), pbb.getMaxX(), pbb.getMinY(), pbb.getMaxY())) pxys.append((pk.getFx(), pk.getFy())) if doPlot: plt.clf() plt.imshow(img.getArray(), extent=iext, interpolation='nearest', origin='lower') ax = plt.axis() x0,x1,y0,y1 = fbb.getMinX(), fbb.getMaxX(), fbb.getMinY(), fbb.getMaxY() plt.plot([x0,x0,x1,x1,x0], [y0,y1,y1,y0,y0], 'k-') for x0,x1,y0,y1 in pbbs: plt.plot([x0,x0,x1,x1,x0], [y0,y1,y1,y0,y0], 'r-') for x,y in pxys: plt.plot(x, y, 'ro') plt.axis(ax) plt.savefig('img.png') varimg = afwImage.ImageF(fbb) varimg.set(sig1**2) psf_chisq_cut1 = psf_chisq_cut2 = psf_chisq_cut2b = 1.5 pkres = PerPeak() loglvl = pexLogging.Log.INFO #if verbose: # loglvl = pexLogging.Log.DEBUG log = pexLogging.Log(pexLogging.Log.getDefaultLog(), 'tests.fit_psf', loglvl) cpsf = CachingPsf(psf1) peaksF = [pk.getF() for pk in peaks] pkF = pk1.getF() _fitPsf(fp, fmask, pk1, pkF, pkres, fbb, peaks, peaksF, log, cpsf, psffwhm, img, varimg, psf_chisq_cut1, psf_chisq_cut2, psf_chisq_cut2b) for k in dir(pkres): if k.startswith('__'): continue print ' ', k, getattr(pkres, k) cpsf = CachingPsf(psf2) _fitPsf(fp, fmask, pk1, pkF, pkres, fbb, peaks, peaksF, log, cpsf, psffwhm, img, varimg, psf_chisq_cut1, psf_chisq_cut2, psf_chisq_cut2b) for k in dir(pkres): if k.startswith('__'): continue print ' ', k, getattr(pkres, k) pkF = pk3.getF() _fitPsf(fp, fmask, pk3, pkF, pkres, fbb, peaks, peaksF, log, cpsf, psffwhm, img, varimg, psf_chisq_cut1, psf_chisq_cut2, psf_chisq_cut2b) for k in dir(pkres): if k.startswith('__'): continue print ' ', k, getattr(pkres, k)
match = maskFormat.match(datasec) if match == None: # unable to match mask area! print '# WARNING: Extn', nExt, 'unable to parse', maskArea continue group = map(int, match.groups()) # ACB : by visual inspection, the y0 values can be too # high by 1. however, since some of the y0 values are '1' # in the mask string, i can't decrement this by 2 without # going off the image. we just deal with this for dc3a. bbox = afwImage.BBox(afwImage.PointI(group[0] - 1, group[1] - 1), afwImage.PointI(group[2] - 1, group[3] - 1)) fp = afwDetection.Footprint(bbox) afwDetection.setMaskFromFootprint(mask, fp, bitmask) # debugging #outfile0 = '%d.fits' % (i) #print '# Writing', outfile0 #mask.writeFits(outfile0) # trim this thing! it includes the overscan etc... bboxA = afwImage.BBox(afwImage.PointI(32, 0), afwImage.PointI(1055, 4611)) bboxB = afwImage.BBox(afwImage.PointI(1055, 0), afwImage.PointI(2111 - 32, 4611)) #bboxA = afwImage.BBox(afwImage.PointI(0,0), # afwImage.PointI(1055,4611))
def testInclude(self): """Test that we can expand a Footprint to include the union of itself and all others provided.""" region = afwGeom.Box2I(afwGeom.Point2I(-6, -6), afwGeom.Point2I(6, 6)) parent = afwDetect.Footprint( afwGeom.Box2I(afwGeom.Point2I(-2, -2), afwGeom.Point2I(2, 2)), region) parent.addPeak(0, 0, float("NaN")) child1 = afwDetect.Footprint( afwGeom.Box2I(afwGeom.Point2I(-3, 0), afwGeom.Point2I(0, 3)), region) child1.addPeak(-1, 1, float("NaN")) child2 = afwDetect.Footprint( afwGeom.Box2I(afwGeom.Point2I(-4, -3), afwGeom.Point2I(-1, 0)), region) child3 = afwDetect.Footprint( afwGeom.Box2I(afwGeom.Point2I(4, -1), afwGeom.Point2I(6, 1))) merge123 = afwDetect.Footprint(parent) merge123.include([child1, child2, child3]) self.assertTrue(merge123.getBBox().contains(parent.getBBox())) self.assertTrue(merge123.getBBox().contains(child1.getBBox())) self.assertTrue(merge123.getBBox().contains(child2.getBBox())) self.assertTrue(merge123.getBBox().contains(child3.getBBox())) mask123a = afwImage.MaskU(region) mask123b = afwImage.MaskU(region) afwDetect.setMaskFromFootprint(mask123a, parent, 1) afwDetect.setMaskFromFootprint(mask123a, child1, 1) afwDetect.setMaskFromFootprint(mask123a, child2, 1) afwDetect.setMaskFromFootprint(mask123a, child3, 1) afwDetect.setMaskFromFootprint(mask123b, merge123, 1) self.assertEqual(mask123a.getArray().sum(), merge123.getArea()) self.assertClose(mask123a.getArray(), mask123b.getArray(), rtol=0, atol=0) # Test that ignoreSelf=True works for include ignoreParent = True childOnly = afwDetect.Footprint() childOnly.include([child1, child2, child3]) merge123 = afwDetect.Footprint(parent) merge123.include([child1, child2, child3], ignoreParent) maskChildren = afwImage.MaskU(region) mask123 = afwImage.MaskU(region) afwDetect.setMaskFromFootprint(maskChildren, childOnly, 1) afwDetect.setMaskFromFootprint(mask123, merge123, 1) self.assertTrue(np.all(maskChildren.getArray() == mask123.getArray()))
def __call__(self, source, exposure): fp = source.getFootprint() peaks = fp.getPeaks() peaksF = [pk.getF() for pk in peaks] fbb = fp.getBBox() fmask = afwImage.MaskU(fbb) fmask.setXY0(fbb.getMinX(), fbb.getMinY()) afwDetect.setMaskFromFootprint(fmask, fp, 1) psf = exposure.getPsf() psfSigPix = psf.computeShape().getDeterminantRadius() psfFwhmPix = psfSigPix * self.sigma2fwhm subimage = afwImage.ExposureF(exposure, fbb, True) cpsf = deblendBaseline.CachingPsf(psf) # if fewer than 2 peaks, just return a copy of the source if len(peaks) < 2: return source.getTable().copyRecord(source) # make sure you only deblend 2 peaks; take the brighest and faintest speaks = [(p.getPeakValue(), p) for p in peaks] speaks.sort() dpeaks = [speaks[0][1], speaks[-1][1]] # and only set these peaks in the footprint (peaks is mutable) peaks.clear() for peak in dpeaks: peaks.append(peak) if True: # Call top-level deblend task fpres = deblendBaseline.deblend(fp, exposure.getMaskedImage(), psf, psfFwhmPix, log = self.log, psfChisqCut1 = self.psfChisqCut1, psfChisqCut2 = self.psfChisqCut2, psfChisqCut2b = self.psfChisqCut2b) else: # Call lower-level _fit_psf task # Prepare results structure fpres = deblendBaseline.PerFootprint() fpres.peaks = [] for pki,pk in enumerate(dpeaks): pkres = deblendBaseline.PerPeak() pkres.peak = pk pkres.pki = pki fpres.peaks.append(pkres) for pki,(pk,pkres,pkF) in enumerate(zip(dpeaks, fpres.peaks, peaksF)): self.log.logdebug('Peak %i' % pki) deblendBaseline._fitPsf(fp, fmask, pk, pkF, pkres, fbb, dpeaks, peaksF, self.log, cpsf, psfFwhmPix, subimage.getMaskedImage().getImage(), subimage.getMaskedImage().getVariance(), self.psfChisqCut1, self.psfChisqCut2, self.psfChisqCut2b) deblendedSource = source.getTable().copyRecord(source) deblendedSource.setParent(source.getId()) peakList = deblendedSource.getFootprint().getPeaks() peakList.clear() for i, peak in enumerate(fpres.peaks): if peak.psfFitFlux > 0: suffix = "pos" else: suffix = "neg" c = peak.psfFitCenter self.log.info("deblended.centroid.dipole.psf.%s %f %f" % ( suffix, c[0], c[1])) self.log.info("deblended.chi2dof.dipole.%s %f" % ( suffix, peak.psfFitChisq / peak.psfFitDof)) self.log.info("deblended.flux.dipole.psf.%s %f" % ( suffix, peak.psfFitFlux * np.sum(peak.templateImage.getArray()))) peakList.append(peak.peak) return deblendedSource
def __call__(self, source, exposure): fp = source.getFootprint() peaks = fp.getPeaks() peaksF = [pk.getF() for pk in peaks] fbb = fp.getBBox() fmask = afwImage.MaskU(fbb) fmask.setXY0(fbb.getMinX(), fbb.getMinY()) afwDetect.setMaskFromFootprint(fmask, fp, 1) psf = exposure.getPsf() psfSigPix = psf.computeShape().getDeterminantRadius() psfFwhmPix = psfSigPix * self.sigma2fwhm subimage = afwImage.ExposureF(exposure, fbb, True) cpsf = deblendBaseline.CachingPsf(psf) # if fewer than 2 peaks, just return a copy of the source if len(peaks) < 2: return source.getTable().copyRecord(source) # make sure you only deblend 2 peaks; take the brighest and faintest speaks = [(p.getPeakValue(), p) for p in peaks] speaks.sort() dpeaks = [speaks[0][1], speaks[-1][1]] # and only set these peaks in the footprint (peaks is mutable) peaks.clear() for peak in dpeaks: peaks.append(peak) if True: # Call top-level deblend task fpres = deblendBaseline.deblend(fp, exposure.getMaskedImage(), psf, psfFwhmPix, log=self.log, psfChisqCut1=self.psfChisqCut1, psfChisqCut2=self.psfChisqCut2, psfChisqCut2b=self.psfChisqCut2b) else: # Call lower-level _fit_psf task # Prepare results structure fpres = deblendBaseline.PerFootprint() fpres.peaks = [] for pki, pk in enumerate(dpeaks): pkres = deblendBaseline.PerPeak() pkres.peak = pk pkres.pki = pki fpres.peaks.append(pkres) for pki, (pk, pkres, pkF) in enumerate(zip(dpeaks, fpres.peaks, peaksF)): self.log.logdebug('Peak %i' % pki) deblendBaseline._fitPsf( fp, fmask, pk, pkF, pkres, fbb, dpeaks, peaksF, self.log, cpsf, psfFwhmPix, subimage.getMaskedImage().getImage(), subimage.getMaskedImage().getVariance(), self.psfChisqCut1, self.psfChisqCut2, self.psfChisqCut2b) deblendedSource = source.getTable().copyRecord(source) deblendedSource.setParent(source.getId()) peakList = deblendedSource.getFootprint().getPeaks() peakList.clear() for i, peak in enumerate(fpres.peaks): if peak.psfFitFlux > 0: suffix = "pos" else: suffix = "neg" c = peak.psfFitCenter self.log.info("deblended.centroid.dipole.psf.%s %f %f" % (suffix, c[0], c[1])) self.log.info("deblended.chi2dof.dipole.%s %f" % (suffix, peak.psfFitChisq / peak.psfFitDof)) self.log.info("deblended.flux.dipole.psf.%s %f" % (suffix, peak.psfFitFlux * np.sum(peak.templateImage.getArray()))) peakList.append(peak.peak) return deblendedSource
footPrintSet = afwDetect.FootprintSet(footPrintSet, grow, isotropic) footPrints = footPrintSet.getFootprints() footPrintSet.setMask(mi.getMask(), "DETECTED") print footPrints.size(), "footPrint(s) found\n" mask = mi.getMask() mask.addMaskPlane('MUON') mask.addMaskPlane('WORM') mask.addMaskPlane('SPOT') mask.printMaskPlanes() muon_bit, worm_bit, spot_bit = mask.getPlaneBitMask('MUON'), mask.getPlaneBitMask('WORM'), mask.getPlaneBitMask('SPOT') # print muon_bit, worm_bit, spot_bit afwDetect.setMaskFromFootprint(mask, footPrints[9], muon_bit) ShowImage(mi, ROI_Bbox = footPrints[9].getBBox(), border = 0) # exit() #=============================================================================== # Shape extraction if DISPLAY_LEVEL >= 1: try: # initialise DS9, deal with a bug in its launching ds9.initDS9(False)
def testInclude(self): """Test that we can expand a Footprint to include the union of itself and all others provided.""" region = afwGeom.Box2I(afwGeom.Point2I(-6, -6), afwGeom.Point2I(6, 6)) parent = afwDetect.Footprint(afwGeom.Box2I(afwGeom.Point2I(-2, -2), afwGeom.Point2I(2, 2)), region) parent.addPeak(0, 0, float("NaN")) child1 = afwDetect.Footprint(afwGeom.Box2I(afwGeom.Point2I(-3, 0), afwGeom.Point2I(0, 3)), region) child1.addPeak(-1, 1, float("NaN")) child2 = afwDetect.Footprint(afwGeom.Box2I(afwGeom.Point2I(-4, -3), afwGeom.Point2I(-1, 0)), region) child3 = afwDetect.Footprint(afwGeom.Box2I(afwGeom.Point2I(4, -1), afwGeom.Point2I(6, 1))) merge123 = afwDetect.Footprint(parent) merge123.include([child1, child2, child3]) self.assertTrue(merge123.getBBox().contains(parent.getBBox())) self.assertTrue(merge123.getBBox().contains(child1.getBBox())) self.assertTrue(merge123.getBBox().contains(child2.getBBox())) self.assertTrue(merge123.getBBox().contains(child3.getBBox())) mask123a = afwImage.MaskU(region) mask123b = afwImage.MaskU(region) afwDetect.setMaskFromFootprint(mask123a, parent, 1) afwDetect.setMaskFromFootprint(mask123a, child1, 1) afwDetect.setMaskFromFootprint(mask123a, child2, 1) afwDetect.setMaskFromFootprint(mask123a, child3, 1) afwDetect.setMaskFromFootprint(mask123b, merge123, 1) self.assertEqual(mask123a.getArray().sum(), merge123.getArea()) self.assertClose(mask123a.getArray(), mask123b.getArray(), rtol=0, atol=0) # Test that ignoreSelf=True works for include ignoreParent = True childOnly = afwDetect.Footprint() childOnly.include([child1, child2, child3]) merge123 = afwDetect.Footprint(parent) merge123.include([child1, child2, child3], ignoreParent) maskChildren = afwImage.MaskU(region) mask123 = afwImage.MaskU(region) afwDetect.setMaskFromFootprint(maskChildren, childOnly, 1) afwDetect.setMaskFromFootprint(mask123, merge123, 1) self.assertTrue(numpy.all(maskChildren.getArray() == mask123.getArray()))
def __init__(self, config, exposure, footprints, noiseImage=None, exposureId=None, log=None): """! Initialize the NoiseReplacer. @param[in] config instance of NoiseReplacerConfig @param[in,out] exposure Exposure to be noise replaced. (All sources replaced on return) @param[in] footprints dict of {id: (parent, footprint)}; @param[in] noiseImage an afw.image.ImageF used as a predictable noise replacement source (for tests only) @param[in] log pex.logging.Log object to use for status messages; no status messages will be printed if None 'footprints' is a dict of {id: (parent, footprint)}; when used in SFM, the ID will be the source ID, but in forced photometry, this will be the reference ID, as that's what we used to determine the deblend families. This routine should create HeavyFootprints for any non-Heavy Footprints, and replace them in the dict. It should then create a dict of HeavyFootprints containing noise, but only for parent objects, then replace all sources with noise. This should ignore any footprints that lay outside the bounding box of the exposure, and clip those that lie on the border. NOTE: as the code currently stands, the heavy footprint for a deblended object must be available from the input catalog. If it is not, it cannot be reproduced here. In that case, the topmost parent in the objects parent chain must be used. The heavy footprint for that source is created in this class from the masked image. """ noiseMeanVar=None self.noiseSource = config.noiseSource self.noiseOffset = config.noiseOffset self.noiseSeedMultiplier = config.noiseSeedMultiplier self.noiseGenMean = None self.noiseGenStd = None self.log = log # creates heavies, replaces all footprints with noise # We need the source table to be sorted by ID to do the parent lookups self.exposure = exposure self.footprints = footprints mi = exposure.getMaskedImage() im = mi.getImage() mask = mi.getMask() # Add temporary Mask planes for THISDET and OTHERDET self.removeplanes = [] bitmasks = [] for maskname in ['THISDET', 'OTHERDET']: try: # does it already exist? plane = mask.getMaskPlane(maskname) if self.log: self.log.logdebug('Mask plane "%s" already existed' % maskname) except: # if not, add it; we should delete it when done. plane = mask.addMaskPlane(maskname) self.removeplanes.append(maskname) mask.clearMaskPlane(plane) bitmask = mask.getPlaneBitMask(maskname) bitmasks.append(bitmask) if self.log: self.log.logdebug('Mask plane "%s": plane %i, bitmask %i = 0x%x' % (maskname, plane, bitmask, bitmask)) self.thisbitmask,self.otherbitmask = bitmasks del bitmasks self.heavies = {} # Start by creating HeavyFootprints for each source which has no parent # and just use them for children which do not already have heavy footprints. # If a heavy footprint is available for a child, we will use it. Otherwise, # we use the first parent in the parent chain which has a heavy footprint, # which with the one level deblender will alway be the topmost parent # NOTE: heavy footprints get destroyed by the transform process in forcedPhotImage.py, # so they are never available for forced measurements. # Create in the dict heavies = {id:heavyfootprint} for id in footprints.keys(): fp = footprints[id] if fp[1].isHeavy(): self.heavies[id] = afwDet.cast_HeavyFootprintF(fp[1]) elif fp[0] == 0: self.heavies[id] = afwDet.makeHeavyFootprint(fp[1], mi) ### FIXME: the heavy footprint includes the mask ### and variance planes, which we shouldn't need ### (I don't think we ever want to modify them in ### the input image). Copying them around is ### wasteful. # We now create a noise HeavyFootprint for each source with has a heavy footprint. # We'll put the noise footprints in a dict heavyNoise = {id:heavyNoiseFootprint} self.heavyNoise = {} noisegen = self.getNoiseGenerator(exposure, noiseImage, noiseMeanVar, exposureId=exposureId) # The noiseGenMean and Std are used by the unit tests self.noiseGenMean = noisegen.mean self.noiseGenStd = noisegen.std if self.log: self.log.logdebug('Using noise generator: %s' % (str(noisegen))) for id in self.heavies.keys(): fp = footprints[id][1] noiseFp = noisegen.getHeavyFootprint(fp) self.heavyNoise[id] = noiseFp # Also insert the noisy footprint into the image now. # Notice that we're just inserting it into "im", ie, # the Image, not the MaskedImage. noiseFp.insert(im) # Also set the OTHERDET bit afwDet.setMaskFromFootprint(mask, fp, self.otherbitmask)
def begin(self, exposure, sources, noiseImage=None, noiseMeanVar=None): # creates heavies, replaces all footprints with noise # We need the source table to be sorted by ID to do the parent lookups # (sources.find() below) if not sources.isSorted(): sources.sort() mi = exposure.getMaskedImage() im = mi.getImage() mask = mi.getMask() # Add temporary Mask planes for THISDET and OTHERDET self.removeplanes = [] bitmasks = [] for maskname in ['THISDET', 'OTHERDET']: try: # does it already exist? plane = mask.getMaskPlane(maskname) self.log.logdebug('Mask plane "%s" already existed' % maskname) except: # if not, add it; we should delete it when done. plane = mask.addMaskPlane(maskname) self.removeplanes.append(maskname) mask.clearMaskPlane(plane) bitmask = mask.getPlaneBitMask(maskname) bitmasks.append(bitmask) self.log.logdebug('Mask plane "%s": plane %i, bitmask %i = 0x%x' % (maskname, plane, bitmask, bitmask)) self.thisbitmask, self.otherbitmask = bitmasks del bitmasks # Start by creating HeavyFootprints for each source. # # The "getParent()" checks are here because top-level # sources (ie, those with no parents) are not supposed to # have HeavyFootprints, but child sources (ie, those that # have been deblended) should have HeavyFootprints # already. self.heavies = [] for source in sources: fp = source.getFootprint() hfp = afwDet.cast_HeavyFootprintF(fp) if source.getParent() and hfp is not None: # this source has been deblended; "fp" should # already be a HeavyFootprint (but may not be # if read from disk). # Swig downcasts it to Footprint, so we have to re-cast. self.heavies.append(hfp) else: # top-level source: copy pixels from the input # image. ### FIXME: the heavy footprint includes the mask ### and variance planes, which we shouldn't need ### (I don't think we ever want to modify them in ### the input image). Copying them around is ### wasteful. heavy = afwDet.makeHeavyFootprint(fp, mi) self.heavies.append(heavy) # We now create a noise HeavyFootprint for each top-level Source. # We'll put the noisy footprints in a map from id -> HeavyFootprint: self.heavyNoise = {} noisegen = self.getNoiseGenerator(exposure, noiseImage, noiseMeanVar) self.log.logdebug('Using noise generator: %s' % (str(noisegen))) for source in sources: if source.getParent(): continue fp = source.getFootprint() heavy = noisegen.getHeavyFootprint(fp) self.heavyNoise[source.getId()] = heavy # Also insert the noisy footprint into the image now. # Notice that we're just inserting it into "im", ie, # the Image, not the MaskedImage. heavy.insert(im) # Also set the OTHERDET bit afwDet.setMaskFromFootprint(mask, fp, self.otherbitmask)
def begin(self, exposure, sources, noiseImage=None, noiseMeanVar=None): # creates heavies, replaces all footprints with noise # We need the source table to be sorted by ID to do the parent lookups # (sources.find() below) if not sources.isSorted(): sources.sort() mi = exposure.getMaskedImage() im = mi.getImage() mask = mi.getMask() # Add temporary Mask planes for THISDET and OTHERDET self.removeplanes = [] bitmasks = [] for maskname in ['THISDET', 'OTHERDET']: try: # does it already exist? plane = mask.getMaskPlane(maskname) self.log.logdebug('Mask plane "%s" already existed' % maskname) except: # if not, add it; we should delete it when done. plane = mask.addMaskPlane(maskname) self.removeplanes.append(maskname) mask.clearMaskPlane(plane) bitmask = mask.getPlaneBitMask(maskname) bitmasks.append(bitmask) self.log.logdebug('Mask plane "%s": plane %i, bitmask %i = 0x%x' % (maskname, plane, bitmask, bitmask)) self.thisbitmask,self.otherbitmask = bitmasks del bitmasks # Start by creating HeavyFootprints for each source. # # The "getParent()" checks are here because top-level # sources (ie, those with no parents) are not supposed to # have HeavyFootprints, but child sources (ie, those that # have been deblended) should have HeavyFootprints # already. self.heavies = [] for source in sources: fp = source.getFootprint() hfp = afwDet.cast_HeavyFootprintF(fp) if source.getParent() and hfp is not None: # this source has been deblended; "fp" should # already be a HeavyFootprint (but may not be # if read from disk). # Swig downcasts it to Footprint, so we have to re-cast. self.heavies.append(hfp) else: # top-level source: copy pixels from the input # image. ### FIXME: the heavy footprint includes the mask ### and variance planes, which we shouldn't need ### (I don't think we ever want to modify them in ### the input image). Copying them around is ### wasteful. heavy = afwDet.makeHeavyFootprint(fp, mi) self.heavies.append(heavy) # We now create a noise HeavyFootprint for each top-level Source. # We'll put the noisy footprints in a map from id -> HeavyFootprint: self.heavyNoise = {} noisegen = self.getNoiseGenerator(exposure, noiseImage, noiseMeanVar) self.log.logdebug('Using noise generator: %s' % (str(noisegen))) for source in sources: if source.getParent(): continue fp = source.getFootprint() heavy = noisegen.getHeavyFootprint(fp) self.heavyNoise[source.getId()] = heavy # Also insert the noisy footprint into the image now. # Notice that we're just inserting it into "im", ie, # the Image, not the MaskedImage. heavy.insert(im) # Also set the OTHERDET bit afwDet.setMaskFromFootprint(mask, fp, self.otherbitmask)
match = maskFormat.match(datasec) if match == None: # unable to match mask area! print '# WARNING: Extn', nExt, 'unable to parse', maskArea continue group = map(int, match.groups()) # ACB : by visual inspection, the y0 values can be too # high by 1. however, since some of the y0 values are '1' # in the mask string, i can't decrement this by 2 without # going off the image. we just deal with this for dc3a. bbox = afwImage.BBox(afwImage.PointI(group[0]-1, group[1]-1), afwImage.PointI(group[2]-1, group[3]-1)) fp = afwDetection.Footprint(bbox) afwDetection.setMaskFromFootprint(mask, fp, bitmask) # debugging #outfile0 = '%d.fits' % (i) #print '# Writing', outfile0 #mask.writeFits(outfile0) # trim this thing! it includes the overscan etc... bboxA = afwImage.BBox(afwImage.PointI(32,0), afwImage.PointI(1055,4611)) bboxB = afwImage.BBox(afwImage.PointI(1055,0), afwImage.PointI(2111-32,4611)) #bboxA = afwImage.BBox(afwImage.PointI(0,0),