def footprintToImage(fp, mi=None, mask=False): if fp.isHeavy(): try: fp = afwDet.cast_HeavyFootprintF(fp) # not needed with pybind11 except AttributeError: pass pass elif mi is None: print("Unable to make a HeavyFootprint as image is None", file=sys.stderr) else: fp = afwDet.makeHeavyFootprint(fp, mi) bb = fp.getBBox() if mask: im = afwImage.MaskedImageF(bb.getWidth(), bb.getHeight()) else: im = afwImage.ImageF(bb.getWidth(), bb.getHeight()) im.setXY0(bb.getMinX(), bb.getMinY()) try: fp.insert(im) except AttributeError: # we failed to make it heavy assert not mi pass if mask: im = im.getMask() return im
def footprintToImage(fp, mi=None, mask=False): if fp.isHeavy(): try: fp = afwDet.cast_HeavyFootprintF(fp) # not needed with pybind11 except AttributeError: pass pass elif mi is None: print >> sys.stderr, "Unable to make a HeavyFootprint as image is None" else: fp = afwDet.makeHeavyFootprint(fp, mi) bb = fp.getBBox() if mask: im = afwImage.MaskedImageF(bb.getWidth(), bb.getHeight()) else: im = afwImage.ImageF(bb.getWidth(), bb.getHeight()) im.setXY0(bb.getMinX(), bb.getMinY()) try: fp.insert(im) except AttributeError: # we failed to make it heavy assert not mi pass if mask: im = im.getMask() return im
def makePortionFigure(deblend, origMimg, origMimgB, pedestal=0.0): portions = [] centers = [] boxes = [] for i, peak in enumerate(deblend.peaks): # make an image matching the size of the original portionedImg = afwImage.ImageF(origMimg.getBBox()) # get the heavy footprint for the flux aportioned to this peak heavyFoot = afwDet.cast_HeavyFootprintF(peak.getFluxPortion()) footBox = heavyFoot.getBBox() pk = peak.peak centers.append((pk.getIx(), pk.getIy())) boxes.append(( (footBox.getMinX(), footBox.getMinY()), footBox.getWidth(), footBox.getHeight())) print i, peak, pk.getIx(), pk.getIy(), footBox, "skip:", peak.skip # make a sub-image for this peak, and put the aportioned flux into it portionedSubImg = afwImage.ImageF(portionedImg, footBox) portionedSubImg += pedestal heavyFoot.insert(portionedSubImg) portions.append(portionedImg) fig = figure.Figure(figsize=(8,10)) canvas = FigCanvas(fig) g = int(numpy.ceil(numpy.sqrt(len(deblend.peaks)))) gx, gy = g, g+1 def makeAx(ax, im, title): im = im.getArray() a = ax.imshow(im, cmap='gray') cb = fig.colorbar(a) ax.set_title(title, size='small') ax.set_xlim((0, im.shape[0])) ax.set_ylim((0, im.shape[1])) for t in ax.get_xticklabels() + ax.get_yticklabels() + cb.ax.get_yticklabels(): t.set_size('x-small') return ax # show the originals makeAx(fig.add_subplot(gy, gx, 1), origMimg.getImage(), "Orig") makeAx(fig.add_subplot(gy, gx, 2), origMimgB.getImage(), "Missing Src") # show each aportioned image i = gy for i_p in range(len(portions)): im = portions[i_p] ax = makeAx(fig.add_subplot(gy, gx, i), im, "") xy, w, h = boxes[i_p] ax.add_patch(Rectangle(xy, w, h, fill=False, edgecolor='#ff0000')) for x,y in centers: ax.plot(x, y, '+', color='#00ff00') i += 1 return fig
def test1(self): im = afwImage.ImageF(100, 100) im += 42. fp = afwDet.Footprint(afwGeom.Point2I(50,50), 10.) #seed = 42 #rand = afwMath.Random(afwMath.Random.MT19937, seed) #afwMath.randomGaussianImage(im, rand) mi = afwImage.MaskedImageF(im) # set a mask bit before grabbing the heavyfootprint mi.getMask().set(50, 50, 1) heavy = afwDet.makeHeavyFootprint(fp, mi) # reset it mi.getMask().set(50, 50, 0) schema = afwTable.SourceTable.makeMinimalSchema() table = afwTable.SourceTable.make(schema) table.preallocate(10) catalog = afwTable.SourceCatalog(table) catalog.addNew() # This used to segfault catalog[0].setFootprint(heavy) # However, we still have to up-cast fp = catalog[0].getFootprint() hfp = afwDet.cast_HeavyFootprintF(fp) # change one pixel... self.assertEqual(mi.getImage().get(50, 50), 42) self.assertEqual(mi.getMask().get(50, 50), 0) mi.getImage().set(50, 50, 100) mi.getMask().set(50, 50, 2) mi.getMask().set(51, 50, 2) self.assertEqual(mi.getImage().get(50, 50), 100) self.assertEqual(mi.getMask().get(50, 50), 2) self.assertEqual(mi.getMask().get(51, 50), 2) # reinsert the heavy footprint; it should reset the pixel value. # insert(MaskedImage) hfp.insert(mi) self.assertEqual(mi.getImage().get(50, 50), 42) self.assertEqual(mi.getMask().get(50, 50), 1) self.assertEqual(mi.getMask().get(51, 50), 0) # Also test insert(Image) im = mi.getImage() self.assertEqual(im.get(50, 50), 42) im.set(50, 50, 100) self.assertEqual(im.get(50, 50), 100) self.assertEqual(mi.getImage().get(50, 50), 100) # reinsert the heavy footprint; it should reset the pixel value. hfp.insert(im) self.assertEqual(im.get(50, 50), 42) self.assertEqual(mi.getImage().get(50, 50), 42) self.assertEqual(mi.getMask().get(50, 50), 1) self.assertEqual(mi.getMask().get(51, 50), 0)
def testMakeHeavy(self): """Test that we can make a FootprintSet heavy""" fs = afwDetect.FootprintSet(self.mi, afwDetect.Threshold(1)) ctrl = afwDetect.HeavyFootprintCtrl(afwDetect.HeavyFootprintCtrl.NONE) fs.makeHeavy(self.mi, ctrl) if display: ds9.mtv(self.mi, frame=0, title="input") #ds9.mtv(omi, frame=1, title="output") omi = self.mi.Factory(self.mi.getDimensions()) for foot in fs.getFootprints(): self.assertNotEqual(afwDetect.cast_HeavyFootprint(foot, self.mi), None) afwDetect.cast_HeavyFootprint(foot, self.mi).insert(omi) for foot in fs.getFootprints(): self.assertNotEqual(afwDetect.cast_HeavyFootprintF(foot), None) afwDetect.cast_HeavyFootprintF(foot).insert(omi) self.assertTrue(np.all(np.equal(self.mi.getImage().getArray(), omi.getImage().getArray())))
def footprintToImage(fp, mi=None, mask=False): if fp.isHeavy(): fp = afwDet.cast_HeavyFootprintF(fp) else: fp = afwDet.makeHeavyFootprint(fp, mi) bb = fp.getBBox() if mask: im = afwImage.MaskedImageF(bb.getWidth(), bb.getHeight()) else: im = afwImage.ImageF(bb.getWidth(), bb.getHeight()) im.setXY0(bb.getMinX(), bb.getMinY()) fp.insert(im) if mask: im = im.getMask() return im
def testCast_HeavyFootprint(self): """Test that we can cast a Footprint to a HeavyFootprint""" hfoot = afwDetect.makeHeavyFootprint(self.foot, self.mi) ctrl = afwDetect.HeavyFootprintCtrl(afwDetect.HeavyFootprintCtrl.NONE) hfoot = afwDetect.makeHeavyFootprint(self.foot, self.mi, ctrl) # # This isn't quite a full test, as hfoot is already a HeavyFootprint, # the complete test is in testMakeHeavy # self.assertNotEqual(afwDetect.cast_HeavyFootprint(hfoot, self.mi), None, "Cast to the right sort of HeavyFootprint") self.assertNotEqual(afwDetect.cast_HeavyFootprintF(hfoot), None, "Cast to the right sort of HeavyFootprint") self.assertEqual(afwDetect.cast_HeavyFootprint(self.foot, self.mi), None, "Can't cast a Footprint to a HeavyFootprint") self.assertEqual(afwDetect.cast_HeavyFootprintI(hfoot), None, "Cast to the wrong sort of HeavyFootprint")
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 __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 __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)