def thresholdImage(self, image, thresholdParity, maskName="DETECTED"): """!Threshold the convolved image, returning a FootprintSet. Helper function for detect(). \param image The (optionally convolved) MaskedImage to threshold \param thresholdParity Parity of threshold \param maskName Name of mask to set \return FootprintSet """ parity = False if thresholdParity == "negative" else True threshold = afwDet.createThreshold(self.config.thresholdValue, self.config.thresholdType, parity) threshold.setIncludeMultiplier(self.config.includeThresholdMultiplier) if self.config.thresholdType == 'stdev': bad = image.getMask().getPlaneBitMask(['BAD', 'SAT', 'EDGE', 'NO_DATA',]) sctrl = afwMath.StatisticsControl() sctrl.setAndMask(bad) stats = afwMath.makeStatistics(image, afwMath.STDEVCLIP, sctrl) thres = stats.getValue(afwMath.STDEVCLIP) * self.config.thresholdValue threshold = afwDet.createThreshold(thres, 'value', parity) threshold.setIncludeMultiplier(self.config.includeThresholdMultiplier) fpSet = afwDet.FootprintSet(image, threshold, maskName, self.config.minPixels) return fpSet
def makeThreshold(self, image, thresholdParity): """Make an afw.detection.Threshold object corresponding to the task's configuration and the statistics of the given image. Parameters ---------- image : `afw.image.MaskedImage` Image to measure noise statistics from if needed. thresholdParity: `str` One of "positive" or "negative", to set the kind of fluctuations the Threshold will detect. """ parity = False if thresholdParity == "negative" else True threshold = afwDet.createThreshold(self.config.thresholdValue, self.config.thresholdType, parity) threshold.setIncludeMultiplier(self.config.includeThresholdMultiplier) if self.config.thresholdType == 'stdev': bad = image.getMask().getPlaneBitMask([ 'BAD', 'SAT', 'EDGE', 'NO_DATA', ]) sctrl = afwMath.StatisticsControl() sctrl.setAndMask(bad) stats = afwMath.makeStatistics(image, afwMath.STDEVCLIP, sctrl) thres = (stats.getValue(afwMath.STDEVCLIP) * self.config.thresholdValue) threshold = afwDet.createThreshold(thres, 'value', parity) threshold.setIncludeMultiplier( self.config.includeThresholdMultiplier) return threshold
def thresholdImage(self, image, thresholdParity, maskName="DETECTED"): """!Threshold the convolved image, returning a FootprintSet. Helper function for detect(). \param image The (optionally convolved) MaskedImage to threshold \param thresholdParity Parity of threshold \param maskName Name of mask to set \return FootprintSet """ parity = False if thresholdParity == "negative" else True threshold = afwDet.createThreshold(self.config.thresholdValue, self.config.thresholdType, parity) threshold.setIncludeMultiplier(self.config.includeThresholdMultiplier) if self.config.thresholdType == 'stdev': bad = image.getMask().getPlaneBitMask([ 'BAD', 'SAT', 'EDGE', 'NO_DATA', ]) sctrl = afwMath.StatisticsControl() sctrl.setAndMask(bad) stats = afwMath.makeStatistics(image, afwMath.STDEVCLIP, sctrl) thres = stats.getValue( afwMath.STDEVCLIP) * self.config.thresholdValue threshold = afwDet.createThreshold(thres, 'value', parity) threshold.setIncludeMultiplier( self.config.includeThresholdMultiplier) fpSet = afwDet.FootprintSet(image, threshold, maskName, self.config.minPixels) return fpSet
def makeThreshold(self, image, thresholdParity, factor=1.0): """Make an afw.detection.Threshold object corresponding to the task's configuration and the statistics of the given image. Parameters ---------- image : `afw.image.MaskedImage` Image to measure noise statistics from if needed. thresholdParity: `str` One of "positive" or "negative", to set the kind of fluctuations the Threshold will detect. factor : `float` Factor by which to multiply the configured detection threshold. This is useful for tweaking the detection threshold slightly. Returns ------- threshold : `lsst.afw.detection.Threshold` Detection threshold. """ parity = False if thresholdParity == "negative" else True thresholdValue = self.config.thresholdValue thresholdType = self.config.thresholdType if self.config.thresholdType == 'stdev': bad = image.getMask().getPlaneBitMask(self.config.statsMask) sctrl = afwMath.StatisticsControl() sctrl.setAndMask(bad) stats = afwMath.makeStatistics(image, afwMath.STDEVCLIP, sctrl) thresholdValue *= stats.getValue(afwMath.STDEVCLIP) thresholdType = 'value' threshold = afwDet.createThreshold(thresholdValue*factor, thresholdType, parity) threshold.setIncludeMultiplier(self.config.includeThresholdMultiplier) return threshold
def testPeakRemoval(self): ''' A simple example: three overlapping blobs (detected as 1 footprint with three peaks). Additional peaks are added near the blob peaks that should be identified as degenerate. ''' H, W = 100, 100 fpbb = geom.Box2I(geom.Point2I(0, 0), geom.Point2I(W - 1, H - 1)) afwimg = afwImage.MaskedImageF(fpbb) imgbb = afwimg.getBBox() img = afwimg.getImage().getArray() var = afwimg.getVariance().getArray() var[:, :] = 1. blob_fwhm = 10. blob_psf = doubleGaussianPsf(99, 99, blob_fwhm, 2.*blob_fwhm, 0.03) fakepsf_fwhm = 3. fakepsf = gaussianPsf(11, 11, fakepsf_fwhm) blobimgs = [] x = 75. XY = [(x, 35.), (x, 65.), (50., 50.)] flux = 1e6 for x, y in XY: bim = blob_psf.computeImage(geom.Point2D(x, y)) bbb = bim.getBBox() bbb.clip(imgbb) bim = bim.Factory(bim, bbb) bim2 = bim.getArray() blobimg = np.zeros_like(img) blobimg[bbb.getMinY():bbb.getMaxY()+1, bbb.getMinX():bbb.getMaxX()+1] += flux*bim2 blobimgs.append(blobimg) img[bbb.getMinY():bbb.getMaxY()+1, bbb.getMinX():bbb.getMaxX()+1] += flux * bim2 # Run the detection code to get a ~ realistic footprint thresh = afwDet.createThreshold(5., 'value', True) fpSet = afwDet.FootprintSet(afwimg, thresh, 'DETECTED', 1) fps = fpSet.getFootprints() self.assertTrue(len(fps) == 1) # Add new peaks near to the first peaks that will be degenerate fp0 = fps[0] for x, y in XY: fp0.addPeak(x - 10, y + 6, 10) deb = deblend(fp0, afwimg, fakepsf, fakepsf_fwhm, verbose=True, removeDegenerateTemplates=True) self.assertTrue(deb.deblendedParents[0].peaks[3].degenerate) self.assertTrue(deb.deblendedParents[0].peaks[4].degenerate) self.assertTrue(deb.deblendedParents[0].peaks[5].degenerate)
def testPeakRemoval(self): ''' A simple example: three overlapping blobs (detected as 1 footprint with three peaks). Additional peaks are added near the blob peaks that should be identified as degenerate. ''' H, W = 100, 100 fpbb = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Point2I(W - 1, H - 1)) afwimg = afwImage.MaskedImageF(fpbb) imgbb = afwimg.getBBox() img = afwimg.getImage().getArray() var = afwimg.getVariance().getArray() var[:, :] = 1. blob_fwhm = 10. blob_psf = doubleGaussianPsf(99, 99, blob_fwhm, 2.*blob_fwhm, 0.03) fakepsf_fwhm = 3. fakepsf = gaussianPsf(11, 11, fakepsf_fwhm) blobimgs = [] x = 75. XY = [(x, 35.), (x, 65.), (50., 50.)] flux = 1e6 for x, y in XY: bim = blob_psf.computeImage(afwGeom.Point2D(x, y)) bbb = bim.getBBox() bbb.clip(imgbb) bim = bim.Factory(bim, bbb) bim2 = bim.getArray() blobimg = np.zeros_like(img) blobimg[bbb.getMinY():bbb.getMaxY()+1, bbb.getMinX():bbb.getMaxX()+1] += flux*bim2 blobimgs.append(blobimg) img[bbb.getMinY():bbb.getMaxY()+1, bbb.getMinX():bbb.getMaxX()+1] += flux * bim2 # Run the detection code to get a ~ realistic footprint thresh = afwDet.createThreshold(5., 'value', True) fpSet = afwDet.FootprintSet(afwimg, thresh, 'DETECTED', 1) fps = fpSet.getFootprints() self.assertTrue(len(fps) == 1) # Add new peaks near to the first peaks that will be degenerate fp0 = fps[0] for x, y in XY: fp0.addPeak(x - 10, y + 6, 10) deb = deblend(fp0, afwimg, fakepsf, fakepsf_fwhm, verbose=True, removeDegenerateTemplates=True) self.assertTrue(deb.deblendedParents[0].peaks[3].degenerate) self.assertTrue(deb.deblendedParents[0].peaks[4].degenerate) self.assertTrue(deb.deblendedParents[0].peaks[5].degenerate)
def psf(self, exposure, sources): """Measure the PSF @param exposure Exposure to process @param sources Measured sources on exposure """ assert exposure, "No exposure provided" assert sources, "No sources provided" psfPolicy = self.config['psf'] selName = psfPolicy['selectName'] selPolicy = psfPolicy['select'].getPolicy() algName = psfPolicy['algorithmName'] algPolicy = psfPolicy['algorithm'].getPolicy() self.log.log(self.log.INFO, "Measuring PSF") # # Run an extra detection step to mask out faint stars # if False: print "RHL is cleaning faint sources" import lsst.afw.math as afwMath sigma = 1.0 gaussFunc = afwMath.GaussianFunction1D(sigma) gaussKernel = afwMath.SeparableKernel(15, 15, gaussFunc, gaussFunc) im = exposure.getMaskedImage().getImage() convolvedImage = im.Factory(im.getDimensions()) afwMath.convolve(convolvedImage, im, gaussKernel) del im fs = afwDet.makeFootprintSet(convolvedImage, afwDet.createThreshold(4, "stdev")) fs = afwDet.makeFootprintSet(fs, 3, True) fs.setMask(exposure.getMaskedImage().getMask(), "DETECTED") starSelector = measAlg.makeStarSelector(selName, selPolicy) psfCandidateList = starSelector.selectStars(exposure, sources) psfDeterminer = measAlg.makePsfDeterminer(algName, algPolicy) psf, cellSet = psfDeterminer.determinePsf(exposure, psfCandidateList) # The PSF candidates contain a copy of the source, and so we need to explicitly propagate new flags for cand in psfCandidateList: cand = measAlg.cast_PsfCandidateF(cand) src = cand.getSource() if src.getFlagForDetection() & measAlg.Flags.PSFSTAR: ident = src.getId() src = sources[ident] assert src.getId() == ident src.setFlagForDetection(src.getFlagForDetection() | measAlg.Flags.PSFSTAR) exposure.setPsf(psf) return psf, cellSet
def threshold(image, threshold, positive, log=None): thresh = afwDet.createThreshold(threshold, "value", positive) feet = afwDet.makeFootprintSet(image, thresh) if log is not None: log.log(log.INFO, "Found %d footprints" % len(feet.getFootprints())) pixels = afwImage.ImageU(image.getDimensions()) pixels.set(0) for foot in feet.getFootprints(): foot.insertIntoImage(pixels, 1) return pixels
def detect(mimg): thresh = afwDet.createThreshold(10., 'value', True) fpSet = afwDet.FootprintSet(mimg, thresh, 'DETECTED', 1) fps = fpSet.getFootprints() print 'found', len(fps), 'footprints' for fp in fps: print 'peaks:', len(fp.getPeaks()) for pk in fp.getPeaks(): print ' ', pk.getIx(), pk.getIy() return fps[0] if fps else None
def detect(mimg): thresh = afwDet.createThreshold(10., 'value', True) fpSet = afwDet.FootprintSet(mimg, thresh, 'DETECTED', 1) fps = fpSet.getFootprints() print('found', len(fps), 'footprints') for fp in fps: print('peaks:', len(fp.getPeaks())) for pk in fp.getPeaks(): print(' ', pk.getIx(), pk.getIy()) return fps[0] if fps else None
def testFootprints(self): """Check that we found the correct number of objects using FootprintSet""" level = 0x2 ds = afwDetect.FootprintSet(self.mim.getMask(), afwDetect.createThreshold(level, "bitmask")) objects = ds.getFootprints() if 0 and display: ds9.mtv(self.mim, frame=0) self.assertEqual(len(objects), len([o for o in self.objects if (o.val & level)])) i = 0 for o in self.objects: if o.val & level: self.assertEqual(o, objects[i]) i += 1
def thresholdImage(self, image, thresholdParity, maskName="DETECTED"): """Threshold the convolved image, returning a FootprintSet. Helper function for detect(). @param image The (optionally convolved) MaskedImage to threshold @param thresholdParity Parity of threshold @param maskName Name of mask to set @return FootprintSet """ parity = False if thresholdParity == "negative" else True threshold = afwDet.createThreshold(self.config.thresholdValue, self.config.thresholdType, parity) threshold.setIncludeMultiplier(self.config.includeThresholdMultiplier) fpSet = afwDet.FootprintSet(image, threshold, maskName, self.config.minPixels) return fpSet
def testFootprints3(self): """Check that we found the correct number of objects using FootprintSet and PIXEL_STDEV""" threshold = 4.5 # in units of sigma self.ms.set(2, 4, (10, 0x0, 36)) # not detected (high variance) y, x = self.objects[2].spans[0][0:2] self.ms.set(x, y, (threshold, 0x0, 1.0)) ds = afwDetect.FootprintSet(self.ms, afwDetect.createThreshold(threshold, "pixel_stdev"), "OBJECT") objects = ds.getFootprints() self.assertEqual(len(objects), len(self.objects)) for i in range(len(objects)): self.assertEqual(objects[i], self.objects[i])
def testFootprints3(self): """Check that we found the correct number of objects using FootprintSet and PIXEL_STDEV""" threshold = 4.5 # in units of sigma self.ms[2, 4, afwImage.LOCAL] = (10, 0x0, 36) # not detected (high variance) y, x = self.objects[2].spans[0][0:2] self.ms[x, y, afwImage.LOCAL] = (threshold, 0x0, 1.0) ds = afwDetect.FootprintSet(self.ms, afwDetect.createThreshold(threshold, "pixel_stdev"), "OBJECT") objects = ds.getFootprints() self.assertEqual(len(objects), len(self.objects)) for i in range(len(objects)): self.assertEqual(objects[i], self.objects[i])
def testInf(self): """Test detection for images with Infs""" im = afwImage.MaskedImageF(lsst.geom.Extent2I(10, 20)) im.set(0) import numpy for x in range(im.getWidth()): im[x, -1, afwImage.LOCAL] = (numpy.Inf, 0x0, 0) ds = afwDetect.FootprintSet(im, afwDetect.createThreshold(100)) objects = ds.getFootprints() afwDetect.setMaskFromFootprintList(im.getMask(), objects, 0x10) if display: afwDisplay.Display(frame=2).mtv(im, title=self._testMethodName + " image") self.assertEqual(len(objects), 1)
def testInf(self): """Test detection for images with Infs""" im = afwImage.MaskedImageF(afwGeom.Extent2I(10, 20)) im.set(0) import numpy for x in range(im.getWidth()): im.set(x, im.getHeight() - 1, (numpy.Inf, 0x0, 0)) ds = afwDetect.makeFootprintSet(im, afwDetect.createThreshold(100)) objects = ds.getFootprints() afwDetect.setMaskFromFootprintList(im.getMask(), objects, 0x10) if display: ds9.mtv(im) self.assertEqual(len(objects), 1)
def testInf(self): """Test detection for images with Infs""" im = afwImage.MaskedImageF(lsst.geom.Extent2I(10, 20)) im.set(0) import numpy for x in range(im.getWidth()): im[x, -1, afwImage.LOCAL] = (numpy.Inf, 0x0, 0) ds = afwDetect.FootprintSet(im, afwDetect.createThreshold(100)) objects = ds.getFootprints() afwDetect.setMaskFromFootprintList(im.getMask(), objects, 0x10) if display: ds9.mtv(im) self.assertEqual(len(objects), 1)
psf_im = psf_im.convertF() subim += psf_im print(" subim = ", subim) back_im = afwImage.ImageF(im.getBBox()) afwMath.randomPoissonImage(back_im, rand, 100) im += back_im display.mtv(im) display.incrDefaultFrame() mask = afwImage.MaskU(im.getBBox()) masked_im = afwImage.MaskedImageF(im, mask, im) sys.exit() threshold = afwDetect.createThreshold(5., 'stdev') fs = afwDetect.FootprintSet(masked_im, threshold, 'DETECTED') #display.mtv(masked_im) #display.incrDefaultFrame() bctrl = afwMath.BackgroundControl(11, 11) bkgd = afwMath.makeBackground(masked_im, bctrl) masked_im -= bkgd.getImageF() masked_im.getMask().set(0) # reset mask fs = afwDetect.FootprintSet(masked_im, threshold, 'DETECTED') #display.mtv(masked_im) #display.incrDefaultFrame() # numpy arrays from images im, mask, var = masked_im.getArrays() print type(im)
def test2(self): ''' A 1-d example, to test the stray-flux assignment. ''' H,W = 1,100 fpbb = afwGeom.Box2I(afwGeom.Point2I(0,0), afwGeom.Point2I(W-1,H-1)) afwimg = afwImage.MaskedImageF(fpbb) imgbb = afwimg.getBBox(afwImage.PARENT) img = afwimg.getImage().getArray() var = afwimg.getVariance().getArray() var[:,:] = 1. y = 0 img[y, 1:-1] = 10. img[0, 1] = 20. img[0, -2] = 20. fakepsf_fwhm = 1. fakepsf = gaussianPsf(1, 1, fakepsf_fwhm) # Run the detection code to get a ~ realistic footprint thresh = afwDet.createThreshold(5., 'value', True) fpSet = afwDet.FootprintSet(afwimg, thresh, 'DETECTED', 1) fps = fpSet.getFootprints() self.assertEqual(len(fps), 1) fp = fps[0] # WORKAROUND: the detection alg produces ONE peak, at (1,0), # rather than two. self.assertEqual(len(fp.getPeaks()), 1) fp.addPeak(W-2, y, float("NaN")) #print 'Added peak; peaks:', len(fp.getPeaks()) #for pk in fp.getPeaks(): # print ' ', pk.getFx(), pk.getFy() deb = deblend(fp, afwimg, fakepsf, fakepsf_fwhm, verbose=True, fitPsfs=False, ) if doPlot: XX = np.arange(W+1).repeat(2)[1:-1] plt.clf() p1 = plt.plot(XX, img[y,:].repeat(2), 'g-', lw=3, alpha=0.3) for i,dpk in enumerate(deb.peaks): print dpk port = dpk.fluxPortion.getImage() bb = port.getBBox(afwImage.PARENT) YY = np.zeros(XX.shape) YY[bb.getMinX()*2 : (bb.getMaxX()+1)*2] = port.getArray()[0,:].repeat(2) p2 = plt.plot(XX, YY, 'r-') simg = afwImage.ImageF(fpbb) dpk.strayFlux.insert(simg) p3 = plt.plot(XX, simg.getArray()[y,:].repeat(2), 'b-') plt.legend((p1[0],p2[0],p3[0]), ('Parent Flux', 'Child portion', 'Child stray flux')) plt.ylim(-2, 22) plt.savefig(plotpat % 3) strays = [] for i,dpk in enumerate(deb.peaks): simg = afwImage.ImageF(fpbb) dpk.strayFlux.insert(simg) strays.append(simg.getArray()) ssum = reduce(np.add, strays) starget = np.zeros(W) starget[2:-2] = 10. self.assertTrue(np.all(ssum == starget)) X = np.arange(W) dx1 = X - 1. dx2 = X - (W-2) f1 = (1. / (1. + dx1**2)) f2 = (1. / (1. + dx2**2)) strayclip = 0.001 fsum = f1 + f2 f1[f1 < strayclip * fsum] = 0. f2[f2 < strayclip * fsum] = 0. s1 = f1 / (f1+f2) * 10. s2 = f2 / (f1+f2) * 10. s1[:2] = 0. s2[-2:] = 0. if doPlot: p4 = plt.plot(XX, s1.repeat(2), 'm-') plt.plot(XX, s2.repeat(2), 'm-') plt.legend((p1[0],p2[0],p3[0],p4[0]), ('Parent Flux', 'Child portion', 'Child stray flux', 'Expected stray flux')) plt.ylim(-2, 22) plt.savefig(plotpat % 4) # test abs diff d = np.max(np.abs(s1 - strays[0])) self.assertTrue(d < 1e-6) d = np.max(np.abs(s2 - strays[1])) self.assertTrue(d < 1e-6) # test relative diff self.assertTrue(np.max(np.abs(s1 - strays[0]) / np.maximum(1e-3, s1)) < 1e-6) self.assertTrue(np.max(np.abs(s2 - strays[1]) / np.maximum(1e-3, s2)) < 1e-6)
def test1(self): ''' A simple example: three overlapping blobs (detected as 1 footprint with three peaks). We artificially omit one of the peaks, meaning that its flux is "stray". Assert that the stray flux assigned to the other two peaks accounts for all the flux in the parent. ''' H, W = 100, 100 fpbb = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Point2I(W-1, H-1)) afwimg = afwImage.MaskedImageF(fpbb) imgbb = afwimg.getBBox() img = afwimg.getImage().getArray() var = afwimg.getVariance().getArray() var[:, :] = 1. blob_fwhm = 10. blob_psf = doubleGaussianPsf(99, 99, blob_fwhm, 3.*blob_fwhm, 0.03) fakepsf_fwhm = 3. fakepsf = gaussianPsf(11, 11, fakepsf_fwhm) blobimgs = [] x = 75. XY = [(x, 35.), (x, 65.), (50., 50.)] flux = 1e6 for x, y in XY: bim = blob_psf.computeImage(afwGeom.Point2D(x, y)) bbb = bim.getBBox() bbb.clip(imgbb) bim = bim.Factory(bim, bbb) bim2 = bim.getArray() blobimg = np.zeros_like(img) blobimg[bbb.getMinY():bbb.getMaxY()+1, bbb.getMinX():bbb.getMaxX()+1] += flux * bim2 blobimgs.append(blobimg) img[bbb.getMinY():bbb.getMaxY()+1, bbb.getMinX():bbb.getMaxX()+1] += flux * bim2 # Run the detection code to get a ~ realistic footprint thresh = afwDet.createThreshold(5., 'value', True) fpSet = afwDet.FootprintSet(afwimg, thresh, 'DETECTED', 1) fps = fpSet.getFootprints() print('found', len(fps), 'footprints') pks2 = [] for fp in fps: print('peaks:', len(fp.getPeaks())) for pk in fp.getPeaks(): print(' ', pk.getIx(), pk.getIy()) pks2.append((pk.getIx(), pk.getIy())) # The first peak in this list is the one we want to omit. fp0 = fps[0] fakefp = afwDet.Footprint(fp0.getSpans(), fp0.getBBox()) for pk in fp0.getPeaks()[1:]: fakefp.getPeaks().append(pk) ima = dict(interpolation='nearest', origin='lower', cmap='gray', vmin=0, vmax=1e3) if doPlot: plt.figure(figsize=(12, 6)) plt.clf() plt.suptitle('strayFlux.py: test1 input') plt.subplot(2, 2, 1) plt.title('Image') plt.imshow(img, **ima) ax = plt.axis() plt.plot([x for x, y in XY], [y for x, y in XY], 'r.') plt.axis(ax) for i, (b, (x, y)) in enumerate(zip(blobimgs, XY)): plt.subplot(2, 2, 2+i) plt.title('Blob %i' % i) plt.imshow(b, **ima) ax = plt.axis() plt.plot(x, y, 'r.') plt.axis(ax) plt.savefig(plotpat % 1) # Change verbose to False to quiet down the meas_deblender.baseline logger deb = deblend(fakefp, afwimg, fakepsf, fakepsf_fwhm, verbose=True) parent_img = afwImage.ImageF(fpbb) fakefp.spans.copyImage(afwimg.getImage(), parent_img) if doPlot: def myimshow(*args, **kwargs): plt.imshow(*args, **kwargs) plt.xticks([]) plt.yticks([]) plt.axis(imExt(afwimg)) plt.clf() plt.suptitle('strayFlux.py: test1 results') # R,C = 3,5 R, C = 3, 4 plt.subplot(R, C, (2*C) + 1) plt.title('Image') myimshow(img, **ima) ax = plt.axis() plt.plot([x for x, y in XY], [y for x, y in XY], 'r.') plt.axis(ax) plt.subplot(R, C, (2*C) + 2) plt.title('Parent footprint') myimshow(parent_img.getArray(), **ima) ax = plt.axis() plt.plot([pk.getIx() for pk in fakefp.getPeaks()], [pk.getIy() for pk in fakefp.getPeaks()], 'r.') plt.axis(ax) sumimg = None for i, dpk in enumerate(deb.peaks): plt.subplot(R, C, i*C + 1) plt.title('ch%i symm' % i) symm = dpk.templateImage myimshow(symm.getArray(), extent=imExt(symm), **ima) plt.subplot(R, C, i*C + 2) plt.title('ch%i portion' % i) port = dpk.fluxPortion.getImage() myimshow(port.getArray(), extent=imExt(port), **ima) himg = afwImage.ImageF(fpbb) heavy = dpk.getFluxPortion(strayFlux=False) heavy.insert(himg) # plt.subplot(R, C, i*C + 3) # plt.title('ch%i heavy' % i) # myimshow(himg.getArray(), **ima) # ax = plt.axis() # plt.plot([x for x,y in XY], [y for x,y in XY], 'r.') # plt.axis(ax) simg = afwImage.ImageF(fpbb) dpk.strayFlux.insert(simg) plt.subplot(R, C, i*C + 3) plt.title('ch%i stray' % i) myimshow(simg.getArray(), **ima) ax = plt.axis() plt.plot([x for x, y in XY], [y for x, y in XY], 'r.') plt.axis(ax) himg2 = afwImage.ImageF(fpbb) heavy = dpk.getFluxPortion(strayFlux=True) heavy.insert(himg2) if sumimg is None: sumimg = himg2.getArray().copy() else: sumimg += himg2.getArray() plt.subplot(R, C, i*C + 4) myimshow(himg2.getArray(), **ima) plt.title('ch%i total' % i) ax = plt.axis() plt.plot([x for x, y in XY], [y for x, y in XY], 'r.') plt.axis(ax) plt.subplot(R, C, (2*C) + C) myimshow(sumimg, **ima) ax = plt.axis() plt.plot([x for x, y in XY], [y for x, y in XY], 'r.') plt.axis(ax) plt.title('Sum of deblends') plt.savefig(plotpat % 2) # Compute the sum-of-children image sumimg = None for i, dpk in enumerate(deb.deblendedParents[0].peaks): himg2 = afwImage.ImageF(fpbb) dpk.getFluxPortion().insert(himg2) if sumimg is None: sumimg = himg2.getArray().copy() else: sumimg += himg2.getArray() # Sum of children ~= Original image inside footprint (parent_img) absdiff = np.max(np.abs(sumimg - parent_img.getArray())) print('Max abs diff:', absdiff) imgmax = parent_img.getArray().max() print('Img max:', imgmax) self.assertLess(absdiff, imgmax*1e-6)
def test2(self): ''' A 1-d example, to test the stray-flux assignment. ''' H, W = 1, 100 fpbb = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Point2I(W-1, H-1)) afwimg = afwImage.MaskedImageF(fpbb) img = afwimg.getImage().getArray() var = afwimg.getVariance().getArray() var[:, :] = 1. y = 0 img[y, 1:-1] = 10. img[0, 1] = 20. img[0, -2] = 20. fakepsf_fwhm = 1. fakepsf = gaussianPsf(1, 1, fakepsf_fwhm) # Run the detection code to get a ~ realistic footprint thresh = afwDet.createThreshold(5., 'value', True) fpSet = afwDet.FootprintSet(afwimg, thresh, 'DETECTED', 1) fps = fpSet.getFootprints() self.assertEqual(len(fps), 1) fp = fps[0] # WORKAROUND: the detection alg produces ONE peak, at (1,0), # rather than two. self.assertEqual(len(fp.getPeaks()), 1) fp.addPeak(W-2, y, float("NaN")) # print 'Added peak; peaks:', len(fp.getPeaks()) # for pk in fp.getPeaks(): # print ' ', pk.getFx(), pk.getFy() # Change verbose to False to quiet down the meas_deblender.baseline logger deb = deblend(fp, afwimg, fakepsf, fakepsf_fwhm, verbose=True, fitPsfs=False, ) if doPlot: XX = np.arange(W+1).repeat(2)[1:-1] plt.clf() p1 = plt.plot(XX, img[y, :].repeat(2), 'g-', lw=3, alpha=0.3) for i, dpk in enumerate(deb.peaks): print(dpk) port = dpk.fluxPortion.getImage() bb = port.getBBox() YY = np.zeros(XX.shape) YY[bb.getMinX()*2: (bb.getMaxX()+1)*2] = port.getArray()[0, :].repeat(2) p2 = plt.plot(XX, YY, 'r-') simg = afwImage.ImageF(fpbb) dpk.strayFlux.insert(simg) p3 = plt.plot(XX, simg.getArray()[y, :].repeat(2), 'b-') plt.legend((p1[0], p2[0], p3[0]), ('Parent Flux', 'Child portion', 'Child stray flux')) plt.ylim(-2, 22) plt.savefig(plotpat % 3) strays = [] for i, dpk in enumerate(deb.deblendedParents[0].peaks): simg = afwImage.ImageF(fpbb) dpk.strayFlux.insert(simg) strays.append(simg.getArray()) ssum = reduce(np.add, strays) starget = np.zeros(W) starget[2:-2] = 10. self.assertFloatsEqual(ssum, starget) X = np.arange(W) dx1 = X - 1. dx2 = X - (W-2) f1 = (1. / (1. + dx1**2)) f2 = (1. / (1. + dx2**2)) strayclip = 0.001 fsum = f1 + f2 f1[f1 < strayclip * fsum] = 0. f2[f2 < strayclip * fsum] = 0. s1 = f1 / (f1+f2) * 10. s2 = f2 / (f1+f2) * 10. s1[:2] = 0. s2[-2:] = 0. if doPlot: p4 = plt.plot(XX, s1.repeat(2), 'm-') plt.plot(XX, s2.repeat(2), 'm-') plt.legend((p1[0], p2[0], p3[0], p4[0]), ('Parent Flux', 'Child portion', 'Child stray flux', 'Expected stray flux')) plt.ylim(-2, 22) plt.savefig(plotpat % 4) # test abs diff d = np.max(np.abs(s1 - strays[0])) self.assertLess(d, 1e-6) d = np.max(np.abs(s2 - strays[1])) self.assertLess(d, 1e-6) # test relative diff self.assertLess(np.max(np.abs(s1 - strays[0])/np.maximum(1e-3, s1)), 1e-6) self.assertLess(np.max(np.abs(s2 - strays[1])/np.maximum(1e-3, s2)), 1e-6)
def findHotAndColdPixels(self, exp, nSigma): """Find hot and cold pixels in an image. Using config-defined thresholds on a per-amp basis, mask pixels that are nSigma above threshold in dark frames (hot pixels), or nSigma away from the clipped mean in flats (hot & cold pixels). Parameters ---------- exp : `lsst.afw.image.exposure.Exposure` The exposure in which to find defects. nSigma : `list [ `float` ] Detection threshold to use. Positive for DETECTED pixels, negative for DETECTED_NEGATIVE pixels. Returns ------- defects : `lsst.ip.isr.Defect` The defects found in the image. """ self._setEdgeBits(exp) maskedIm = exp.maskedImage # the detection polarity for afwDetection, True for positive, # False for negative, and therefore True for darks as they only have # bright pixels, and both for flats, as they have bright and dark pix footprintList = [] for amp in exp.getDetector(): ampImg = maskedIm[amp.getBBox()].clone() # crop ampImage depending on where the amp lies in the image if self.config.nPixBorderLeftRight: if ampImg.getX0() == 0: ampImg = ampImg[self.config.nPixBorderLeftRight:, :, afwImage.LOCAL] else: ampImg = ampImg[:-self.config.nPixBorderLeftRight, :, afwImage.LOCAL] if self.config.nPixBorderUpDown: if ampImg.getY0() == 0: ampImg = ampImg[:, self.config.nPixBorderUpDown:, afwImage.LOCAL] else: ampImg = ampImg[:, :-self.config.nPixBorderUpDown, afwImage.LOCAL] if self._getNumGoodPixels( ampImg) == 0: # amp contains no usable pixels continue # Remove a background estimate ampImg -= afwMath.makeStatistics( ampImg, afwMath.MEANCLIP, ).getValue() mergedSet = None for sigma in nSigma: nSig = np.abs(sigma) self.debugHistogram('ampFlux', ampImg, nSig, exp) polarity = {-1: False, 1: True}[np.sign(sigma)] threshold = afwDetection.createThreshold(nSig, 'stdev', polarity=polarity) footprintSet = afwDetection.FootprintSet(ampImg, threshold) footprintSet.setMask( maskedIm.mask, ("DETECTED" if polarity else "DETECTED_NEGATIVE")) if mergedSet is None: mergedSet = footprintSet else: mergedSet.merge(footprintSet) footprintList += mergedSet.getFootprints() self.debugView( 'defectMap', ampImg, Defects.fromFootprintList(mergedSet.getFootprints()), exp.getDetector()) defects = Defects.fromFootprintList(footprintList) defects = self.maskBlocksIfIntermitentBadPixelsInColumn(defects) return defects
def test1(self): ''' In this test, we create a test image containing two blobs, one of which is truncated by the edge of the image. We run the detection code to get realistic peaks and footprints. We then test out the different edge treatments and assert that they do what they claim. We also make plots, tests/edge*.png ''' # Create fake image... H, W = 100, 100 fpbb = geom.Box2I(geom.Point2I(0, 0), geom.Point2I(W-1, H-1)) afwimg = afwImage.MaskedImageF(fpbb) imgbb = afwimg.getBBox() img = afwimg.getImage().getArray() var = afwimg.getVariance().getArray() var[:, :] = 1. blob_fwhm = 15. blob_psf = doubleGaussianPsf(201, 201, blob_fwhm, 3.*blob_fwhm, 0.03) fakepsf_fwhm = 5. S = int(np.ceil(fakepsf_fwhm * 2.)) * 2 + 1 print('S', S) fakepsf = gaussianPsf(S, S, fakepsf_fwhm) # Create and save blob images, and add to image to deblend. blobimgs = [] XY = [(50., 50.), (90., 50.)] flux = 1e6 for x, y in XY: bim = blob_psf.computeImage(geom.Point2D(x, y)) bbb = bim.getBBox() bbb.clip(imgbb) bim = bim.Factory(bim, bbb) bim2 = bim.getArray() blobimg = np.zeros_like(img) blobimg[bbb.getMinY():bbb.getMaxY()+1, bbb.getMinX():bbb.getMaxX()+1] += flux * bim2 blobimgs.append(blobimg) img[bbb.getMinY():bbb.getMaxY()+1, bbb.getMinX():bbb.getMaxX()+1] += flux * bim2 # Run the detection code to get a ~ realistic footprint thresh = afwDet.createThreshold(10., 'value', True) fpSet = afwDet.FootprintSet(afwimg, thresh, 'DETECTED', 1) fps = fpSet.getFootprints() print('found', len(fps), 'footprints') # set EDGE bit on edge pixels. margin = 5 lo = imgbb.getMin() lo.shift(geom.Extent2I(margin, margin)) hi = imgbb.getMax() hi.shift(geom.Extent2I(-margin, -margin)) goodbbox = geom.Box2I(lo, hi) print('Good bbox for setting EDGE pixels:', goodbbox) print('image bbox:', imgbb) edgebit = afwimg.getMask().getPlaneBitMask("EDGE") print('edgebit:', edgebit) measAlg.SourceDetectionTask.setEdgeBits(afwimg, goodbbox, edgebit) if False: plt.clf() plt.imshow(afwimg.getMask().getArray(), interpolation='nearest', origin='lower') plt.colorbar() plt.title('Mask') plt.savefig('mask.png') M = afwimg.getMask().getArray() for bit in range(32): mbit = (1 << bit) if not np.any(M & mbit): continue plt.clf() plt.imshow(M & mbit, interpolation='nearest', origin='lower') plt.colorbar() plt.title('Mask bit %i (0x%x)' % (bit, mbit)) plt.savefig('mask-%02i.png' % bit) for fp in fps: print('peaks:', len(fp.getPeaks())) for pk in fp.getPeaks(): print(' ', pk.getIx(), pk.getIy()) assert(len(fps) == 1) fp = fps[0] assert(len(fp.getPeaks()) == 2) ima = dict(interpolation='nearest', origin='lower', # cmap='gray', cmap='jet', vmin=0, vmax=400) for j, (tt, kwa) in enumerate([ ('No edge treatment', dict()), ('Ramp by PSF', dict(rampFluxAtEdge=True)), ('No clip at edge', dict(patchEdges=True)), ]): # print 'Deblending...' # Change verbose to False to quiet down the meas_deblender.baseline logger deb = deblend(fp, afwimg, fakepsf, fakepsf_fwhm, verbose=True, **kwa) # print 'Result:', deb # print len(deb.peaks), 'deblended peaks' parent_img = afwImage.ImageF(fpbb) fp.spans.copyImage(afwimg.getImage(), parent_img) X = [x for x, y in XY] Y = [y for x, y in XY] PX = [pk.getIx() for pk in fp.getPeaks()] PY = [pk.getIy() for pk in fp.getPeaks()] # Grab 1-d slices to make assertion about. symms = [] monos = [] symm1ds = [] mono1ds = [] yslice = H//2 parent1d = img[yslice, :] for i, dpk in enumerate(deb.deblendedParents[0].peaks): symm = dpk.origTemplate symms.append(symm) bbox = symm.getBBox() x0, y0 = bbox.getMinX(), bbox.getMinY() im = symm.getArray() h, w = im.shape oned = np.zeros(W) oned[x0: x0+w] = im[yslice-y0, :] symm1ds.append(oned) mono = afwImage.ImageF(fpbb) dpk.templateFootprint.spans.copyImage(dpk.templateImage, mono) monos.append(mono) im = mono.getArray() bbox = mono.getBBox() x0, y0 = bbox.getMinX(), bbox.getMinY() h, w = im.shape oned = np.zeros(W) oned[x0: x0+w] = im[yslice-y0, :] mono1ds.append(oned) for i, (symm, mono) in enumerate(zip(symm1ds, mono1ds)): # for the first two cases, the basic symmetric # template for the second source drops to zero at < # ~75 where the symmetric part is outside the # footprint. if i == 1 and j in [0, 1]: self.assertFloatsEqual(symm[:74], 0.0) if i == 1 and j == 2: # For the third case, the 'symm' template gets # "patched" with the parent's value self.assertFloatsEqual(symm[:74], parent1d[:74]) if i == 1 and j == 0: # No edge handling: mono template == 0 self.assertFloatsEqual(mono[:74], 0.0) if i == 1 and j == 1: # ramp by psf: zero up to ~65, ramps up self.assertFloatsEqual(mono[:64], 0.0) self.assertTrue(np.any(mono[65:74] > 0)) self.assertTrue(np.all(np.diff(mono)[60:80] >= 0.)) if i == 1 and j == 2: # no edge clipping: profile is monotonic and positive. self.assertTrue(np.all(np.diff(mono)[:85] >= 0.)) self.assertTrue(np.all(mono[:85] > 0.)) if not doPlot: continue plt.clf() p1 = plt.plot(parent1d, 'b-', lw=3, alpha=0.5) for i, (symm, mono) in enumerate(zip(symm1ds, mono1ds)): p2 = plt.plot(symm, 'r-', lw=2, alpha=0.7) p3 = plt.plot(mono, 'g-') plt.legend((p1[0], p2[0], p3[0]), ('Parent', 'Symm template', 'Mono template'), loc='upper left') plt.title('1-d slice: %s' % tt) fn = plotpat % (2*j+0) plt.savefig(fn) print('Wrote', fn) def myimshow(*args, **kwargs): x0, x1, y0, y1 = imExt(afwimg) plt.fill([x0, x0, x1, x1, x0], [y0, y1, y1, y0, y0], color=(1, 1, 0.8), zorder=20) plt.imshow(*args, zorder=25, **kwargs) plt.xticks([]) plt.yticks([]) plt.axis(imExt(afwimg)) plt.clf() pa = dict(color='m', marker='.', linestyle='None', zorder=30) R, C = 3, 6 plt.subplot(R, C, (2*C) + 1) myimshow(img, **ima) ax = plt.axis() plt.plot(X, Y, **pa) plt.axis(ax) plt.title('Image') plt.subplot(R, C, (2*C) + 2) myimshow(parent_img.getArray(), **ima) ax = plt.axis() plt.plot(PX, PY, **pa) plt.axis(ax) plt.title('Footprint') sumimg = None for i, dpk in enumerate(deb.deblendedParents[0].peaks): plt.subplot(R, C, i*C + 1) myimshow(blobimgs[i], **ima) ax = plt.axis() plt.plot(PX[i], PY[i], **pa) plt.axis(ax) plt.title('true') plt.subplot(R, C, i*C + 2) t = dpk.origTemplate myimshow(t.getArray(), extent=imExt(t), **ima) ax = plt.axis() plt.plot(PX[i], PY[i], **pa) plt.axis(ax) plt.title('symm') # monotonic template mimg = afwImage.ImageF(fpbb) afwDet.copyWithinFootprintImage(dpk.templateFootprint, dpk.templateImage, mimg) plt.subplot(R, C, i*C + 3) myimshow(mimg.getArray(), extent=imExt(mimg), **ima) ax = plt.axis() plt.plot(PX[i], PY[i], **pa) plt.axis(ax) plt.title('monotonic') plt.subplot(R, C, i*C + 4) port = dpk.fluxPortion.getImage() myimshow(port.getArray(), extent=imExt(port), **ima) plt.title('portion') ax = plt.axis() plt.plot(PX[i], PY[i], **pa) plt.axis(ax) if dpk.strayFlux is not None: simg = afwImage.ImageF(fpbb) dpk.strayFlux.insert(simg) plt.subplot(R, C, i*C + 5) myimshow(simg.getArray(), **ima) plt.title('stray') ax = plt.axis() plt.plot(PX, PY, **pa) plt.axis(ax) himg2 = afwImage.ImageF(fpbb) portion = dpk.getFluxPortion() portion.insert(himg2) if sumimg is None: sumimg = himg2.getArray().copy() else: sumimg += himg2.getArray() plt.subplot(R, C, i*C + 6) myimshow(himg2.getArray(), **ima) plt.title('portion+stray') ax = plt.axis() plt.plot(PX, PY, **pa) plt.axis(ax) plt.subplot(R, C, (2*C) + C) myimshow(sumimg, **ima) ax = plt.axis() plt.plot(X, Y, **pa) plt.axis(ax) plt.title('Sum of deblends') plt.suptitle(tt) fn = plotpat % (2*j + 1) plt.savefig(fn) print('Wrote', fn)
def test1(self): ''' A simple example: three overlapping blobs (detected as 1 footprint with three peaks). We artificially omit one of the peaks, meaning that its flux is "stray". Assert that the stray flux assigned to the other two peaks accounts for all the flux in the parent. ''' H,W = 100,100 fpbb = afwGeom.Box2I(afwGeom.Point2I(0,0), afwGeom.Point2I(W-1,H-1)) afwimg = afwImage.MaskedImageF(fpbb) imgbb = afwimg.getBBox(afwImage.PARENT) img = afwimg.getImage().getArray() var = afwimg.getVariance().getArray() var[:,:] = 1. blob_fwhm = 10. blob_psf = doubleGaussianPsf(99, 99, blob_fwhm, 3.*blob_fwhm, 0.03) fakepsf_fwhm = 3. fakepsf = gaussianPsf(11, 11, fakepsf_fwhm) blobimgs = [] x = 75. XY = [(x,35.), (x,65.), (50.,50.)] flux = 1e6 for x,y in XY: bim = blob_psf.computeImage(afwGeom.Point2D(x, y)) bbb = bim.getBBox(afwImage.PARENT) bbb.clip(imgbb) bim = bim.Factory(bim, bbb, afwImage.PARENT) bim2 = bim.getArray() blobimg = np.zeros_like(img) blobimg[bbb.getMinY():bbb.getMaxY()+1, bbb.getMinX():bbb.getMaxX()+1] += flux * bim2 blobimgs.append(blobimg) img[bbb.getMinY():bbb.getMaxY()+1, bbb.getMinX():bbb.getMaxX()+1] += flux * bim2 # Run the detection code to get a ~ realistic footprint thresh = afwDet.createThreshold(5., 'value', True) fpSet = afwDet.FootprintSet(afwimg, thresh, 'DETECTED', 1) fps = fpSet.getFootprints() print 'found', len(fps), 'footprints' pks2 = [] for fp in fps: print 'peaks:', len(fp.getPeaks()) for pk in fp.getPeaks(): print ' ', pk.getIx(), pk.getIy() pks2.append((pk.getIx(), pk.getIy())) # The first peak in this list is the one we want to omit. fp0 = fps[0] fakefp = afwDet.Footprint(fp0.getSpans(), fp0.getBBox()) for pk in fp0.getPeaks()[1:]: fakefp.getPeaks().append(pk) ima = dict(interpolation='nearest', origin='lower', cmap='gray', vmin=0, vmax=1e3) if doPlot: plt.figure(figsize=(12,6)) plt.clf() plt.suptitle('strayFlux.py: test1 input') plt.subplot(2,2,1) plt.title('Image') plt.imshow(img, **ima) ax = plt.axis() plt.plot([x for x,y in XY], [y for x,y in XY], 'r.') plt.axis(ax) for i,(b,(x,y)) in enumerate(zip(blobimgs, XY)): plt.subplot(2,2, 2+i) plt.title('Blob %i' % i) plt.imshow(b, **ima) ax = plt.axis() plt.plot(x, y, 'r.') plt.axis(ax) plt.savefig(plotpat % 1) deb = deblend(fakefp, afwimg, fakepsf, fakepsf_fwhm, verbose=True) parent_img = afwImage.ImageF(fpbb) afwDet.copyWithinFootprintImage(fakefp, afwimg.getImage(), parent_img) if doPlot: def myimshow(*args, **kwargs): plt.imshow(*args, **kwargs) plt.xticks([]); plt.yticks([]) plt.axis(imExt(afwimg)) plt.clf() plt.suptitle('strayFlux.py: test1 results') #R,C = 3,5 R,C = 3,4 plt.subplot(R, C, (2*C) + 1) plt.title('Image') myimshow(img, **ima) ax = plt.axis() plt.plot([x for x,y in XY], [y for x,y in XY], 'r.') plt.axis(ax) plt.subplot(R, C, (2*C) + 2) plt.title('Parent footprint') myimshow(parent_img.getArray(), **ima) ax = plt.axis() plt.plot([pk.getIx() for pk in fakefp.getPeaks()], [pk.getIy() for pk in fakefp.getPeaks()], 'r.') plt.axis(ax) sumimg = None for i,dpk in enumerate(deb.peaks): plt.subplot(R, C, i*C + 1) plt.title('ch%i symm' % i) symm = dpk.templateImage myimshow(symm.getArray(), extent=imExt(symm), **ima) plt.subplot(R, C, i*C + 2) plt.title('ch%i portion' % i) port = dpk.fluxPortion.getImage() myimshow(port.getArray(), extent=imExt(port), **ima) himg = afwImage.ImageF(fpbb) heavy = dpk.getFluxPortion(strayFlux=False) heavy.insert(himg) # plt.subplot(R, C, i*C + 3) # plt.title('ch%i heavy' % i) # myimshow(himg.getArray(), **ima) # ax = plt.axis() # plt.plot([x for x,y in XY], [y for x,y in XY], 'r.') # plt.axis(ax) simg = afwImage.ImageF(fpbb) dpk.strayFlux.insert(simg) plt.subplot(R, C, i*C + 3) plt.title('ch%i stray' % i) myimshow(simg.getArray(), **ima) ax = plt.axis() plt.plot([x for x,y in XY], [y for x,y in XY], 'r.') plt.axis(ax) himg2 = afwImage.ImageF(fpbb) heavy = dpk.getFluxPortion(strayFlux=True) heavy.insert(himg2) if sumimg is None: sumimg = himg2.getArray().copy() else: sumimg += himg2.getArray() plt.subplot(R, C, i*C + 4) myimshow(himg2.getArray(), **ima) plt.title('ch%i total' % i) ax = plt.axis() plt.plot([x for x,y in XY], [y for x,y in XY], 'r.') plt.axis(ax) plt.subplot(R, C, (2*C) + C) myimshow(sumimg, **ima) ax = plt.axis() plt.plot([x for x,y in XY], [y for x,y in XY], 'r.') plt.axis(ax) plt.title('Sum of deblends') plt.savefig(plotpat % 2) # Compute the sum-of-children image sumimg = None for i,dpk in enumerate(deb.peaks): himg2 = afwImage.ImageF(fpbb) dpk.getFluxPortion().insert(himg2) if sumimg is None: sumimg = himg2.getArray().copy() else: sumimg += himg2.getArray() # Sum of children ~= Original image inside footprint (parent_img) absdiff = np.max(np.abs(sumimg - parent_img.getArray())) print 'Max abs diff:', absdiff imgmax = parent_img.getArray().max() print 'Img max:', imgmax self.assertTrue(absdiff < imgmax * 1e-6)
t1 = wcs.pixelToSky(eIm.getWidth(), 0) t2 = wcs.pixelToSky(0, eIm.getHeight()) t3 = wcs.pixelToSky(eIm.getWidth(), eIm.getHeight()) minRA = min(t0.getPosition()[0], t1.getPosition()[0], t2.getPosition()[0], t3.getPosition()[0]) maxRA = max(t0.getPosition()[0], t1.getPosition()[0], t2.getPosition()[0], t3.getPosition()[0]) minDec = min(t0.getPosition()[1], t1.getPosition()[1], t2.getPosition()[1], t3.getPosition()[1]) maxDec = max(t0.getPosition()[1], t1.getPosition()[1], t2.getPosition()[1], t3.getPosition()[1]) if eFile.startswith('eimage'): # There shouldn't be many sources in negative print 'Making negative footprint detections.' detSetN = afwDetection.makeFootprintSet(useEImForBG, afwDetection.createThreshold(5, 'stdev', False)) footprintsN = detSetN.getFootprints() if len(footprintsN) > 0: raise RuntimeError, '*** Unexpected negative source.' else: print ' No negative footprints found, as expected.' regOut = open(outDir + 'pDet.reg', 'w') print 'Making positive footprint detections.' detSetP = afwDetection.makeFootprintSet(useEImForBG, afwDetection.createThreshold(5, "stdev")) footprintsP = detSetP.getFootprints() nf = len(footprintsP) detxs = []; detys = []; nCts = []; estSizePix = [] n = 0; boxSize = 2; circleSize = 20 print 'Considering %i positive footprints.' % len(footprintsP) fAllFPP = open(outDir + 'fAllFPP.reg', 'w') for fp in footprintsP:
def findMatchingFootprints(eIm, eHDUList, wcs, ra, dec, rmags, baRatio, objId, option, a_disk, b_disk, a_bulge, b_bulge, diskFluxNorm, bulgeFluxNorm, pa_d, raEdge, decEdge, dxMin, dyMin, matchArcsec, plotno, ePath): # Get the set of footprints from the FITS image, setting the # threshold by either count value or STDEV. footprintsP is the list # of positive footprints for that particular FITS file, con- # sisting of a set of pixels. getFootprints() returns the # footprints of detected objects. # Don't set the detection limit too bright, or sources will # sometimes be missed. detSetP = afwDetection.makeFootprintSet( eIm, afwDetection.createThreshold(2., 'value')) #eIm, afwDetection.createThreshold(28., 'stdev')) footprintsP = detSetP.getFootprints() nf = len(footprintsP) b1 = 1.999*1 - 0.327 b4 = 1.999*4 - 0.327 detxs = []; detys = []; nCts = []; estSizePix = [] detMinx = []; detMaxx = []; detMiny = []; detMaxy = [] detMaxRad2 = [] n = 0; boxSize = 2 minCtsBrightThresh = 1000 #print 'Considering %i positive footprints.' % len(footprintsP) for fp in footprintsP: if n % 10000 == 0: print '%i of %i positive footprints analyzed.' % (n, nf) # Return "a list of BBoxs whose union contains exactly the pixels in # foot, neither more or less." # This looks at each boundary box in the list of boundary boxes (bboxes) # and gets the minimum and maximum x and y values of the list of coordinates, # and calculates the x and y lengths of the boundary box (dx, dy). # Lots of times they're only 1 pixel in length. fAllFPP is a file # containing the center x,y coordinates of each footprint, as well as dx and dy. # minx, maxx, miny, and maxy will be the very minimum and maximum values of # all the footprints for all the boundary boxes in the list. Create a # rectangular footprint: bboxes = afwDetection.footprintToBBoxList(fp) minx = 1e100; maxx = -1e100; miny = 1e100; maxy = -1e100 for bbox in bboxes: x0, y0 = bbox.getMinX(), bbox.getMinY() x1, y1 = bbox.getMaxX(), bbox.getMaxY() dx = x1 - x0; dy = y1 - y0 minx = min([minx, x0, x1]); maxx = max([maxx, x0, x1]) miny = min([miny, y0, y1]); maxy = max([maxy, y0, y1]) oldminx = minx; oldmaxx = maxx oldminy = miny; oldmaxy = maxy # The footprint regions are sometimes skewed, so center them # as best we can by finding the maximum pixel and then weighting # around that. # eIm.get(x,y) returns the number of counts (t0) in that pixel. # DS9 uses 1-based coords, so add 1 highPixx = -1; highPixy = -1; highPixVal = -1.e100 for x in range(minx, maxx+1): for y in range(miny, maxy+1): t0 = eIm.get(x, y) if t0 > highPixVal: highPixx = x; highPixy = y; highPixVal = t0 # Now we know the max pixel. Work in an aperture around it. Use the # footprints to set the maximum extent of the aperture. # Check to make sure the distance of the pixel in question is equal # to or less that the maximum radius of the aperture. # ctsWtSumx(or y) is the weighted center coordinate of the object # in the x (or y) direction. # detxs is a list of ctsWtSumx for each footprint. # Only keep the eImages that are above a minimum brightness threshold # and above a minimum x or y width in terms of pixels. tCts = 0; ctsWtSumx = 0; ctsWtSumy = 0; nPix = 0 t0 = (maxx - highPixx)**2 t1 = (minx - highPixx)**2 maxx2 = max(t0, t1) t0 = (maxy - highPixy)**2 t1 = (miny - highPixy)**2 maxy2 = max(t0, t1) maxRad2 = maxx2 + maxy2 dx = abs(maxx - minx) dy = abs(maxy - miny) if dx >= dxMin or dy >= dyMin: for x in range(minx, maxx+1): for y in range(miny, maxy+1): r2 = (x-highPixx)**2 + (y-highPixy)**2 if r2 > maxRad2: continue t0 = eIm.get(x, y) tCts += t0 ctsWtSumx += x * t0; ctsWtSumy += y * t0 nPix += 1 if tCts > minCtsBrightThresh: ctsWtSumx /= float(tCts); ctsWtSumy /= float(tCts) # Now iterate it again over a smaller region to improve # your chances of hitting the center. minx = int(ctsWtSumx - dx/5.); maxx = int(ctsWtSumx + dx/5.) miny = int(ctsWtSumy - dy/5.); maxy = int(ctsWtSumy + dy/5.) if maxx > 3999: maxx = 3999 if minx < 1: minx = 0 if maxy > 4071: maxy = 4071 if miny < 1: miny = 0 highPixx = -1; highPixy = -1; highPixVal = -1.e100 for x in range(minx, maxx+1): for y in range(miny, maxy+1): t0 = eIm.get(x, y) if t0 > highPixVal: highPixx = x; highPixy = y; highPixVal = t0 tCts = 0; ctsWtSumx = 0; ctsWtSumy = 0; nPix = 0 t0 = (maxx - highPixx)**2 t1 = (minx - highPixx)**2 maxx2 = max(t0, t1) t0 = (maxy - highPixy)**2 t1 = (miny - highPixy)**2 maxy2 = max(t0, t1) maxRad2 = maxx2 + maxy2 for x in range(minx, maxx+1): for y in range(miny, maxy+1): r2 = (x-highPixx)**2 + (y-highPixy)**2 if r2 > maxRad2: continue t0 = eIm.get(x, y) tCts += t0 ctsWtSumx += x * t0; ctsWtSumy += y * t0 nPix += 1 ctsWtSumx /= float(tCts); ctsWtSumy /= float(tCts) minx = oldminx maxx = oldmaxx miny = oldminy maxy = oldmaxy t0 = (maxx - ctsWtSumx)**2 t1 = (minx - ctsWtSumx)**2 maxx2 = max(t0, t1) t0 = (maxy - ctsWtSumy)**2 t1 = (miny - ctsWtSumy)**2 maxy2 = max(t0, t1) maxRad2 = maxx2 + maxy2 detxs.append(ctsWtSumx); detys.append(ctsWtSumy) nCts.append(tCts); estSizePix.append(nPix) detMinx.append(int(ctsWtSumx-dx/2.)); detMaxx.append(int(ctsWtSumx+dx/2.)) detMiny.append(int(ctsWtSumy-dy/2.)); detMaxy.append(int(ctsWtSumy+dy/2.)) detMaxRad2.append(maxRad2) n += 1 # At this point you have data for bright enough, wide enough footprints. detxs = numpy.array(detxs); detys = numpy.array(detys) nCts = numpy.array(nCts); estSizePix = numpy.array(estSizePix) detMinx = numpy.array(detMinx); detMaxx = numpy.array(detMaxx) detMiny = numpy.array(detMiny); detMaxy = numpy.array(detMaxy) #brightRAs = numpy.zeros(len(detxs)) #brightDecs = numpy.zeros(len(detxs)) brightRAs = wcs.pixelToSky(detxs, detys).getPosition()[0] brightDecs = wcs.pixelToSky(detxs, detys).getPosition()[1] # for each value of your original coordinates of interest, # create a list (t0) of the square of the distance between each bright # coordinate and the galaxy coordinates. t1 is the index of the minimum distance # squared, so t0[t1] is the minimum distance squared. The match to your # coordinates is brightRAs[t1] and BrightDecs[t1]. #matchDistArcsec = numpy.zeros(len(ra))id psi = [] psiFit = [] psiCatRaDec = [] psiCatXY = [] psiImageRaDec = [] psiImageXY = [] pa_d = [] aFit = [] bFit = [] baRatioFit = [] idx = [] tidx = [] distArcsec = [] gal_code = ['Lowba_bulge_Only', 'Lowba_disk_Only', 'Lowba_bulge_and_Disk'] #gal_code = ['Bulge_Only', 'Disk_Only', 'Bulge_and_Disk'] for i in range(len(ra)): # Assuming distance is small, keep it linear t0 = (brightRAs - ra[i])**2 + (brightDecs - dec[i])**2 t1 = numpy.argmin(t0) diffArcsec = numpy.sqrt(t0[t1]) * 3600. if diffArcsec <= matchArcsec: idx.append(i) tidx.append(t1) distArcsec.append(diffArcsec) ra = ra[idx] dec = dec[idx] raEdge = raEdge[idx] decEdge = decEdge[idx] raCat = raEdge - ra decCat = decEdge - dec psiCatRaDec.append(positionAngle(raCat, decCat)) xyCtrCat = wcs.skyToPixel(ra, dec) xCtrCat, yCtrCat = xyCtrCat xyPixPos = wcs.skyToPixel(raEdge, decEdge) xPixPos, yPixPos = xyPixPos xCat = xPixPos - xCtrCat yCat = yPixPos - yCtrCat psiCatXY.append(positionAngle(xCat, yCat)) distArcsec = numpy.array(distArcsec) brightRAs = brightRAs[tidx] brightDecs = brightDecs[tidx] ra = ra[idx] dec = dec[idx] raEdge = raEdge[idx] decEdge = decEdge[idx] detMinx = detMinx[tidx] detMaxx = detMaxx[tidx] detMiny = detMiny[tidx] detMaxy = detMaxy[tidx] xwidth = abs(detMaxx - detMinx) ywidth = abs(detMaxy - detMiny) detxs = detxs[tidx] detys = detys[tidx] pa_d = pa_d[idx] Rad2Max = max((xwidth/2.)**2, (ywidth/2.)**2) nbins = int(max(xwidth/2., ywidth/2.)) rmags = rmags[idx] baRatio = baRatio[idx] option = option[idx] objId = objId[idx] a_disk = a_disk[idx] b_disk = b_disk[idx] a_bulge = a_bulge[idx] #for m in range(nbins[i]): b_bulge = b_bulge[idx] diskFluxNorm = diskFluxNorm[idx] bulgeFluxNorm = bulgeFluxNorm[idx] # Now you've got the object and its radius. To calculate the flux as a # function of radius, I(r), break the radius squared into multiple segments # and bin the number of counts. Then divide the total number of counts # in each bin by the area, if you want. print 'len(detxs), len(objId), len(rmags), len(a_disk), len(detMinx), len(detMaxy): ' print len(detxs), len(objId), len(rmags), len(a_disk), len(detMinx), len(detMaxy) for i in range(len(detxs)): if i != -1: print 'Galaxy ID: ', objId[i] print 'rmags: ', rmags[i] print 'a_disk: ', a_disk[i] print 'b_disk: ', b_disk[i] print 'a_bulge: ', a_bulge[i] print 'b_bulge: ', b_bulge[i] print 'diskFluxNorm: ', diskFluxNorm[i] print 'bulgeFluxNorm: ', bulgeFluxNorm[i] print 'detMinx: ', detMinx[i] print 'detMaxx: ', detMaxx[i] print 'detMiny: ', detMiny[i] print 'detMaxy: ', detMaxy[i] print 'pa_d: ', pa_d[i] print 'detxs: ', detxs[i] print 'detys: ', detys[i] print 'ra (cat): ', ra[i] print 'dec (cat): ', dec[i] print 'raEdge, decEdge: ', raEdge[i], decEdge[i] print 'psiCatXY: xPixPos, xCtrCat, yPixPos, yCtrCat' print xPixPos[i], xCtrCat[i], yPixPos[i], yCtrCat[i] tCts = numpy.zeros(nbins[i]) I_R = numpy.zeros(nbins[i]) nPix = numpy.zeros(nbins[i]) mew = numpy.zeros(nbins[i]) rErr = numpy.zeros(nbins[i]) Err_Up = numpy.zeros(nbins[i]) Err_Dn = numpy.zeros(nbins[i]) a2Bin = numpy.zeros(nbins[i]) aBin = numpy.zeros(nbins[i]) AveABin = numpy.zeros(nbins[i]) xBdry = [] yBdry = [] ellipticity = b_disk[i]/a_disk[i] # Create an image plot for each footprint. C = numpy.zeros(((detMaxy[i]-detMiny[i]+1), (detMaxx[i]-detMinx[i]+1)), numpy.int) for y in range (detMiny[i], detMaxy[i], 1): for x in range(detMinx[i], detMaxx[i], 1): C[y-detMiny[i], x-detMinx[i]] = eIm.get(x,y) # Find the boundaries of an eimage using the pixel count threshold # as the discriminator. Break the eimage into anglar bins (say, # 50,so the distant outliers are less likely to be included)and # select the minimum value in each bin. The original purpose was # to get data points for fitting ellipses to galactic disks. n = 50 deltaAng = 2.*math.pi/float(n) xBdry = [] yBdry = [] theta = [] radDist2 = [] xVal = [] yVal = [] angleDeg = [] for j in range(n): radDist2.append([]) xVal.append([]) yVal.append([]) angleDeg.append([]) # This section is devoted to finding psi, the angle of # the ellipse's rotation CCW with respect to the positive # x-axis countMin = 12 count = 0 for x in range(detMinx[i] + 1, detMaxx[i]-1, 1): xp = float(x - detMinx[i]) for y in range(detMiny[i], detMaxy[i], 1): yp = float(y - detMiny[i]) if C[yp, xp] < countMin: if C[yp, xp-1] < countMin or C[yp, xp+1] < countMin: y0 = float(y) - detys[i] x0 = float(x) - detxs[i] Angle = xyPosAngle(x0, y0) m = int(Angle/deltaAng) radDist2[m].append(x0**2 + y0**2) xVal[m].append(xp) yVal[m].append(yp) angleDeg[m].append(Angle*180./math.pi) for j in range(n): if len(radDist2[j]) >= 1.: t1 = numpy.argmin(radDist2[j]) xBdry.append(xVal[j][t1]) yBdry.append(yVal[j][t1]) theta.append(angleDeg[j][t1]) z, a, b, psiAve = fitellipse([xBdry, yBdry]) aFit.append(a) bFit.append(b) if a >= b and a != None and b !=None: baRatioFit.append(b/a) elif b > a and a != None and b !=None: baRatioFit.append(a/b) else: baRatioFit.append(None) if psiAve != None: psiFit.append(float(psiAve)*180./math.pi) else: psiFit.append(None) print 'psiFit: ', psiFit[i] if a and b and psiAve and z != None: xEllipse, yEllipse = ellipse(aFit[-1], bFit[-1], psiAve, detxs[i]-detMinx[i], detys[i]-detMiny[i]) daMax2 = a*a/float(nbins[i]) else: print 'a, b, psiAve, or z = None for i = ', i, a, b, psiAve, z psiImageXY.append(None) psiImageRaDec.append(None) print 'psiImageXY, psiImageRaDec: ', psiImageXY[i], psiImageRaDec[i] continue xMajor = aFit[-1]*math.cos(psiAve) + detxs[i]-detMinx[i] yMajor = aFit[-1]*math.sin(psiAve) + detys[i]-detMiny[i] print 'xMajor, yMajor = ', xMajor, yMajor x0 = xMajor - detxs[i] y0 = yMajor - detys[i] psiImageXY.append(positionAngle(x0, y0)) ra3 = wcs.pixelToSky(xMajor, yMajor).getPosition()[0] dec3 = wcs.pixelToSky(xMajor, yMajor).getPosition()[1] print 'ra3, brightRAs[i], dec3, brightDecs[i] = ', ra3, brightRAs[i], brightDecs[i], dec3 xyMajor3 = wcs.skyToPixel(ra3, dec3) xMajor3, yMajor3 = xyMajor3 print "xMajor3, yMajor3 = ", xMajor3, yMajor3 xyMajor2 = wcs.skyToPixel(raEdge[i], decEdge[i]) xMajor2, yMajor2 = xyMajor2 print 'brightRAs[i], brightDecs[i]:' print brightRAs[i], brightDecs[i] ra0 = ra3 - brightRAs[i] dec0 = dec3 - brightDecs[i] psiImageRaDec.append(positionAngle(ra0, dec0)) t0 = 0. for m in range(nbins[i]): t0 += daMax2 a2Bin[m] = t0 aBin[m] = math.sqrt(t0) AveABin[0] = 10.**(math.log10(aBin[0])/2.) for m in range(nbins[i]-1): Ave = (math.log10(aBin[m+1]) + math.log10(aBin[m]))/2. AveABin[m+1] = 10.**Ave xbin = [] ybin = [] for x in range(detMinx[i], detMaxx[i]+1): for y in range(detMiny[i], detMaxy[i]+1): xprime = x - detxs[i] yprime = y - detys[i] aXY2 = (xprime*math.cos(psiAve) + yprime*math.sin(psiAve ))**2 + (xprime*math.sin(psiAve) - yprime*math.cos(psiAve)/(b/a))**2 if aXY2 > a*a: continue nval = min(int(aXY2/daMax2), nbins[i]-1) tCts[nval] += eIm.get(x,y) nPix[nval] += 1 if nval <= 4: xbin.append(x - detMinx[i]) ybin.append(y - detMiny[i]) sumCts = 0 sumPix = 0 for m in range(nbins[i]): sumCts += tCts[m] sumPix += nPix[m] #mew, the mean, is in counts/pixel mew[m] = tCts[m]/nPix[m] for m in range(nbins[i]): # I(R) in units of counts per square arcsec: if mew[m] == 0: I_R[m] = numpy.nan else: I_R[m] = mew[m]/.04 rErr[m] = math.sqrt(tCts[m])/nPix[m]/.04 I_Reff = max(I_R)/math.e for m in range(nbins[i]): if I_R[m] < I_Reff: R_eff = 10**(math.log10(AveABin[m]) - (math.log10(I_R[m]) - math.log10(I_Reff))/(math.log10(I_R[m]) - math.log10(I_R[m-1]))*(math.log10(AveABin[m]) - math.log10(AveABin[m-1]))) break print 'xwidth, ywidth (in pixels) = ', abs(detMaxx[i] - detMinx[i]), abs(detMaxy[i] - detMiny[i]) print 'Total Counts = %i, Total Pixels = %i' % (sumCts, sumPix) print 'log_Radius(") log_Intensity n = 1 and 4 n = 1 n = 4 Pixels Counts Mean Sigma' #Prepare Sersic n=1 and n = 4 model profiles for comparison In1 = numpy.zeros(nbins[i]) In4 = numpy.zeros(nbins[i]) InBoth = numpy.zeros(nbins[i]) for m in range(nbins[i]): In1[m] = I_Reff*math.exp(-b1*((AveABin[m]/R_eff) - 1)) In4[m] = I_Reff*math.exp(-b4*(((AveABin[m]/R_eff)**0.25) - 1)) InBoth[m] = (diskFluxNorm[i]*In1[m] + bulgeFluxNorm[i]*In4[m])/(diskFluxNorm[i] + bulgeFluxNorm[i]) for m in range(nbins[i]): # Convert pixels to arcsec (0.2 arcsec/pixel, roughly) AveABin[m] = math.log10(AveABin[m]*.2) if I_R[m] != None: Err_Up[m] = math.log10(I_R[m] + rErr[m]) - math.log10(I_R[m]) if I_R[m] > rErr[m]: Err_Dn[m] = math.log10(I_R[m]) - math.log10(I_R[m] - rErr[m]) else: Err_Dn[m] = 5 I_R[m] = math.log10(I_R[m]) if In1[m] != 0.: In1[m] = math.log10(In1[m]) else: In1[m] = numpy.nan if In4[m] != 0.: In4[m] = math.log10(In4[m]) else: In4[m] = numpy.nan if InBoth[m] != 0.: InBoth[m] = math.log10(InBoth[m]) else: InBoth[m] = numpy.nan if m > 8 and I_R[m] is 'nan' and I_R[m-1] is 'nan' and I_R[m-2] is 'nan' and I_R[m-3] is 'nan': nbins[i] = nbins[:(nbins[i]-m+1)] for m in range(nbins[i]): print '%11.2f %11.2f %11.2f %11.2f %11.2f %11.2f %11.2f %11.2f %11.2f' % (AveABin[m], I_R[m], InBoth[m], In1[m], In4[m], nPix[m], tCts[m], mew[m], rErr[m]) fig = plt.figure() fig.suptitle('Galaxy %s, (ra,dec)=(%5.2f, %5.2f), %d pixels \n%d counts; Gal_ID %s R_eff = %5.2f arcsecs, PA = %5.2f deg.\n%s' %(gal_code[option[i]], brightRAs[i], brightDecs[i], sumPix, sumCts, objId[i], R_eff*.2, pa_d[i], ePath), fontsize=9) ax = fig.add_subplot(121) im = plt.imshow(C, aspect ='equal', origin='lower', cmap = plt.cm.gray, interpolation = 'nearest') cir = Circle((detxs[i]-detMinx[i],detys[i]-detMiny[i]), radius = .25, ec='r', fc = 'r') cir2 = Circle((xMajor, yMajor), radius = .25, ec='g', fc = 'g') print 'semi-major axis direction at (', xMajor, ', ', yMajor, ')' ax.add_patch(cir) ax.add_patch(cir2) line5, = ax.plot(xBdry, yBdry, 'r.') line6, = ax.plot(xEllipse, yEllipse, 'm.') line7, = ax.plot(xbin, ybin, 'y.') xcolname = 'log [Radius (arcsec)]' ycolname = 'Intensity (Log_10[Counts/Area])' ax2 = fig.add_subplot(122) plt.xlabel(xcolname, fontsize=10) plt.ylabel(ycolname, fontsize=10) line1 = ax2.errorbar(AveABin, I_R, yerr=[Err_Dn, Err_Up], fmt = 'bo', ms = 2) line2, = ax2.plot(AveABin, In1, 'm--') line3, = ax2.plot(AveABin, In4, 'g-.') line4, = ax2.plot(AveABin, InBoth, 'r-') props = font_manager.FontProperties(size=12) leg = ax2.legend([line1[0], line2, line3, line4], ['eImage', 'n=1', 'n=4', 'n=1+4'], loc='upper right', prop=props) plt.text(0.1, 0.1, 'r = %5.2f\nb/a = %5.3f' % (rmags[i], baRatio[i]), transform = ax2.transAxes) plt.savefig('%s/Sers70cM12%sh.png' % (gal_code[option[i]], objId[i]), format = 'png') plotno += 1 plt.clf() print 'Length of the following variables:' print len(detxs), len(detys), len(xPixPos), len(yPixPos), len(psiImageXY), len(psiImageRaDec), len(psiCatXY), len(psiCatRaDec), len(psiFit), len(a_disk), len(b_disk), len(aFit), len(bFit) print 'objId ra2-raEdge dec2-decEdge detxs detys xPixPos yPixPos a_disk b_disk a b b/a catalog b/a fit' for i in range(len(detxs)): if aFit[i] and bFit[i] and a_disk[i] and b_disk[i] and psiFit[i] != None: print '%8i %7.2e %7.2e %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f' % (objId[i], ra2[i]-raEdge[i], dec2[i]-decEdge[i], detxs[i], detys[i], xPixPos[i], yPixPos[i], a_disk[i], b_disk[i], aFit[i], bFit[i], b_disk[i]/a_disk[i], bFit[i]/aFit[i]) print 'objId pa_d psiCatRD psiImRD psiCatXY psiImXY psiFit b/a cat b/a fit' for i in range(len(detxs)): if aFit[i] and bFit[i] and a_disk[i] and b_disk[i] and psiFit[i] != None: print '%8i %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f' % (objId[i], pa_d[i], psiCatRaDec[i], psiImageRaDec[i], psiCatXY[i], psiImageXY[i], psiFit[i], b_disk[i]/a_disk[i], bFit[i]/aFit[i]) return plotno
t2.getPosition()[0], t3.getPosition()[0]) minDec = min(t0.getPosition()[1], t1.getPosition()[1], t2.getPosition()[1], t3.getPosition()[1]) maxDec = max(t0.getPosition()[1], t1.getPosition()[1], t2.getPosition()[1], t3.getPosition()[1]) if eFile.startswith('eimage'): # There shouldn't be many sources in negative print 'Making negative footprint detections.' detSetN = afwDetection.makeFootprintSet( useEImForBG, afwDetection.createThreshold(5, 'stdev', False)) footprintsN = detSetN.getFootprints() if len(footprintsN) > 0: raise RuntimeError, '*** Unexpected negative source.' else: print ' No negative footprints found, as expected.' regOut = open(outDir + 'pDet.reg', 'w') print 'Making positive footprint detections.' detSetP = afwDetection.makeFootprintSet( useEImForBG, afwDetection.createThreshold(5, "stdev")) footprintsP = detSetP.getFootprints() nf = len(footprintsP) detxs = [] detys = [] nCts = []
def test1(self): ''' In this test, we create a test image containing two blobs, one of which is truncated by the edge of the image. We run the detection code to get realistic peaks and footprints. We then test out the different edge treatments and assert that they do what they claim. We also make plots, tests/edge*.png ''' # Create fake image... H,W = 100,100 fpbb = afwGeom.Box2I(afwGeom.Point2I(0,0), afwGeom.Point2I(W-1,H-1)) afwimg = afwImage.MaskedImageF(fpbb) imgbb = afwimg.getBBox() img = afwimg.getImage().getArray() var = afwimg.getVariance().getArray() var[:,:] = 1. blob_fwhm = 15. blob_psf = doubleGaussianPsf(201, 201, blob_fwhm, 3.*blob_fwhm, 0.03) fakepsf_fwhm = 5. S = int(np.ceil(fakepsf_fwhm * 2.)) * 2 + 1 print 'S', S fakepsf = gaussianPsf(S, S, fakepsf_fwhm) # Create and save blob images, and add to image to deblend. blobimgs = [] XY = [(50.,50.), (90.,50.)] flux = 1e6 for x,y in XY: bim = blob_psf.computeImage(afwGeom.Point2D(x, y)) bbb = bim.getBBox() bbb.clip(imgbb) bim = bim.Factory(bim, bbb) bim2 = bim.getArray() blobimg = np.zeros_like(img) blobimg[bbb.getMinY():bbb.getMaxY()+1, bbb.getMinX():bbb.getMaxX()+1] += flux * bim2 blobimgs.append(blobimg) img[bbb.getMinY():bbb.getMaxY()+1, bbb.getMinX():bbb.getMaxX()+1] += flux * bim2 # Run the detection code to get a ~ realistic footprint thresh = afwDet.createThreshold(10., 'value', True) fpSet = afwDet.FootprintSet(afwimg, thresh, 'DETECTED', 1) fps = fpSet.getFootprints() print 'found', len(fps), 'footprints' # set EDGE bit on edge pixels. margin = 5 lo = imgbb.getMin() lo.shift(afwGeom.Extent2I(margin, margin)) hi = imgbb.getMax() hi.shift(afwGeom.Extent2I(-margin, -margin)) goodbbox = afwGeom.Box2I(lo, hi) print 'Good bbox for setting EDGE pixels:', goodbbox print 'image bbox:', imgbb edgebit = afwimg.getMask().getPlaneBitMask("EDGE") print 'edgebit:', edgebit measAlg.SourceDetectionTask.setEdgeBits(afwimg, goodbbox, edgebit) if False: plt.clf() plt.imshow(afwimg.getMask().getArray(), interpolation='nearest', origin='lower') plt.colorbar() plt.title('Mask') plt.savefig('mask.png') M = afwimg.getMask().getArray() for bit in range(32): mbit = (1 << bit) if not np.any(M & mbit): continue plt.clf() plt.imshow(M & mbit, interpolation='nearest', origin='lower') plt.colorbar() plt.title('Mask bit %i (0x%x)' % (bit, mbit)) plt.savefig('mask-%02i.png' % bit) for fp in fps: print 'peaks:', len(fp.getPeaks()) for pk in fp.getPeaks(): print ' ', pk.getIx(), pk.getIy() assert(len(fps) == 1) fp = fps[0] assert(len(fp.getPeaks()) == 2) ima = dict(interpolation='nearest', origin='lower', #cmap='gray', cmap='jet', vmin=0, vmax=400) for j,(tt,kwa) in enumerate([ ('No edge treatment', dict()), ('Ramp by PSF', dict(rampFluxAtEdge=True)), ('No clip at edge', dict(patchEdges=True)), ]): #print 'Deblending...' deb = deblend(fp, afwimg, fakepsf, fakepsf_fwhm, verbose=True, **kwa) #print 'Result:', deb #print len(deb.peaks), 'deblended peaks' parent_img = afwImage.ImageF(fpbb) afwDet.copyWithinFootprintImage(fp, afwimg.getImage(), parent_img) X = [x for x,y in XY] Y = [y for x,y in XY] PX = [pk.getIx() for pk in fp.getPeaks()] PY = [pk.getIy() for pk in fp.getPeaks()] # Grab 1-d slices to make assertion about. symms = [] monos = [] symm1ds = [] mono1ds = [] yslice = H/2 parent1d = img[yslice, :] for i,dpk in enumerate(deb.peaks): symm = dpk.origTemplate symms.append(symm) bbox = symm.getBBox() x0,y0 = bbox.getMinX(), bbox.getMinY() im = symm.getArray() h,w = im.shape oned = np.zeros(W) oned[x0: x0+w] = im[yslice-y0, :] symm1ds.append(oned) mono = afwImage.ImageF(fpbb) afwDet.copyWithinFootprintImage(dpk.templateFootprint, dpk.templateImage, mono) monos.append(mono) im = mono.getArray() bbox = mono.getBBox() x0,y0 = bbox.getMinX(), bbox.getMinY() h,w = im.shape oned = np.zeros(W) oned[x0: x0+w] = im[yslice-y0, :] mono1ds.append(oned) for i,(symm,mono) in enumerate(zip(symm1ds, mono1ds)): # for the first two cases, the basic symmetric # template for the second source drops to zero at < # ~75 where the symmetric part is outside the # footprint. if i == 1 and j in [0,1]: self.assertTrue(np.all(symm[:74] == 0)) if i == 1 and j == 2: # For the third case, the 'symm' template gets # "patched" with the parent's value self.assertTrue(np.all((symm == parent1d)[:74])) if i == 1 and j == 0: # No edge handling: mono template == 0 self.assertTrue(np.all(mono[:74] == 0)) if i == 1 and j == 1: # ramp by psf: zero up to ~65, ramps up self.assertTrue(np.all(mono[:64] == 0)) self.assertTrue(np.any(mono[65:74] > 0)) self.assertTrue(np.all(np.diff(mono)[60:80] >= 0.)) if i == 1 and j == 2: # no edge clipping: profile is monotonic and positive. self.assertTrue(np.all(np.diff(mono)[:85] >= 0.)) self.assertTrue(np.all(mono[:85] > 0.)) if not doPlot: continue plt.clf() p1 = plt.plot(parent1d, 'b-', lw=3, alpha=0.5) for i,(symm,mono) in enumerate(zip(symm1ds, mono1ds)): p2 = plt.plot(symm, 'r-', lw=2, alpha=0.7) p3 = plt.plot(mono, 'g-') plt.legend((p1[0],p2[0],p3[0]), ('Parent','Symm template', 'Mono template'), loc='upper left') plt.title('1-d slice: %s' % tt) fn = plotpat % (2*j+0) plt.savefig(fn) print 'Wrote', fn def myimshow(*args, **kwargs): x0,x1,y0,y1 = imExt(afwimg) plt.fill([x0,x0,x1,x1,x0],[y0,y1,y1,y0,y0], color=(1,1,0.8), zorder=20) plt.imshow(*args, zorder=25, **kwargs) plt.xticks([]); plt.yticks([]) plt.axis(imExt(afwimg)) plt.clf() pa = dict(color='m', marker='.', linestyle='None', zorder=30) R,C = 3,6 plt.subplot(R, C, (2*C) + 1) myimshow(img, **ima) ax = plt.axis() plt.plot(X, Y, **pa) plt.axis(ax) plt.title('Image') plt.subplot(R, C, (2*C) + 2) myimshow(parent_img.getArray(), **ima) ax = plt.axis() plt.plot(PX, PY, **pa) plt.axis(ax) plt.title('Footprint') sumimg = None for i,dpk in enumerate(deb.peaks): plt.subplot(R, C, i*C + 1) myimshow(blobimgs[i], **ima) ax = plt.axis() plt.plot(PX[i], PY[i], **pa) plt.axis(ax) plt.title('true') plt.subplot(R, C, i*C + 2) t = dpk.origTemplate myimshow(t.getArray(), extent=imExt(t), **ima) ax = plt.axis() plt.plot(PX[i], PY[i], **pa) plt.axis(ax) plt.title('symm') # monotonic template mimg = afwImage.ImageF(fpbb) afwDet.copyWithinFootprintImage(dpk.templateFootprint, dpk.templateImage, mimg) plt.subplot(R, C, i*C + 3) myimshow(mimg.getArray(), extent=imExt(mimg), **ima) ax = plt.axis() plt.plot(PX[i], PY[i], **pa) plt.axis(ax) plt.title('monotonic') plt.subplot(R, C, i*C + 4) port = dpk.fluxPortion.getImage() myimshow(port.getArray(), extent=imExt(port), **ima) plt.title('portion') ax = plt.axis() plt.plot(PX[i], PY[i], **pa) plt.axis(ax) if dpk.strayFlux is not None: simg = afwImage.ImageF(fpbb) dpk.strayFlux.insert(simg) plt.subplot(R, C, i*C + 5) myimshow(simg.getArray(), **ima) plt.title('stray') ax = plt.axis() plt.plot(PX, PY, **pa) plt.axis(ax) himg2 = afwImage.ImageF(fpbb) portion = dpk.getFluxPortion() portion.insert(himg2) if sumimg is None: sumimg = himg2.getArray().copy() else: sumimg += himg2.getArray() plt.subplot(R, C, i*C + 6) myimshow(himg2.getArray(), **ima) plt.title('portion+stray') ax = plt.axis() plt.plot(PX, PY, **pa) plt.axis(ax) plt.subplot(R, C, (2*C) + C) myimshow(sumimg, **ima) ax = plt.axis() plt.plot(X, Y, **pa) plt.axis(ax) plt.title('Sum of deblends') plt.suptitle(tt) fn = plotpat % (2*j + 1) plt.savefig(fn) print 'Wrote', fn
def testThresholdFactory(self): """ Test the creation of a Threshold object This is a white-box test. -tests missing parameters -tests mal-formed parameters """ try: afwDetect.createThreshold(3.4) except Exception: self.fail("Failed to build Threshold with proper parameters") try: afwDetect.createThreshold(3.4, "foo bar") except Exception: pass else: self.fail("Threhold parameters not properly validated") try: afwDetect.createThreshold(3.4, "variance") except Exception: self.fail("Failed to build Threshold with proper parameters") try: afwDetect.createThreshold(3.4, "stdev") except Exception: self.fail("Failed to build Threshold with proper parameters") try: afwDetect.createThreshold(3.4, "value") except Exception: self.fail("Failed to build Threshold with proper parameters") try: afwDetect.createThreshold(3.4, "value", False) except Exception: self.fail("Failed to build Threshold with VALUE, False parameters") try: afwDetect.createThreshold(0x4, "bitmask") except Exception: self.fail("Failed to build Threshold with BITMASK parameters") try: afwDetect.createThreshold(5, "pixel_stdev") except Exception: self.fail("Failed to build Threshold with PIXEL_STDEV parameters")
def testThresholdFactory(self): """ Test the creation of a Threshold object This is a white-box test. -tests missing parameters -tests mal-formed parameters """ try: afwDetect.createThreshold(3.4) except: self.fail("Failed to build Threshold with proper parameters") try: afwDetect.createThreshold(3.4, "foo bar") except: pass else: self.fail("Threhold parameters not properly validated") try: afwDetect.createThreshold(3.4, "variance") except: self.fail("Failed to build Threshold with proper parameters") try: afwDetect.createThreshold(3.4, "stdev") except: self.fail("Failed to build Threshold with proper parameters") try: afwDetect.createThreshold(3.4, "value") except: self.fail("Failed to build Threshold with proper parameters") try: afwDetect.createThreshold(3.4, "value", False) except: self.fail("Failed to build Threshold with VALUE, False parameters") try: afwDetect.createThreshold(0x4, "bitmask") except: self.fail("Failed to build Threshold with BITMASK parameters") try: afwDetect.createThreshold(5, "pixel_stdev") except: self.fail("Failed to build Threshold with PIXEL_STDEV parameters")