def setUp(self): self.exposure = lsst.afw.image.ExposureF(201, 201) # for convenience, we'll put the source at the origin self.exposure.setXY0(lsst.afw.geom.Point2I(-100, -100)) self.exposure.getMaskedImage().getVariance()[:] = 1.0 self.psf = lsst.meas.algorithms.DoubleGaussianPsf( 71, 71, 8.0, 15.0, 1.0) self.exposure.setPsf(self.psf) self.flux = 50.0 psfImage = self.psf.computeImage() box = psfImage.getBBox(lsst.afw.image.PARENT) image = self.exposure.getMaskedImage().getImage() subImage = image.Factory(image, box, lsst.afw.image.PARENT, False) subImage.scaledPlus(self.flux, psfImage.convertF()) self.footprint = lsst.afw.detection.Footprint(box) self.footprint.getPeaks().append(lsst.afw.detection.Peak(0, 0)) self.config = lsst.meas.algorithms.SourceMeasurementConfig() self.config.algorithms.names = [ "flux.psf", "flux.gaussian", "flux.sinc", "correctfluxes" ] self.config.algorithms.names.add("shape.sdss") self.config.centroider.name = None self.config.slots.centroid = None self.config.slots.shape = None self.config.doReplaceWithNoise = False
def setUp(self): self.exposure = lsst.afw.image.ExposureF(201, 201) # for convenience, we'll put the source at the origin self.exposure.setXY0(lsst.afw.geom.Point2I(-100, -100)) self.psf = lsst.meas.algorithms.DoubleGaussianPsf( 71, 71, 8.0, 15.0, 1.0) self.exposure.setPsf(self.psf) self.flux = 50.0 self.radii = [3.0, 6.0, 9.0, 12.0, 15.0, 98.0, 200.0] psfImage = self.psf.computeImage() box = psfImage.getBBox(lsst.afw.image.PARENT) image = self.exposure.getMaskedImage().getImage() subImage = image.Factory(image, box, lsst.afw.image.PARENT, False) subImage.scaledPlus(self.flux, psfImage.convertF()) self.footprint = lsst.afw.detection.Footprint(box) self.footprint.addPeak(0, 0, float("NaN")) self.config = lsst.meas.algorithms.SourceMeasurementConfig() self.config.algorithms.names = [ "flux.sinc", "flux.naive", "flux.aperture" ] self.config.algorithms["flux.sinc"].radius = 3.0 self.config.algorithms["flux.naive"].radius = 15.0 self.config.algorithms["flux.aperture"].maxSincRadius = 10.0 self.config.algorithms["flux.aperture"].radii = self.radii self.config.centroider.name = None self.config.slots.centroid = None self.config.slots.shape = None self.config.slots.apFlux = None self.config.slots.modelFlux = None self.config.slots.psfFlux = None self.config.slots.instFlux = None self.config.slots.calibFlux = None self.config.doReplaceWithNoise = False
def drawSource(self, record, exposure, buffer=0): """Draw the given truth catalog record on the given exposure, makings use of its Psf, Wcs, PhotoCalib, and possibly filter to transform it appropriately. The mask and variance planes of the Exposure are ignored. The 'buffer' parameter is used to expand the source's bounding box when testing whether it is considered fully part of the image. Returns 0 if the object does not appear on the given image at all, 1 if it appears partially, and 2 if it appears fully (including the given buffer). """ wcs = exposure.getWcs() center = wcs.skyToPixel(record.getCoord()) try: psfImage = exposure.getPsf().computeImage(center).convertF() except Exception: return 0 psfBBox = psfImage.getBBox() overlap = exposure.getBBox() overlap.clip(psfBBox) if overlap.isEmpty(): return 0 flux = exposure.getPhotoCalib().magnitudeToInstFlux( record.getD(self.magKey)) normalization = flux / psfImage.getArray().sum() if psfBBox != overlap: psfImage = psfImage.Factory(psfImage, overlap) result = 1 else: result = 2 if buffer != 0: bufferedBBox = lsst.geom.Box2I(psfBBox) bufferedBBox.grow(buffer) bufferedOverlap = exposure.getBBox() bufferedOverlap.clip(bufferedBBox) if bufferedOverlap != bufferedBBox: result = 1 image = exposure.getMaskedImage().getImage() subImage = image.Factory(image, overlap) subImage.scaledPlus(normalization, psfImage) return result
def setUp(self): width, height = 250, 500 self.numAmps = 4 numPixelsPerAmp = 1000 # crosstalk[i][j] is the fraction of the j-th amp present on the i-th # amp. self.crosstalk = [[0.0, 1e-4, 2e-4, 3e-4], [3e-4, 0.0, 2e-4, 1e-4], [4e-4, 5e-4, 0.0, 6e-4], [7e-4, 8e-4, 9e-4, 0.0]] self.value = 12345 self.crosstalkStr = "XTLK" # A bit of noise is important, because otherwise the pixel # distributions are razor-thin and then rejection doesn't work. rng = np.random.RandomState(12345) self.noise = rng.normal(0.0, 0.1, (2 * height, 2 * width)) # Create amp images withoutCrosstalk = [ lsst.afw.image.ImageF(width, height) for _ in range(self.numAmps) ] for image in withoutCrosstalk: image.set(0) xx = rng.randint(0, width, numPixelsPerAmp) yy = rng.randint(0, height, numPixelsPerAmp) image.getArray()[yy, xx] = self.value # Add in crosstalk withCrosstalk = [ image.Factory(image, True) for image in withoutCrosstalk ] for ii, iImage in enumerate(withCrosstalk): for jj, jImage in enumerate(withoutCrosstalk): value = self.crosstalk[ii][jj] iImage.scaledPlus(value, jImage) # Put amp images together def construct(imageList): image = lsst.afw.image.ImageF(2 * width, 2 * height) image.getArray()[:height, :width] = imageList[0].getArray() image.getArray()[:height, width:] = imageList[1].getArray()[:, :: -1] # flip in x image.getArray()[height:, :width] = imageList[2].getArray( )[::-1, :] # flip in y image.getArray()[height:, width:] = imageList[3].getArray( )[::-1, ::-1] # flip in x and y image.getArray()[:] += self.noise return image # Construct detector detName = 'detector 1' detId = 1 detSerial = 'serial 1' orientation = cameraGeom.Orientation() pixelSize = lsst.geom.Extent2D(1, 1) bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(2 * width, 2 * height)) crosstalk = np.array(self.crosstalk, dtype=np.float32) camBuilder = cameraGeom.Camera.Builder("fakeCam") detBuilder = camBuilder.add(detName, detId) detBuilder.setSerial(detSerial) detBuilder.setBBox(bbox) detBuilder.setOrientation(orientation) detBuilder.setPixelSize(pixelSize) detBuilder.setCrosstalk(crosstalk) # Construct second detector in this fake camera detName = 'detector 2' detId = 2 detSerial = 'serial 2' orientation = cameraGeom.Orientation() pixelSize = lsst.geom.Extent2D(1, 1) bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(2 * width, 2 * height)) crosstalk = np.array(self.crosstalk, dtype=np.float32) detBuilder2 = camBuilder.add(detName, detId) detBuilder2.setSerial(detSerial) detBuilder2.setBBox(bbox) detBuilder2.setOrientation(orientation) detBuilder2.setPixelSize(pixelSize) detBuilder2.setCrosstalk(crosstalk) # Create amp info for ii, (xx, yy, corner) in enumerate([ (0, 0, lsst.afw.cameraGeom.ReadoutCorner.LL), (width, 0, lsst.afw.cameraGeom.ReadoutCorner.LR), (0, height, lsst.afw.cameraGeom.ReadoutCorner.UL), (width, height, lsst.afw.cameraGeom.ReadoutCorner.UR) ]): amp = cameraGeom.Amplifier.Builder() amp.setName("amp %d" % ii) amp.setBBox( lsst.geom.Box2I(lsst.geom.Point2I(xx, yy), lsst.geom.Extent2I(width, height))) amp.setRawDataBBox( lsst.geom.Box2I(lsst.geom.Point2I(xx, yy), lsst.geom.Extent2I(width, height))) amp.setReadoutCorner(corner) detBuilder.append(amp) detBuilder2.append(amp) cam = camBuilder.finish() ccd1 = cam.get('detector 1') ccd2 = cam.get('detector 2') self.exposure = lsst.afw.image.makeExposure( lsst.afw.image.makeMaskedImage(construct(withCrosstalk))) self.exposure.setDetector(ccd1) # Create a single ctSource that will be used for interChip CT # correction. self.ctSource = lsst.afw.image.makeExposure( lsst.afw.image.makeMaskedImage(construct(withCrosstalk))) self.ctSource.setDetector(ccd2) self.corrected = construct(withoutCrosstalk) if display: disp = lsst.afw.display.Display(frame=1) disp.mtv(self.exposure, title="exposure") disp = lsst.afw.display.Display(frame=0) disp.mtv(self.corrected, title="corrected exposure")
def convolve(self, exposure, seeing, target, footprint, maxRadius): """Convolve image around source to target seeing We also record the original seeing at the source position. Because we don't want to convolve the entire image just for this source, we cut out an area corresponding to the source's footprint, grown by the radius provided by `maxRadius`. We assume a Gaussian PSF to simplify and speed the convolution. The `seeing` and `target` may be either Gaussian sigma or FWHM, so long as they are the same. Parameters ---------- exposure : `lsst.afw.image.Exposure` Image to convolve. seeing : `float` Current seeing, pixels. target : `float` Desired target seeing, pixels. footprint : `lsst.afw.detection.Footprint` Footprint for source. maxRadius : `int` Maximum radius required by measurement algorithms. Returns ------- convExp : `lsst.afw.image.Exposure` Sub-image containing the source, convolved to the target seeing. Raises ------ DeconvolutionError If the target seeing requires deconvolution. RuntimeError If the bounding box is too small after clipping. """ if target < seeing: raise DeconvolutionError("Target seeing requires deconvolution") kernelSigma = math.sqrt(target*target - seeing*seeing) kernelRadius = int(self.config.kernelScale*kernelSigma + 0.5) kernelWidth = 2*kernelRadius + 1 gauss = lsst.afw.math.GaussianFunction1D(kernelSigma) kernel = lsst.afw.math.SeparableKernel(kernelWidth, kernelWidth, gauss, gauss) bbox = footprint.getBBox() bbox.grow(kernelRadius + maxRadius) # add an extra buffer? bbox.clip(exposure.getBBox()) if bbox.getWidth() < kernelWidth or bbox.getHeight() < kernelWidth: raise RuntimeError("Bounding box is too small following clipping") image = exposure.getMaskedImage() subImage = image.Factory(image, bbox) convolved = image.Factory(bbox) lsst.afw.math.convolve(convolved, subImage, kernel, lsst.afw.math.ConvolutionControl(True, True)) convExp = lsst.afw.image.makeExposure(convolved) convExp.setInfo(lsst.afw.image.ExposureInfo(exposure.getInfo())) return convExp
def setUp(self): width, height = 250, 500 self.numAmps = 4 numPixelsPerAmp = 1000 # crosstalk[i][j] is the fraction of the j-th amp present on the i-th amp. self.crosstalk = [[0.0, 1e-4, 2e-4, 3e-4], [3e-4, 0.0, 2e-4, 1e-4], [4e-4, 5e-4, 0.0, 6e-4], [7e-4, 8e-4, 9e-4, 0.0]] self.value = 12345 self.crosstalkStr = "XTLK" # A bit of noise is important, because otherwise the pixel distributions are razor-thin # and then rejection doesn't work rng = np.random.RandomState(12345) self.noise = rng.normal(0.0, 0.1, (2 * height, 2 * width)) # Create amp images withoutCrosstalk = [ lsst.afw.image.ImageF(width, height) for _ in range(self.numAmps) ] for image in withoutCrosstalk: image.set(0) xx = rng.randint(0, width, numPixelsPerAmp) yy = rng.randint(0, height, numPixelsPerAmp) image.getArray()[yy, xx] = self.value # Add in crosstalk withCrosstalk = [ image.Factory(image, True) for image in withoutCrosstalk ] for ii, iImage in enumerate(withCrosstalk): for jj, jImage in enumerate(withoutCrosstalk): value = self.crosstalk[ii][jj] iImage.scaledPlus(value, jImage) # Put amp images together def construct(imageList): image = lsst.afw.image.ImageF(2 * width, 2 * height) image.getArray()[:height, :width] = imageList[0].getArray() image.getArray()[:height, width:] = imageList[1].getArray()[:, :: -1] # flip in x image.getArray()[height:, :width] = imageList[2].getArray( )[::-1, :] # flip in y image.getArray()[height:, width:] = imageList[3].getArray( )[::-1, ::-1] # flip in x and y image.getArray()[:] += self.noise return image # Create amp info schema = lsst.afw.table.AmpInfoTable.makeMinimalSchema() amplifiers = lsst.afw.table.AmpInfoCatalog(schema) for ii, (xx, yy, corner) in enumerate([(0, 0, LL), (width, 0, LR), (0, height, UL), (width, height, UR)]): amp = amplifiers.addNew() amp.setName("amp %d" % ii) amp.setBBox( lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(xx, yy), lsst.afw.geom.Extent2I(width, height))) amp.setRawDataBBox( lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(xx, yy), lsst.afw.geom.Extent2I(width, height))) amp.setReadoutCorner(corner) # Put everything together ccd = lsst.afw.cameraGeom.Detector( "detector", 123, lsst.afw.cameraGeom.SCIENCE, "serial", lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(0, 0), lsst.afw.geom.Extent2I(2 * width, 2 * height)), amplifiers, lsst.afw.cameraGeom.Orientation(), lsst.afw.geom.Extent2D(1, 1), {}, np.array(self.crosstalk, dtype=np.float32)) self.exposure = lsst.afw.image.makeExposure( lsst.afw.image.makeMaskedImage(construct(withCrosstalk))) self.exposure.setDetector(ccd) self.corrected = construct(withoutCrosstalk) if display: disp = lsst.afw.display.Display(frame=1) disp.mtv(self.exposure, title="exposure") disp = lsst.afw.display.Display(frame=0) disp.mtv(self.corrected, title="corrected exposure")