def makeExposure(imgArray, psfArray, imgVariance): """Convert an image and corresponding PSF into an exposure. Set the (constant) variance plane equal to ``imgVariance``. Parameters ---------- imgArray : `numpy.ndarray` 2D array containing the image. psfArray : `numpy.ndarray` 2D array containing the PSF image. imgVariance : `float` or `numpy.ndarray` Set the variance plane to this value. If an array, must be broadcastable to ``imgArray.shape``. Returns ------- im1ex : `lsst.afw.image.Exposure` The new exposure. """ # All this code to convert the template image array/psf array into an exposure. bbox = geom.Box2I(geom.Point2I(0, 0), geom.Point2I(imgArray.shape[1] - 1, imgArray.shape[0] - 1)) im1ex = afwImage.ExposureD(bbox) im1ex.image.array[:, :] = imgArray im1ex.variance.array[:, :] = imgVariance psfBox = geom.Box2I(geom.Point2I(-12, -12), geom.Point2I(12, 12)) # a 25x25 pixel psf psf = afwImage.ImageD(psfBox) psfBox.shift(geom.Extent2I(-(-size[0]//2), -(-size[1]//2))) # -N//2 != -(N//2) for odd numbers im1_psf_sub = psfArray[psfBox.getMinY():psfBox.getMaxY() + 1, psfBox.getMinX():psfBox.getMaxX() + 1] psf.getArray()[:, :] = im1_psf_sub psfK = afwMath.FixedKernel(psf) psfNew = measAlg.KernelPsf(psfK) im1ex.setPsf(psfNew) wcs = makeWcs() im1ex.setWcs(wcs) return im1ex
def get_coadd_psf_bbox_old(x, y, dim): """ This old code only did the right thing for odd coadd dimensions compute the bounding box for the coadd, based on the coadd center as an integer position (Point2I) and the dimensions Parameters ---------- x: int The integer center in x. Should be gotten from bbox.getCenter() to provide an integer position y: int The integer center in x. Should be gotten from bbox.getCenter() to provide an integer position dim: int The dimensions of the psf, must be odd Returns ------- lsst.geom.Box2I """ xpix = int(x) ypix = int(y) xmin = (xpix - (dim - 1) / 2) ymin = (ypix - (dim - 1) / 2) return geom.Box2I( geom.Point2I(xmin, ymin), geom.Point2I(xmin + dim - 1, ymin + dim - 1), )
def exposureToBackground(bgExp): """Convert an exposure to background model Calibs need to be persisted as an Exposure, so we need to convert the persisted Exposure to a background model. Parameters ---------- bgExp : `lsst.afw.image.Exposure` Background model in Exposure format. Returns ------- bg : `lsst.afw.math.BackgroundList` Background model """ header = bgExp.getMetadata() xMin = header.getScalar("BOX.MINX") yMin = header.getScalar("BOX.MINY") xMax = header.getScalar("BOX.MAXX") yMax = header.getScalar("BOX.MAXY") algorithm = header.getScalar("ALGORITHM") bbox = geom.Box2I(geom.Point2I(xMin, yMin), geom.Point2I(xMax, yMax)) return afwMath.BackgroundList( (afwMath.BackgroundMI(bbox, bgExp.getMaskedImage()), afwMath.stringToInterpStyle(algorithm), afwMath.stringToUndersampleStyle("REDUCE_INTERP_ORDER"), afwMath.ApproximateControl.UNKNOWN, 0, 0, False))
def runConvolveAndSubtract2(self, bgOrder=0, xloc=408, yloc=580): imsize = int(5 * self.kSize) p0 = geom.Point2I(xloc - imsize // 2, yloc - imsize // 2) p1 = geom.Point2I(xloc + imsize // 2, yloc + imsize // 2) bbox = geom.Box2I(p0, p1) tmi = afwImage.MaskedImageF(self.templateImage, bbox, origin=afwImage.LOCAL) smi = afwImage.MaskedImageF(self.scienceImage, bbox, origin=afwImage.LOCAL) bgFunc = afwMath.PolynomialFunction2D( bgOrder) # coeffs are 0. by default diffIm = ipDiffim.convolveAndSubtract(tmi, smi, self.gaussKernel, bgFunc) bbox = self.gaussKernel.shrinkBBox( diffIm.getBBox(origin=afwImage.LOCAL)) diffIm2 = afwImage.MaskedImageF(diffIm, bbox, origin=afwImage.LOCAL) for j in range(diffIm2.getHeight()): for i in range(diffIm2.getWidth()): self.assertAlmostEqual(diffIm2.image[i, j, afwImage.LOCAL], 0., 4)
def getAmplifier(image, amp, ampReference=None, offset=2): """Extract an image of the amplifier from the CCD, along with an offset version The amplifier image will be flipped (if required) to match the orientation of a nominated reference amplifier. An additional image, with the nominated offset applied, is also produced. Parameters ---------- image : Image of CCD amp : Index of amplifier ampReference : Index of reference amplifier offset : Offset to apply Returns ------- amp_image : amplifier image, offset amplifier image """ height = image.getHeight() ampBox = geom.Box2I(geom.Point2I(amp * 512, 0), geom.Extent2I(512, height)) ampImage = image.Factory(image, ampBox, afwImage.LOCAL) if ampReference is not None and amp % 2 != ampReference % 2: ampImage = afwMath.flipImage(ampImage, True, False) offBox = geom.Box2I(geom.Point2I(offset if amp == ampReference else 0, 0), geom.Extent2I(510, height)) offsetImage = ampImage.Factory(ampImage, offBox, afwImage.LOCAL) return ampImage, offsetImage
def calcSpectrumBBox(self, exp, centroid, aperture, order='+1'): """Calculate the bbox for the spectrum, given the centroid. XXX Longer explanation here, inc. parameters TODO: Add support for order = "both" """ extent = self.config.spectrumLengthPixels halfWidth = aperture // 2 translate_y = self.config.offsetFromMainStar sourceX = centroid[0] sourceY = centroid[1] if (order == '-1'): translate_y = -extent - self.config.offsetFromMainStar xStart = sourceX - halfWidth xEnd = sourceX + halfWidth - 1 yStart = sourceY + translate_y yEnd = yStart + extent - 1 xEnd = min(xEnd, exp.getWidth() - 1) yEnd = min(yEnd, exp.getHeight() - 1) yStart = max(yStart, 0) xStart = max(xStart, 0) assert (xEnd > xStart) and (yEnd > yStart) self.log.debug('(xStart, xEnd) = (%s, %s)' % (xStart, xEnd)) self.log.debug('(yStart, yEnd) = (%s, %s)' % (yStart, yEnd)) bbox = geom.Box2I(geom.Point2I(xStart, yStart), geom.Point2I(xEnd, yEnd)) return bbox
def __init__(self, ccd, amp, overscans, task): geom = ccd.amp_geom self.ccd = ccd self.imaging = geom.imaging self.image = ccd[amp] # This is the masked image for the desired amp. if task.config.direction == 'p': self._bbox = self._parallel_box llc = lsstGeom.Point2I( geom.parallel_overscan.getMinX(), geom.parallel_overscan.getMinY() + overscans) urc = geom.parallel_overscan.getCorners()[2] self._bias_reg = lsstGeom.Box2I(llc, urc) self.lastpix = self.imaging.getMaxY() elif task.config.direction == 's': self._bbox = self._serial_box llc = lsstGeom.Point2I(geom.serial_overscan.getMinX() + overscans, geom.serial_overscan.getMinY()) urc = geom.serial_overscan.getCorners()[2] # # Omit the last 4 columns to avoid the bright column in the # last overscan column in the e2v vendor data. # urc[0] -= 4 self._bias_reg = lsstGeom.Box2I(llc, urc) self.lastpix = self.imaging.getMaxX() else: task.log.error("Unknown scan direction: " + str(direction)) sys.exit(1)
def _makeStarImage(self, xc=[15.3], yc=[18.6], flux=[2500], schema=None, randomSeed=None): """Generate an exposure and catalog with the given stellar source(s). """ from lsst.meas.base.tests import TestDataset bbox = geom.Box2I(geom.Point2I(0, 0), geom.Point2I(self.w - 1, self.h - 1)) dataset = TestDataset(bbox, psfSigma=self.psfSigma, threshold=1.) for i in range(len(xc)): dataset.addSource(instFlux=flux[i], centroid=geom.Point2D(xc[i], yc[i])) if schema is None: schema = TestDataset.makeMinimalSchema() exposure, catalog = dataset.realize(noise=self.noise, schema=schema, randomSeed=randomSeed) if self.gradientParams is not None: y, x = np.mgrid[:self.w, :self.h] gp = self.gradientParams gradient = gp[0] + gp[1] * x + gp[2] * y if len(self.gradientParams ) > 3: # it includes a set of 2nd-order polynomial params gradient += gp[3] * x * y + gp[4] * x * x + gp[5] * y * y imgArr = exposure.getMaskedImage().getArrays()[0] imgArr += gradient return exposure, catalog
def _makeBoxEvenSized(bb): """Force a bounding-box to have dimensions that are modulo 2.""" if bb.getWidth() % 2 == 1: # grow to the right bb.include(geom.Point2I(bb.getMaxX() + 1, bb.getMaxY())) # Expand by 1 pixel! bb.clip(bbox) if bb.getWidth( ) % 2 == 1: # clipped at right -- so grow to the left bb.include(geom.Point2I(bb.getMinX() - 1, bb.getMaxY())) bb.clip(bbox) if bb.getHeight() % 2 == 1: # grow upwards bb.include(geom.Point2I(bb.getMaxX(), bb.getMaxY() + 1)) # Expand by 1 pixel! bb.clip(bbox) if bb.getHeight() % 2 == 1: # clipped upwards -- so grow down bb.include(geom.Point2I(bb.getMaxX(), bb.getMinY() - 1)) bb.clip(bbox) if bb.getWidth() % 2 == 1 or bb.getHeight( ) % 2 == 1: # Box is probably too big raise RuntimeError( 'Cannot make bounding box even-sized. Probably too big.') return bb
def runConvolveAndSubtract1(self, bgVal=0, xloc=408, yloc=580): imsize = int(5 * self.kSize) p0 = geom.Point2I(xloc - imsize // 2, yloc - imsize // 2) p1 = geom.Point2I(xloc + imsize // 2, yloc + imsize // 2) bbox = geom.Box2I(p0, p1) tmi = afwImage.MaskedImageF(self.templateImage, bbox, origin=afwImage.LOCAL) smi = afwImage.MaskedImageF(self.scienceImage, bbox, origin=afwImage.LOCAL) diffIm = ipDiffim.convolveAndSubtract(tmi, smi, self.gaussKernel, bgVal) bbox = self.gaussKernel.shrinkBBox( diffIm.getBBox(origin=afwImage.LOCAL)) diffIm2 = afwImage.MaskedImageF(diffIm, bbox, origin=afwImage.LOCAL) # image is empty (or the additional background you subtracted off) for j in range(diffIm2.getHeight()): for i in range(diffIm2.getWidth()): self.assertAlmostEqual(diffIm2.image[i, j, afwImage.LOCAL], -1. * bgVal, 3)
def makeExposure(imgArray, psfArray, imgVariance): """! Convert an image numpy.array and corresponding PSF numpy.array into an exposure. Add the (constant) variance plane equal to `imgVariance`. @param imgArray 2-d numpy.array containing the image @param psfArray 2-d numpy.array containing the PSF image @param imgVariance variance of input image @return a new exposure containing the image, PSF and desired variance plane """ # All this code to convert the template image array/psf array into an exposure. bbox = geom.Box2I( geom.Point2I(0, 0), geom.Point2I(imgArray.shape[1] - 1, imgArray.shape[0] - 1)) im1ex = afwImage.ExposureD(bbox) im1ex.getMaskedImage().getImage().getArray()[:, :] = imgArray im1ex.getMaskedImage().getVariance().getArray()[:, :] = imgVariance psfBox = geom.Box2I(geom.Point2I(-12, -12), geom.Point2I(12, 12)) # a 25x25 pixel psf psf = afwImage.ImageD(psfBox) psfBox.shift(geom.Extent2I(size[0] // 2, size[1] // 2)) im1_psf_sub = psfArray[psfBox.getMinX():psfBox.getMaxX() + 1, psfBox.getMinY():psfBox.getMaxY() + 1] psf.getArray()[:, :] = im1_psf_sub psfK = afwMath.FixedKernel(psf) psfNew = measAlg.KernelPsf(psfK) im1ex.setPsf(psfNew) wcs = makeWcs() im1ex.setWcs(wcs) return im1ex
def setUp(self): # Set up local astrometry_net_data self.datapath = setupAstrometryNetDataDir('photocal') self.config = LoadAstrometryNetObjectsTask.ConfigClass() self.config.pixelMargin = 50 # Original default when these tests were written self.bbox = geom.Box2I(geom.Point2I(0, 0), geom.Extent2I(3001, 3001)) self.ctrPix = geom.Point2I(1500, 1500) metadata = PropertySet() metadata.set("RADESYS", "FK5") metadata.set("EQUINOX", 2000.0) metadata.set("CTYPE1", "RA---TAN") metadata.set("CTYPE2", "DEC--TAN") metadata.set("CUNIT1", "deg") metadata.set("CUNIT2", "deg") metadata.set("CRVAL1", 215.5) metadata.set("CRVAL2", 53.0) metadata.set("CRPIX1", self.ctrPix[0] + 1) metadata.set("CRPIX2", self.ctrPix[1] + 1) metadata.set("CD1_1", 5.1e-05) metadata.set("CD1_2", 0.0) metadata.set("CD2_2", -5.1e-05) metadata.set("CD2_1", 0.0) self.wcs = afwGeom.makeSkyWcs(metadata) self.desNumStarsInPixelBox = 270 self.desNumStarsInSkyCircle = 410
def testGood(self): ti = afwImage.MaskedImageF(geom.Extent2I(100, 100)) ti.getVariance().set(0.1) ti[50, 50, afwImage.LOCAL] = (1., 0x0, 1.) sKernel = self.makeSpatialKernel(2) si = afwImage.MaskedImageF(ti.getDimensions()) convolutionControl = afwMath.ConvolutionControl() convolutionControl.setDoNormalize(True) afwMath.convolve(si, ti, sKernel, convolutionControl) bbox = geom.Box2I(geom.Point2I(25, 25), geom.Point2I(75, 75)) si = afwImage.MaskedImageF(si, bbox, origin=afwImage.LOCAL) ti = afwImage.MaskedImageF(ti, bbox, origin=afwImage.LOCAL) kc = ipDiffim.KernelCandidateF(50., 50., ti, si, self.ps) sBg = afwMath.PolynomialFunction2D(1) bgCoeffs = [0., 0., 0.] sBg.setParameters(bgCoeffs) # must be initialized bskv = ipDiffim.BuildSingleKernelVisitorF(self.kList, self.ps) bskv.processCandidate(kc) self.assertEqual(kc.isInitialized(), True) askv = ipDiffim.AssessSpatialKernelVisitorF(sKernel, sBg, self.ps) askv.processCandidate(kc) self.assertEqual(askv.getNProcessed(), 1) self.assertEqual(askv.getNRejected(), 0) self.assertEqual(kc.getStatus(), afwMath.SpatialCellCandidate.GOOD)
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 test_coadd_psf_bbox_smoke(dim): psf_dim = 51 bbox = geom.Box2I(geom.Point2I(54, 54), geom.Extent2I(dim, dim)) cen = geom.Point2I(bbox.getCenter()) psf_bbox = get_coadd_psf_bbox(cen=cen, dim=psf_dim) assert isinstance(psf_bbox, geom.Box2I)
def run(self, exposure): """Mask defects and trim guider shadow for SuprimeCam Parameters ---------- exposure : `lsst.afw.image.Exposure` Exposure to construct detector-specific masks for. """ assert exposure, "No exposure provided" ccd = exposure.getDetector( ) # This is Suprime-Cam so we know the Detector is a Ccd ccdNum = ccd.getId().getSerial() if ccdNum not in (self.config.suprimeMaskLimitSetA + self.config.suprimeMaskLimitSetB): # No need to mask return md = exposure.getMetadata() if not md.exists("S_AG-X"): self.log.warn("No autoguider position in exposure metadata.") return xGuider = md.getScalar("S_AG-X") if ccdNum in self.config.suprimeMaskLimitSetA: maskLimit = int(60.0 * xGuider - 2300.0) # From SDFRED elif ccdNum in self.config.suprimeMaskLimitSetB: maskLimit = int(60.0 * xGuider - 2000.0) # From SDFRED mi = exposure.getMaskedImage() height = mi.getHeight() if height < maskLimit: # Nothing to mask! return # TODO DM-16806: Ensure GUIDER mask is respected downstream. if False: # XXX This mask plane isn't respected by background subtraction or source detection or measurement self.log.info("Masking autoguider shadow at y > %d" % maskLimit) mask = mi.getMask() bbox = geom.Box2I(geom.Point2I(0, maskLimit - 1), geom.Point2I(mask.getWidth() - 1, height - 1)) badMask = mask.Factory(mask, bbox, afwImage.LOCAL) mask.addMaskPlane("GUIDER") badBitmask = mask.getPlaneBitMask("GUIDER") badMask |= badBitmask else: # XXX Temporary solution until a mask plane is respected by downstream processes self.log.info( "Removing pixels affected by autoguider shadow at y > %d" % maskLimit) bbox = geom.Box2I(geom.Point2I(0, 0), geom.Extent2I(mi.getWidth(), maskLimit)) good = mi.Factory(mi, bbox, afwImage.LOCAL) exposure.setMaskedImage(good)
def measureScale(self, image, skyBackground): """Measure scale of background model in image We treat the sky frame much as we would a fringe frame (except the length scale of the variations is different): we measure samples on the input image and the sky frame, which we will use to determine the scaling factor in the 'solveScales` method. Parameters ---------- image : `lsst.afw.image.Exposure` or `lsst.afw.image.MaskedImage` Science image for which to measure scale. skyBackground : `lsst.afw.math.BackgroundList` Sky background model. Returns ------- imageSamples : `numpy.ndarray` Sample measurements on image. skySamples : `numpy.ndarray` Sample measurements on sky frame. """ if isinstance(image, afwImage.Exposure): image = image.getMaskedImage() # Ensure more samples than pixels xNumSamples = min(self.config.xNumSamples, image.getWidth()) yNumSamples = min(self.config.yNumSamples, image.getHeight()) xLimits = numpy.linspace(0, image.getWidth(), xNumSamples + 1, dtype=int) yLimits = numpy.linspace(0, image.getHeight(), yNumSamples + 1, dtype=int) sky = skyBackground.getImage() maskVal = image.getMask().getPlaneBitMask(self.config.stats.mask) ctrl = afwMath.StatisticsControl(self.config.stats.clip, self.config.stats.nIter, maskVal) statistic = afwMath.stringToStatisticsProperty( self.config.stats.statistic) imageSamples = [] skySamples = [] for xIndex, yIndex in itertools.product(range(xNumSamples), range(yNumSamples)): # -1 on the stop because Box2I is inclusive of the end point and we don't want to overlap boxes xStart, xStop = xLimits[xIndex], xLimits[xIndex + 1] - 1 yStart, yStop = yLimits[yIndex], yLimits[yIndex + 1] - 1 box = geom.Box2I(geom.Point2I(xStart, yStart), geom.Point2I(xStop, yStop)) subImage = image.Factory(image, box) subSky = sky.Factory(sky, box) imageSamples.append( afwMath.makeStatistics(subImage, statistic, ctrl).getValue()) skySamples.append( afwMath.makeStatistics(subSky, statistic, ctrl).getValue()) return imageSamples, skySamples
def testNoMask(self): mask = afwImage.Mask(geom.Extent2I(20, 20)) mask.set(0) fsb = ipDiffim.FindSetBitsU() bbox = geom.Box2I(geom.Point2I(0, 10), geom.Point2I(9, 12)) fsb.apply(afwImage.Mask(mask, bbox, afwImage.LOCAL)) self.assertEqual(fsb.getBits(), 0)
def get_bbox(keyword, dxmin=0, dymin=0, dxmax=0, dymax=0): """ Parse an NOAO section keyword value (e.g., DATASEC = '[1:509,1:200]') from the FITS header and return the corresponding bounding box for sub-image retrieval. """ xmin, xmax, ymin, ymax = [val - 1 for val in eval(keyword.replace(':', ','))] bbox = lsst_geom.Box2I(lsst_geom.Point2I(xmin + dxmin, ymin + dymin), lsst_geom.Point2I(xmax + dxmax, ymax + dymax)) return bbox
def setUp(self): schema = afwTable.SourceTable.makeMinimalSchema() afwTable.Point2DKey.addFields(schema, "Centroid", "input centroid", "pixel") schema.addField("PsfFlux_instFlux", type=float) schema.addField("PsfFlux_instFluxErr", type=float) schema.addField("PsfFlux_flag", type="Flag") self.table = afwTable.SourceTable.make(schema) self.table.definePsfFlux("PsfFlux") self.table.defineCentroid("Centroid") self.ss = afwTable.SourceCatalog(self.table) self.config = ipDiffim.ImagePsfMatchTask.ConfigClass() self.config.kernel.name = "DF" self.subconfig = self.config.kernel.active self.ps = pexConfig.makePropertySet(self.subconfig) self.ps[ 'fitForBackground'] = True # we are testing known background recovery here self.ps['checkConditionNumber'] = False # just in case self.ps["useRegularization"] = False if defDataDir: defSciencePath = os.path.join(defDataDir, "DC3a-Sim", "sci", "v26-e0", "v26-e0-c011-a10.sci.fits") defTemplatePath = os.path.join(defDataDir, "DC3a-Sim", "sci", "v5-e0", "v5-e0-c011-a10.sci.fits") scienceExposure = afwImage.ExposureF(defSciencePath) templateExposure = afwImage.ExposureF(defTemplatePath) # set XY0 = 0 scienceExposure.setXY0(geom.Point2I(0, 0)) templateExposure.setXY0(geom.Point2I(0, 0)) # do the warping first so we don't have any masked pixels in the postage stamps warper = afwMath.Warper.fromConfig(self.subconfig.warpingConfig) templateExposure = warper.warpExposure( scienceExposure.getWcs(), templateExposure, destBBox=scienceExposure.getBBox()) # Change xy0 # Nice star at position 276, 717 # And should be at index 40, 40 # No masked pixels in this one self.x02 = 276 self.y02 = 717 size = 40 bbox2 = geom.Box2I(geom.Point2I(self.x02 - size, self.y02 - size), geom.Point2I(self.x02 + size, self.y02 + size)) self.scienceImage2 = afwImage.ExposureF(scienceExposure, bbox2, origin=afwImage.LOCAL) self.templateExposure2 = afwImage.ExposureF(templateExposure, bbox2, origin=afwImage.LOCAL)
def addCcd(self, exposure): """Add CCD to model We measure the background on the CCD (clipped mean), and record the results in the model. For simplicity, measurements are made in a box on the CCD corresponding to the warped coordinates of the superpixel rather than accounting for little rotations, etc. We also record the number of pixels used in the measurement so we can have a measure of confidence in each bin's value. Parameters ---------- exposure : `lsst.afw.image.Exposure` CCD exposure to measure """ detector = exposure.getDetector() transform = detector.getTransformMap().getTransform( detector.makeCameraSys(afwCameraGeom.PIXELS), detector.makeCameraSys(afwCameraGeom.FOCAL_PLANE)) image = exposure.getMaskedImage() maskVal = image.getMask().getPlaneBitMask(self.config.mask) # Warp the binned image to the focal plane toSample = transform.then( self.transform) # CCD pixels --> focal plane --> sample warped = afwImage.ImageF(self._values.getBBox()) warpedCounts = afwImage.ImageF(self._numbers.getBBox()) width, height = warped.getDimensions() stats = afwMath.StatisticsControl() stats.setAndMask(maskVal) stats.setNanSafe(True) # Iterating over individual pixels in python is usually bad because it's slow, but there aren't many. pixels = itertools.product(range(width), range(height)) for xx, yy in pixels: llc = toSample.applyInverse(geom.Point2D(xx - 0.5, yy - 0.5)) urc = toSample.applyInverse(geom.Point2D(xx + 0.5, yy + 0.5)) bbox = geom.Box2I(geom.Point2I(llc), geom.Point2I(urc)) bbox.clip(image.getBBox()) if bbox.isEmpty(): continue subImage = image.Factory(image, bbox) result = afwMath.makeStatistics(subImage, afwMath.MEANCLIP | afwMath.NPOINT, stats) mean = result.getValue(afwMath.MEANCLIP) num = result.getValue(afwMath.NPOINT) if not numpy.isfinite(mean) or not numpy.isfinite(num): continue warped[xx, yy, afwImage.LOCAL] = mean * num warpedCounts[xx, yy, afwImage.LOCAL] = num self._values += warped self._numbers += warpedCounts
def _getBboxes(self, centroid): x, y = centroid bboxes = [] for offset in self._spectrumBoxOffsets: bbox = geom.Box2I( geom.Point2I(x - self.spectrumHalfWidth, y + offset), geom.Point2I(x + self.spectrumHalfWidth, y + offset + self.spectrumBoxLength)) bboxes.append(bbox) return bboxes
def crossCorrelate(maskedimage1, maskedimage2, maxLag, sigma, binsize): """ Calculate the correlation coefficients. """ sctrl = afwMath.StatisticsControl() sctrl.setNumSigmaClip(sigma) # Diff the images. diff = maskedimage1.clone() diff -= maskedimage2.getImage() # Subtract background. nx = diff.getWidth()//binsize ny = diff.getHeight()//binsize bctrl = afwMath.BackgroundControl(nx, ny, sctrl, afwMath.MEANCLIP) bkgd = afwMath.makeBackground(diff, bctrl) bgImg = bkgd.getImageF(afwMath.Interpolate.CUBIC_SPLINE, afwMath.REDUCE_INTERP_ORDER) diff -= bgImg # Measure the correlations x0, y0 = diff.getXY0() width, height = diff.getDimensions() bbox_extent = lsstGeom.Extent2I(width - maxLag, height - maxLag) bbox = lsstGeom.Box2I(lsstGeom.Point2I(x0, y0), bbox_extent) dim0 = diff[bbox].clone() dim0 -= afwMath.makeStatistics(dim0, afwMath.MEANCLIP, sctrl).getValue() xcorr = np.zeros((maxLag + 1, maxLag + 1), dtype=np.float64) xcorr_err = np.zeros((maxLag + 1, maxLag + 1), dtype=np.float64) for xlag in range(maxLag + 1): for ylag in range(maxLag + 1): bbox_lag = lsstGeom.Box2I(lsstGeom.Point2I(x0 + xlag, y0 + ylag), bbox_extent) dim_xy = diff[bbox_lag].clone() dim_xy -= afwMath.makeStatistics(dim_xy, afwMath.MEANCLIP, sctrl).getValue() dim_xy *= dim0 xcorr[xlag, ylag] = afwMath.makeStatistics( dim_xy, afwMath.MEANCLIP, sctrl).getValue() dim_xy_array = dim_xy.getImage().getArray().flatten()/xcorr[0][0] N = len(dim_xy_array.flatten()) if xlag != 0 and ylag != 0: f = (1+xcorr[xlag, ylag]/xcorr[0][0]) / \ (1-xcorr[xlag, ylag]/xcorr[0][0]) xcorr_err[xlag, ylag] = ( np.std(dim_xy_array)/np.sqrt(N))*np.sqrt(f) else: xcorr_err[xlag, ylag] = 0 return xcorr, xcorr_err
def testGetCollection(self): # NOTE - you need to subtract off background from the image # you run detection on. Here it is the template. bgConfig = self.subconfig.afwBackgroundConfig diffimTools.backgroundSubtract(bgConfig, [ self.templateImage, ]) detConfig = self.subconfig.detectionConfig maskPlane = detConfig.badMaskPlanes[0] maskVal = afwImage.Mask.getPlaneBitMask(maskPlane) kcDetect = ipDiffim.KernelCandidateDetectionF( pexConfig.makePropertySet(detConfig)) kcDetect.apply(self.templateImage, self.scienceImage) fpList1 = kcDetect.getFootprints() self.assertNotEqual(len(fpList1), 0) for fp in fpList1: bbox = fp.getBBox() tmi = afwImage.MaskedImageF(self.templateImage, bbox, origin=afwImage.LOCAL) smi = afwImage.MaskedImageF(self.scienceImage, bbox, origin=afwImage.LOCAL) tmask = tmi.getMask() smask = smi.getMask() for j in range(tmask.getHeight()): for i in range(tmask.getWidth()): # No masked pixels in either image self.assertEqual(tmask[i, j, afwImage.LOCAL], 0) self.assertEqual(smask[i, j, afwImage.LOCAL], 0) # add a masked pixel to the template image and make sure you don't get it tp = geom.Point2I(tmask.getWidth() // 2, tmask.getHeight() // 2) self.templateImage.mask[fpList1[0].getBBox(), afwImage.LOCAL][tp, afwImage.LOCAL] = maskVal kcDetect.apply(self.templateImage, self.scienceImage) fpList2 = kcDetect.getFootprints() self.assertEqual(len(fpList2), (len(fpList1) - 1)) # add a masked pixel to the science image and make sure you don't get it sp = geom.Point2I(smask.getWidth() // 2, smask.getHeight() // 2) self.scienceImage.mask[fpList1[1].getBBox(), afwImage.LOCAL][sp, afwImage.LOCAL] = maskVal self.scienceImage.mask[fpList1[2].getBBox(), afwImage.LOCAL][sp, afwImage.LOCAL] = maskVal kcDetect.apply(self.templateImage, self.scienceImage) fpList3 = kcDetect.getFootprints() self.assertEqual(len(fpList3), (len(fpList1) - 3))
def testConstructors(self): # test extent from extent 2-d e1 = geom.Extent2I(1, 2) e2 = geom.Extent2I(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) e1 = geom.Extent2D(1.2, 3.4) e2 = geom.Extent2D(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) e1 = geom.Extent2I(1, 2) e2 = geom.Extent2D(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) # test extent from extent 3-d e1 = geom.Extent3I(1, 2, 3) e2 = geom.Extent3I(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) e1 = geom.Extent3D(1.2, 3.4, 5.6) e2 = geom.Extent3D(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) e1 = geom.Extent3I(1, 2, 3) e2 = geom.Extent3D(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) # test extent from point 2-d e1 = geom.Point2I(1, 2) e2 = geom.Extent2I(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) e1 = geom.Point2D(1.2, 3.4) e2 = geom.Extent2D(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) e1 = geom.Point2I(1, 2) e2 = geom.Extent2D(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) # test extent from point 3-d e1 = geom.Point3I(1, 2, 3) e2 = geom.Extent3I(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) e1 = geom.Point3D(1.2, 3.4, 5.6) e2 = geom.Extent3D(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) e1 = geom.Point3I(1, 2, 3) e2 = geom.Extent3D(e1) self.assertAlmostEqual(tuple(e1), tuple(e2))
def _testAddToCoaddImpl(self, useMask, uniformWeight=True): """Test coadd""" trueImageValue = 10.0 imBBox = geom.Box2I(geom.Point2I(0, 0), geom.Extent2I(10, 20)) if useMask: coadd = afwImage.MaskedImageF(imBBox) weightMap = coadd.getImage().Factory(coadd.getBBox()) badBits = 0x1 badPixel = (float("NaN"), badBits, 0) truth = (trueImageValue, 0x0, 0) else: coadd = afwImage.ImageF(imBBox) weightMap = coadd.Factory(coadd.getBBox()) badPixel = float("NaN") truth = trueImageValue for i in range(0, 20, 3): image = coadd.Factory(coadd.getDimensions()) image.set(badPixel) subBBox = geom.Box2I(geom.Point2I(0, i), image.getDimensions() - geom.Extent2I(0, i)) subImage = image.Factory(image, subBBox, afwImage.LOCAL) subImage.set(truth) del subImage weight = 1.0 if uniformWeight else 1.0 + 0.1 * i if useMask: coaddUtils.addToCoadd(coadd, weightMap, image, badBits, weight) else: coaddUtils.addToCoadd(coadd, weightMap, image, weight) self.assertEqual(image[-1, -1, afwImage.LOCAL], truth) coadd /= weightMap if display: ds9.mtv(image, title="image", frame=1) ds9.mtv(coadd, title="coadd", frame=2) ds9.mtv(weightMap, title="weightMap", frame=3) stats = afwMath.makeStatistics(coadd, afwMath.MEAN | afwMath.STDEV) return [ trueImageValue, stats.getValue(afwMath.MEAN), 0.0, stats.getValue(afwMath.STDEV) ]
def testOneMask(self): mask = afwImage.Mask(geom.Extent2I(20, 20)) mask.set(0) bitmaskBad = mask.getPlaneBitMask('BAD') fsb = ipDiffim.FindSetBitsU() bbox = geom.Box2I(geom.Point2I(9, 10), geom.Point2I(11, 12)) submask = afwImage.Mask(mask, bbox, afwImage.LOCAL) submask |= bitmaskBad bbox2 = geom.Box2I(geom.Point2I(8, 8), geom.Point2I(19, 19)) fsb.apply(afwImage.Mask(mask, bbox2, afwImage.LOCAL)) self.assertEqual(fsb.getBits(), bitmaskBad)
def testPut(self): """Compare put of individual components vs a composite. Notes ----- Raw and calibration frames do not round trip (they are saved as DecoratedImageU and read in as ExposureU), so create the raw and flat manually. """ outputs = (dafPersist.RepositoryArgs(root=self.compositeOutput, tags='composite'), dafPersist.RepositoryArgs(root=self.nonCompositeOutput, tags='noncomposite')) butler = dafPersist.Butler(inputs=dafPersist.RepositoryArgs( root=self.input, mapper='lsst.obs.test.testMapper.TestMapper'), outputs=outputs) bbox = geom.Box2I(geom.Point2I(0, 0), geom.Point2I(10, 10)) raw = makeRampDecoratedImage(bbox=bbox, start=100, raw1=5, raw2="hello") flat = makeRampDecoratedImage(bbox=bbox, start=-55, flat1="me", flat2=47) # a hack-ish way of creating a rawAndFlat object; read in the data, then replace it with our own rawAndFlat = butler.get('rawAndFlat', dataId=self.dataId) rawAndFlat.raw = raw rawAndFlat.flat = flat butler.put(rawAndFlat, 'rawAndFlat', dataId=self.dataId, tags='composite') butler.put(raw, 'raw', dataId=self.dataId, tags='noncomposite') butler.put(raw, 'flat', dataId=self.dataId, tags='noncomposite') self.assertTrue( filecmp.cmp( os.path.join(self.compositeOutput, 'raw', 'raw_v1_fg.fits.gz'), os.path.join(self.nonCompositeOutput, 'raw', 'raw_v1_fg.fits.gz'))) self.assertTrue( filecmp.cmp( os.path.join(self.compositeOutput, 'flat', 'flat_fg.fits.gz'), os.path.join(self.nonCompositeOutput, 'flat', 'flat_fg.fits.gz')))
def setUp(self): nSources = 10 # CFHT Filters from the camera mapper. afwImageUtils.resetFilters() afwImageUtils.defineFilter('u', lambdaEff=374, alias="u.MP9301") afwImageUtils.defineFilter('g', lambdaEff=487, alias="g.MP9401") afwImageUtils.defineFilter('r', lambdaEff=628, alias="r.MP9601") afwImageUtils.defineFilter('i', lambdaEff=778, alias="i.MP9701") afwImageUtils.defineFilter('z', lambdaEff=1170, alias="z.MP9801") self.bbox = geom.Box2I(geom.Point2I(0, 0), geom.Extent2I(1024, 1153)) dataset = measTests.TestDataset(self.bbox) for srcIdx in range(nSources): dataset.addSource(100000.0, geom.Point2D(100, 100)) self.inputCatalogNoFlags, _ = make_input_source_catalog(dataset, False) self.inputCatalog, self.exposure = \ make_input_source_catalog(dataset, True) detector = DetectorWrapper(id=23, bbox=self.exposure.getBBox()).detector visit = afwImage.VisitInfo(exposureId=4321, exposureTime=200., date=dafBase.DateTime(nsecs=1400000000 * 10**9)) self.exposure.setDetector(detector) self.exposure.getInfo().setVisitInfo(visit) self.exposure.setFilter(afwImage.Filter('g.MP9401')) scale = 2 scaleErr = 1 self.photoCalib = afwImage.PhotoCalib(scale, scaleErr) self.exposure.setPhotoCalib(self.photoCalib)
def skipParent(self, source, mask): """Indicate that the parent source is not being deblended We set the appropriate flags and mask. @param source The source to flag as skipped @param mask The mask to update """ fp = source.getFootprint() source.set(self.deblendSkippedKey, True) if self.config.notDeblendedMask: mask.addMaskPlane(self.config.notDeblendedMask) fp.spans.setMask( mask, mask.getPlaneBitMask(self.config.notDeblendedMask)) # Set the center of the parent bbox = fp.getBBox() centerX = int(bbox.getMinX() + bbox.getWidth() / 2) centerY = int(bbox.getMinY() + bbox.getHeight() / 2) source.set(self.peakCenter, geom.Point2I(centerX, centerY)) # There are no deblended children, so nChild = 0 source.set(self.nChildKey, 0) # But we also want to know how many peaks that we would have # deblended if the parent wasn't skipped. source.set(self.nPeaksKey, len(fp.peaks)) # Top level parents are not a detected peak, so they have no peakId source.set(self.peakIdKey, 0) # Top level parents also have no parentNPeaks source.set(self.parentNPeaksKey, 0)