def exposureFromImage(image, dataId=None, mapper=None, logger=None, setVisitInfo=True): """Generate an Exposure from an image-like object If the image is a DecoratedImage then also set its WCS and metadata (Image and MaskedImage are missing the necessary metadata and Exposure already has those set) Parameters ---------- image : Image-like object Can be one of lsst.afw.image.DecoratedImage, Image, MaskedImage or Exposure. Returns ------- `lsst.afw.image.Exposure` Exposure containing input image. """ metadata = None if isinstance(image, afwImage.MaskedImage): exposure = afwImage.makeExposure(image) elif isinstance(image, afwImage.DecoratedImage): exposure = afwImage.makeExposure(afwImage.makeMaskedImage(image.getImage())) metadata = image.getMetadata() try: wcs = afwGeom.makeSkyWcs(metadata, strip=True) exposure.setWcs(wcs) except pexExcept.TypeError as e: # raised on failure to create a wcs (and possibly others) if logger is None: logger = lsstLog.Log.getLogger("CameraMapper") logger.warn("wcs set to None; insufficient information found in metadata to create a valid wcs: " "%s", e.args[0]) exposure.setMetadata(metadata) elif isinstance(image, afwImage.Exposure): # Exposure exposure = image metadata = exposure.getMetadata() else: # Image exposure = afwImage.makeExposure(afwImage.makeMaskedImage(image)) # # set VisitInfo if we can # if setVisitInfo and exposure.getInfo().getVisitInfo() is None: if metadata is not None: if mapper is None: if not logger: logger = lsstLog.Log.getLogger("CameraMapper") logger.warn("I can only set the VisitInfo if you provide a mapper") else: exposureId = mapper._computeCcdExposureId(dataId) visitInfo = mapper.makeRawVisitInfo(md=metadata, exposureId=exposureId) exposure.getInfo().setVisitInfo(visitInfo) return exposure
def makeExposure(bbox, scale, psfFwhm, flux): """Make a fake exposure @param bbox: Bounding box for image (Box2I) @param scale: Pixel scale (Angle) @param psfFwhm: PSF FWHM (arcseconds) @param flux: PSF flux (ADU) @return Exposure, source center """ image = afwImage.ImageF(bbox) image.set(0) center = afwGeom.Box2D(bbox).getCenter() psfSigma = psfFwhm/SIGMA_TO_FWHM/scale.asArcseconds() psfWidth = 2*int(4.0*psfSigma) + 1 psf = afwDetection.GaussianPsf(psfWidth, psfWidth, psfSigma) psfImage = psf.computeImage(center).convertF() psfFlux = psfImage.getArray().sum() psfImage *= flux/psfFlux subImage = afwImage.ImageF(image, psfImage.getBBox(afwImage.PARENT), afwImage.PARENT) subImage += psfImage exp = afwImage.makeExposure(afwImage.makeMaskedImage(image)) exp.setPsf(psf) exp.getMaskedImage().getVariance().set(1.0) exp.getMaskedImage().getMask().set(0) exp.setWcs(afwImage.makeWcs(afwCoord.Coord(0.0*afwGeom.degrees, 0.0*afwGeom.degrees), center, scale.asDegrees(), 0.0, 0.0, scale.asDegrees())) return exp, center
def readFull(self, fileDescriptor, parameters=None): """Read the full Exposure object. Parameters ---------- fileDescriptor : `FileDescriptor` Identifies the file to read and parameters to be used for reading. parameters : `dict`, optional If specified a dictionary of slicing parameters that overrides those in ``fileDescriptor`. Returns ------- exposure : `~lsst.afw.image.Exposure` Complete in-memory exposure. """ from lsst.afw.image import makeExposure, makeMaskedImage full = makeExposure(makeMaskedImage(self.readImage(fileDescriptor))) mask = self.readMask(fileDescriptor) if mask is not None: full.setMask(mask) variance = self.readVariance(fileDescriptor) if variance is not None: full.setVariance(variance) metadata = self.readMetadata(fileDescriptor) info = full.getInfo() info.setWcs(self.makeWcs(metadata)) info.setFilter(self.makeFilter(metadata)) info.setVisitInfo(self.makeVisitInfo(metadata)) # We shouldn't have to call stripMetadata() here because that should # have been done by makeVisitInfo and makeWcs (or by subclasses that # strip metadata for other components when constructing them). full.setMetadata(metadata) return full
def std_raw(self, item, dataId): md = item.getMetadata() md.set("LSSTAMP", "%(raft)s %(sensor)s %(channel)s" % dataId) newItem = afwImage.makeExposure( afwImage.makeMaskedImage(item.getImage())) newItem.setMetadata(md) return newItem
def standardizeCalib(self, dataset, item, dataId): """Standardize a calibration image read in by the butler Some calibrations are stored on disk as Images instead of MaskedImages or Exposures. Here, we convert it to an Exposure. @param dataset Dataset type (e.g., "bias", "dark" or "flat") @param item The item read by the butler @param dataId The data identifier (unused, included for future flexibility) @return standardized Exposure """ mapping = self.calibrations[dataset] if "MaskedImage" in mapping.python: exp = afwImage.makeExposure(item) elif "Image" in mapping.python: if hasattr(item, "getImage"): # For DecoratedImageX item = item.getImage() exp = afwImage.makeExposure(afwImage.makeMaskedImage(item)) elif "Exposure" in mapping.python: exp = item else: raise RuntimeError("Unrecognised python type: %s" % mapping.python) parent = super(PfsMapper, self) if hasattr(parent, "std_" + dataset): return getattr(parent, "std_" + dataset)(exp, dataId) return self._standardizeExposure(mapping, exp, dataId)
def testMultiple(self, pedestal=0.0): """Test subtraction of multiple fringe frames Paramters --------- pedestal : `float`, optional Pedestal to add into fringe frame. """ xFreqList = [0.1, 0.13, 0.06] xOffsetList = [0.0, 0.1, 0.2] yFreqList = [0.09, 0.12, 0.07] yOffsetList = [0.3, 0.2, 0.1] fringeList = [createFringe(self.size, self.size, xFreq, xOffset, yFreq, yOffset) for xFreq, xOffset, yFreq, yOffset in zip(xFreqList, xOffsetList, yFreqList, yOffsetList)] for fringe in fringeList: fMi = fringe.getMaskedImage() fMi += pedestal # Generate science frame scales = [0.33, 0.33, 0.33] image = afwImage.ImageF(self.size, self.size) image.set(0) for s, f in zip(scales, fringeList): image.scaledPlus(s, f.getMaskedImage().getImage()) mi = afwImage.makeMaskedImage(image) exp = afwImage.makeExposure(mi) exp.setFilter(afwImage.Filter('FILTER')) task = FringeTask(name="multiFringe", config=self.config) self.checkFringe(task, exp, fringeList, stddevMax=1.0e-2)
def _standardizeMasterCal(self, datasetType, item, dataId, setFilter=False): """Standardize a MasterCal image obtained from NOAO archive into Exposure These MasterCal images are MEF files with one HDU for each detector. Some WCS header, eg CTYPE1, exists only in the zeroth extensionr, so info in the zeroth header need to be copied over to metadata. @param datasetType: Dataset type ("bias" or "flat") @param item: The image read by the butler @param dataId: Data identifier @param setFilter: Whether to set the filter in the Exposure @return (lsst.afw.image.Exposure) the standardized Exposure """ mi = afwImage.makeMaskedImage(item.getImage()) md = item.getMetadata() masterCalMap = getattr(self, "map_" + datasetType) masterCalPath = masterCalMap(dataId).getLocations()[0] headerPath = re.sub(r'[\[](\d+)[\]]$', "[0]", masterCalPath) md0 = afwImage.readMetadata(headerPath) for kw in ('CTYPE1', 'CTYPE2', 'CRVAL1', 'CRVAL2', 'CUNIT1', 'CUNIT2', 'CD1_1', 'CD1_2', 'CD2_1', 'CD2_2'): if kw in md0.paramNames() and kw not in md.paramNames(): md.add(kw, md0.get(kw)) wcs = afwImage.makeWcs(md, True) exp = afwImage.makeExposure(mi, wcs) exp.setMetadata(md) return self._standardizeExposure(self.calibrations[datasetType], exp, dataId, filter=setFilter)
def createFringe(width, height, xFreq, xOffset, yFreq, yOffset): """Create a fringe frame. Parameters ---------- width, height : `int` Size of image. xFreq, yFreq : `float` Frequency of sinusoids in x and y. xOffset, yOffset : `float` Phase of sinusoids in x and y. Returns ------- exp : `lsst.afw.image.ExposureF` Fringe frame. """ image = afwImage.ImageF(width, height) array = image.getArray() x, y = np.indices(array.shape) array[x, y] = np.sin(xFreq*x + xOffset) + np.sin(yFreq*y + yOffset) mi = afwImage.makeMaskedImage(image) exp = afwImage.makeExposure(mi) exp.setFilter(afwImage.Filter('FILTER')) return exp
def makeTestImage(xsize=200, ysize=100, nCR=15): randArr = numpy.random.poisson(1000., xsize * ysize) randArr = numpy.array(randArr.reshape(ysize, xsize), dtype=numpy.float32) # force to ImageF factory = measAlg.GaussianPsfFactory() factory.addWing = False psf = factory.apply(4) # FWHM in pixels img = afwImage.makeImageFromArray(randArr) var = afwImage.ImageF(img, True) # copy constructor mask = afwImage.Mask(xsize, ysize) xind = numpy.random.randint(0, xsize, nCR) yind = numpy.random.randint(0, ysize, nCR) # set some CRs for xi, yi in zip(xind, yind): xi, yi = int(xi), int(yi) img.set(xi, yi, 1e6) mi = afwImage.makeMaskedImage(img, mask, var) exp = afwImage.makeExposure(mi) exp.setPsf(psf) return exp
def makeExposure(bbox, scale, psfFwhm, flux): """Make a fake exposure @param bbox: Bounding box for image (Box2I) @param scale: Pixel scale (Angle) @param psfFwhm: PSF FWHM (arcseconds) @param flux: PSF flux (ADU) @return Exposure, source center """ image = afwImage.ImageF(bbox) image.set(0) center = afwGeom.Box2D(bbox).getCenter() psfSigma = psfFwhm / SIGMA_TO_FWHM / scale.asArcseconds() psfWidth = 2 * int(4.0 * psfSigma) + 1 psf = afwDetection.GaussianPsf(psfWidth, psfWidth, psfSigma) psfImage = psf.computeImage(center).convertF() psfFlux = psfImage.getArray().sum() psfImage *= flux / psfFlux subImage = afwImage.ImageF(image, psfImage.getBBox(afwImage.PARENT), afwImage.PARENT) subImage += psfImage exp = afwImage.makeExposure(afwImage.makeMaskedImage(image)) exp.setPsf(psf) exp.getMaskedImage().getVariance().set(1.0) exp.getMaskedImage().getMask().set(0) exp.setWcs( afwImage.makeWcs( afwCoord.Coord(0.0 * afwGeom.degrees, 0.0 * afwGeom.degrees), center, scale.asDegrees(), 0.0, 0.0, scale.asDegrees())) return exp, center
def computeIntensity(imageR, imageG=None, imageB=None): """!Return a naive total intensity from the red, blue, and green intensities @param imageR intensity of image that'll be mapped to red; or intensity if imageG and imageB are None @param imageG intensity of image that'll be mapped to green; or None @param imageB intensity of image that'll be mapped to blue; or None Inputs may be MaskedImages, Images, or numpy arrays and the return is of the same type """ if imageG is None or imageB is None: assert imageG is None and imageB is None, \ "Please specify either a single image or red, green, and blue images" return imageR imageRGB = [imageR, imageG, imageB] for i, c in enumerate(imageRGB): if hasattr(c, "getImage"): c = imageRGB[i] = c.getImage() if hasattr(c, "getArray"): imageRGB[i] = c.getArray() intensity = (imageRGB[0] + imageRGB[1] + imageRGB[2]) / float(3) # # Repack into whatever type was passed to us # Image = afwImage.ImageU if intensity.dtype == 'uint16' else afwImage.ImageF if hasattr(imageR, "getImage"): # a maskedImage intensity = afwImage.makeMaskedImage(Image(intensity)) elif hasattr(imageR, "getArray"): intensity = Image(intensity) return intensity
def testMultiple(self, pedestal=0.0): """Test subtraction of multiple fringe frames Paramters --------- pedestal : `float`, optional Pedestal to add into fringe frame. """ xFreqList = [0.1, 0.13, 0.06] xOffsetList = [0.0, 0.1, 0.2] yFreqList = [0.09, 0.12, 0.07] yOffsetList = [0.3, 0.2, 0.1] fringeList = [ createFringe(self.size, self.size, xFreq, xOffset, yFreq, yOffset) for xFreq, xOffset, yFreq, yOffset in zip( xFreqList, xOffsetList, yFreqList, yOffsetList) ] for fringe in fringeList: fMi = fringe.getMaskedImage() fMi += pedestal # Generate science frame scales = [0.33, 0.33, 0.33] image = afwImage.ImageF(self.size, self.size) image.set(0) for s, f in zip(scales, fringeList): image.scaledPlus(s, f.getMaskedImage().getImage()) mi = afwImage.makeMaskedImage(image) exp = afwImage.makeExposure(mi) exp.setFilter(afwImage.FilterLabel(physical='FILTER')) task = FringeTask(name="multiFringe", config=self.config) self.checkFringe(task, exp, fringeList, stddevMax=1.0e-2)
def makeExposure(self, im, mask=None, variance=None): """Method for constructing an exposure object from an image and the information contained in this class to construct the Detector. Parameters ---------- im : `lsst.afw.image.Image` Image used to construct the exposure. mask : `lsst.afw.image.MaskU` Optional mask plane. variance : `lsst.afw.image.Image` Optional variance plance as an image of the same type as im. Returns ------- exposure : `lsst.afw.image.Exposure` Constructed exposure (specific type will match that of ``im``). """ if mask is None: mask = afwImage.Mask(im.getDimensions()) if variance is None: variance = im mi = afwImage.makeMaskedImage(im, mask, variance) detector = self.buildDetector() exp = afwImage.makeExposure(mi) exp.setDetector(detector) return exp
def readRawFile(fileName, dataId={}, detector=None): """Read a raw file from fileName, assembling it nicely. Parameters ---------- filename : `str` The fully-qualified filename. dataId : `lsst.daf.persistence.DataId` If provided, used to look up e.g. the filter. detector : `lsst.afw.cameraGeom.Detector` If provided, add this detector to the returned Exposure Returns ------- exposure : `lsst.afw.image.Exposure` The assembled exposure from the supplied filename. """ class Info(): def __init__(self, obj): self.obj = obj amps = [] for hdu in range(1, 16+1): exp = afwImage.makeExposure(afwImage.makeMaskedImage(afwImage.ImageF(fileName, hdu=hdu))) exp.setDetector(detector) amps.append(exp) component_info = {} component_info["raw_hdu"] = Info(afwImage.readMetadata(fileName, hdu=0)) component_info["raw_amp"] = Info(amps) exp = assemble_raw(dataId, component_info, None) return exp
def computeIntensity(imageR, imageG=None, imageB=None): """!Return a naive total intensity from the red, blue, and green intensities \param imageR intensity of image that'll be mapped to red; or intensity if imageG and imageB are None \param imageG intensity of image that'll be mapped to green; or None \param imageB intensity of image that'll be mapped to blue; or None Inputs may be MaskedImages, Images, or numpy arrays and the return is of the same type """ if imageG is None or imageB is None: assert imageG is None and imageB is None, \ "Please specify either a single image or red, green, and blue images" return imageR imageRGB = [imageR, imageG, imageB] for i, c in enumerate(imageRGB): if hasattr(c, "getImage"): c = imageRGB[i] = c.getImage() if hasattr(c, "getArray"): imageRGB[i] = c.getArray() intensity = (imageRGB[0] + imageRGB[1] + imageRGB[2])/float(3) # # Repack into whatever type was passed to us # Image = afwImage.ImageU if intensity.dtype == 'uint16' else afwImage.ImageF if hasattr(imageR, "getImage"): # a maskedImage intensity = afwImage.makeMaskedImage(Image(intensity)) elif hasattr(imageR, "getArray"): intensity = Image(intensity) return intensity
def X_standardizeCalib(self, dataset, item, dataId): """Standardize a calibration image read in by the butler Some calibrations are stored on disk as Images instead of MaskedImages or Exposures. Here, we convert it to an Exposure. @param dataset Dataset type (e.g., "bias", "dark" or "flat") @param item The item read by the butler @param dataId The data identifier (unused, included for future flexibility) @return standardized Exposure """ mapping = self.calibrations[dataset] if "MaskedImage" in mapping.python: exp = afwImage.makeExposure(item) elif "Image" in mapping.python: if hasattr(item, "getImage"): # For DecoratedImageX item = item.getImage() exp = afwImage.makeExposure(afwImage.makeMaskedImage(item)) elif "Exposure" in mapping.python: exp = item else: raise RuntimeError("Unrecognised python type: %s" % mapping.python) parent = super(CameraMapper, self) if hasattr(parent, "std_" + dataset): return getattr(parent, "std_" + dataset)(exp, dataId) return self._standardizeExposure(mapping, exp, dataId)
def process(self): clipboard = self.inputQueue.getNextDataset() metadataPolicy = self._policy.getPolicy("metadata") datatypePolicy = self._policy.getPolicy("datatype") imageKeys = self._policy.getStringArray("calibImageKey") if self._policy.exists("suffix"): suffix = self._policy.get("suffix") else: suffix = "Keyword" for imageKey in imageKeys: exposureKey = re.sub(r'Image', 'Exposure', imageKey) dImage = clipboard.get(imageKey) mask = afwImage.MaskU(dImage.getDimensions()) mask.set(0) var = afwImage.ImageF(dImage.getDimensions()) var.set(0) maskedImage = afwImage.makeMaskedImage(dImage.getImage(), mask, var) metadata = dImage.getMetadata() exposure = afwImage.makeExposure(maskedImage) exposure.setMetadata(metadata) clipboard.put(exposureKey, exposure) self.outputQueue.addDataset(clipboard)
def createFringe(width, height, xFreq, xOffset, yFreq, yOffset): """Create a fringe frame. Parameters ---------- width, height : `int` Size of image. xFreq, yFreq : `float` Frequency of sinusoids in x and y. xOffset, yOffset : `float` Phase of sinusoids in x and y. Returns ------- exp : `lsst.afw.image.ExposureF` Fringe frame. """ image = afwImage.ImageF(width, height) array = image.getArray() x, y = np.indices(array.shape) array[x, y] = np.sin(xFreq * x + xOffset) + np.sin(yFreq * y + yOffset) mi = afwImage.makeMaskedImage(image) exp = afwImage.makeExposure(mi) exp.setFilter(afwImage.FilterLabel(band='y', physical='FILTER')) return exp
def test1295(self): """A test case for #1295 (failure to interpolate over groups of defects.""" im = afwImage.ImageF(lsst.geom.ExtentI(100, 100)) mi = afwImage.makeMaskedImage(im) mi.set(100) flat = afwImage.ImageF(im.getDimensions()) flat.set(1) flat[50:51, :, afwImage.LOCAL] = 0.0 flat[55:56, :, afwImage.LOCAL] = 0.0 flat[58:59, :, afwImage.LOCAL] = 0.0 flat[51:60, 51:, afwImage.LOCAL] = 0.0 mi /= flat if display: afwDisplay.Display(frame=0).mtv(mi, title=self._testMethodName + ": Raw") defectList = algorithms.Defects() bbox = lsst.geom.BoxI(lsst.geom.PointI(50, 0), lsst.geom.ExtentI(1, 100)) defectList.append(algorithms.Defect(bbox)) bbox = lsst.geom.BoxI(lsst.geom.PointI(55, 0), lsst.geom.ExtentI(1, 100)) defectList.append(algorithms.Defect(bbox)) bbox = lsst.geom.BoxI(lsst.geom.PointI(58, 0), lsst.geom.ExtentI(1, 100)) defectList.append(algorithms.Defect(bbox)) bbox = lsst.geom.BoxI(lsst.geom.PointI(51, 51), lsst.geom.ExtentI(9, 49)) defectList.append(algorithms.Defect(bbox)) psf = algorithms.DoubleGaussianPsf(15, 15, 1./(2*math.sqrt(2*math.log(2)))) algorithms.interpolateOverDefects(mi, psf, defectList, 50.) if display: afwDisplay.Display(frame=1).mtv(mi, title=self._testMethodName + ": Interpolated") self.assertTrue(np.isfinite(mi.image[56, 51, afwImage.LOCAL]))
def readFull(self, parameters=None): """Read the full Exposure object. Parameters ---------- parameters : `dict`, optional If specified, a dictionary of slicing parameters that overrides those in the `fileDescriptor` attribute. Returns ------- exposure : `~lsst.afw.image.Exposure` Complete in-memory exposure. """ from lsst.afw.image import makeExposure, makeMaskedImage full = makeExposure(makeMaskedImage(self.readImage())) mask = self.readMask() if mask is not None: full.setMask(mask) variance = self.readVariance() if variance is not None: full.setVariance(variance) full.setDetector(self.getDetector(self.observationInfo.detector_num)) info = full.getInfo() info.setFilter(self.makeFilter()) info.setVisitInfo(self.makeVisitInfo()) info.setWcs(self.makeWcs(info.getVisitInfo(), info.getDetector())) # We don't need to call stripMetadata() here because it has already # been stripped during creation of the ObservationInfo, WCS, etc. full.setMetadata(self.metadata) return full
def readFits(fileName, hdu=0, flags=0): """Read a our list of Backgrounds from a file @param fileName FITS file to read @param hdu First Header/Data Unit to attempt to read from @param flags Flags to control details of reading; currently unused, but present for consistency with afw.table.BaseCatalog.readFits. See also getImage() """ if not isinstance(fileName, MemFileManager) and not os.path.exists(fileName): raise RuntimeError("File not found: %s" % fileName) self = BackgroundList() while True: hdu += 1 md = dafBase.PropertyList() try: img = afwImage.ImageF(fileName, hdu, md); hdu += 1 except FitsError as e: break msk = afwImage.MaskU( fileName, hdu); hdu += 1 var = afwImage.ImageF(fileName, hdu) statsImage = afwImage.makeMaskedImage(img, msk, var) x0 = md.get("BKGD_X0") y0 = md.get("BKGD_Y0") width = md.get("BKGD_WIDTH") height = md.get("BKGD_HEIGHT") imageBBox = afwGeom.BoxI(afwGeom.PointI(x0, y0), afwGeom.ExtentI(width, height)) interpStyle = md.get("INTERPSTYLE") undersampleStyle = md.get("UNDERSAMPLESTYLE") # Older outputs won't have APPROX* settings. Provide alternative defaults. # Note: Currently X- and Y-orders must be equal due to a limitation in # math::Chebyshev1Function2. Setting approxOrderY = -1 is equivalent # to saying approxOrderY = approxOrderX. approxStyle = md.get("APPROXSTYLE") if "APPROXSTYLE" in md.names() \ else afwMath.ApproximateControl.UNKNOWN approxOrderX = md.get("APPROXORDERX") if "APPROXORDERX" in md.names() else 1 approxOrderY = md.get("APPROXORDERY") if "APPROXORDERY" in md.names() else -1 approxWeighting = md.get("APPROXWEIGHTING") if "APPROXWEIGHTING" in md.names() else True bkgd = afwMath.BackgroundMI(imageBBox, statsImage) bctrl = bkgd.getBackgroundControl() bctrl.setInterpStyle(interpStyle) bctrl.setUndersampleStyle(undersampleStyle) actrl = afwMath.ApproximateControl(approxStyle, approxOrderX, approxOrderY, approxWeighting) bctrl.setApproximateControl(actrl) bgInfo = (bkgd, interpStyle, undersampleStyle, approxStyle, approxOrderX, approxOrderY, approxWeighting) self.append(bgInfo) return self
def std_dark(self, item, dataId): exp = afwImage.makeExposure(afwImage.makeMaskedImage(item)) rawPath = self.map_raw(dataId).getLocations()[0] headerPath = re.sub(r'[\[](\d+)[\]]$', "[0]", rawPath) md0 = afwImage.readMetadata(headerPath) visitInfo = self.makeRawVisitInfo(md0) exp.getInfo().setVisitInfo(visitInfo) return self._standardizeExposure(self.calibrations["dark"], exp, dataId, filter=False)
def makeExpFromIm(im, detector): wcs = makeFakeWcs() var = afwImage.ImageF(im) mask = afwImage.MaskU(im.getDimensions()) mi = afwImage.makeMaskedImage(im, mask, var) exp = afwImage.makeExposure(mi) exp.setDetector(detector) exp.setWcs(wcs) return exp
def getExposure(self): """Construct a test exposure. The test exposure has a simple WCS set, as well as a list of unlikely header keywords that can be removed during ISR processing to exercise that code. Returns ------- exposure : `lsst.afw.exposure.Exposure` Construct exposure containing masked image of the appropriate size. """ camera = self.getCamera() detector = camera[self.config.detectorIndex] image = afwUtils.makeImageFromCcd(detector, isTrimmed=self.config.isTrimmed, showAmpGain=False, rcMarkSize=0, binSize=1, imageFactory=afwImage.ImageF) var = afwImage.ImageF(image.getDimensions()) mask = afwImage.Mask(image.getDimensions()) image.assign(0.0) maskedImage = afwImage.makeMaskedImage(image, mask, var) exposure = afwImage.makeExposure(maskedImage) exposure.setDetector(detector) exposure.setWcs(self.getWcs()) visitInfo = afwImage.VisitInfo(exposureTime=self.config.expTime, darkTime=self.config.darkTime) exposure.getInfo().setVisitInfo(visitInfo) metadata = exposure.getMetadata() metadata.add("SHEEP", 7.3, "number of sheep on farm") metadata.add("MONKEYS", 155, "monkeys per tree") metadata.add("VAMPIRES", 4, "How scary are vampires.") ccd = exposure.getDetector() newCcd = ccd.rebuild() newCcd.clear() for amp in ccd: newAmp = amp.rebuild() newAmp.setLinearityCoeffs((0., 1., 0., 0.)) newAmp.setLinearityType("Polynomial") newAmp.setGain(self.config.gain) newAmp.setSuspectLevel(25000.0) newAmp.setSaturation(32000.0) newCcd.append(newAmp) exposure.setDetector(newCcd.finish()) exposure.image.array[:] = np.zeros(exposure.getImage().getDimensions()).transpose() exposure.mask.array[:] = np.zeros(exposure.getMask().getDimensions()).transpose() exposure.variance.array[:] = np.zeros(exposure.getVariance().getDimensions()).transpose() return exposure
def standardizeCalib(self, dataset, item, dataId): mapping = self.calibrations[dataset] if "Image" in mapping.python: exp = afwImage.makeMaskedImage(item) exp = afwImage.makeExposure(exp) exp = self._standardizeExposure(mapping, exp, \ dataId, filter=False, trimmed=False) return exp
def testMakeMaskedImageXY0(self): """Test that makeMaskedImage sets XY0 correctly""" im = afwImage.ImageF(200, 300) xy0 = afwGeom.PointI(10, 20) im.setXY0(*xy0) mi = afwImage.makeMaskedImage(im) self.assertEqual(mi.getImage().getXY0(), xy0) self.assertEqual(mi.getMask().getXY0(), xy0) self.assertEqual(mi.getVariance().getXY0(), xy0)
def testMakeMaskedImageXY0(self): """Test that makeMaskedImage sets XY0 correctly""" im = afwImage.ImageF(200, 300) xy0 = lsst.geom.PointI(10, 20) im.setXY0(*xy0) mi = afwImage.makeMaskedImage(im) self.assertEqual(mi.image.getXY0(), xy0) self.assertEqual(mi.mask.getXY0(), xy0) self.assertEqual(mi.variance.getXY0(), xy0)
def saturate(image, satValue): """Simulate saturation on an image, so we can test 'replaceSaturatedPixels' Takes an Image, sets saturated pixels to NAN and masks them, returning a MaskedImage. """ image = afwImage.makeMaskedImage(image) afwDetect.FootprintSet(image, afwDetect.Threshold(satValue), "SAT") arr = image.getImage().getArray() arr[np.where(arr >= satValue)] = np.nan return image
def testImagesOverlap(self): # make pairs of image, variance and mask planes # using the same dimensions for each so we can mix and match # while making masked images dim = lsst.geom.Extent2I(10, 8) # a set of bounding boxes, some of which overlap each other # and some of which do not, and include the full image bounding box bboxes = ( lsst.geom.Box2I(lsst.geom.Point2I(0, 0), dim), lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(3, 3)), lsst.geom.Box2I(lsst.geom.Point2I(2, 2), lsst.geom.Extent2I(6, 4)), lsst.geom.Box2I(lsst.geom.Point2I(4, 4), lsst.geom.Extent2I(6, 4)), ) masks = [afwImage.Mask(dim), afwImage.Mask(dim)] variances = [afwImage.ImageF(dim), afwImage.ImageF(dim)] imageClasses = (afwImage.ImageF, afwImage.ImageD, afwImage.ImageI, afwImage.ImageU) for ImageClass1, ImageClass2 in itertools.product(imageClasses, imageClasses): images = [ImageClass1(dim), ImageClass2(dim)] for image1, mask1, variance1, image2, mask2, variance2 in itertools.product( images, masks, variances, images, masks, variances): with self.subTest(ImageClass1=ImageClass1, ImageClass2=ImageClass2, image1=image1, mask1=mask1, variance1=variance1, image2=image2, mask2=mask2, variance2=variance2): shouldOverlap = (image1 is image2) or (mask1 is mask2) or (variance1 is variance2) mi1 = afwImage.makeMaskedImage(image=image1, mask=mask1, variance=variance1) mi2 = afwImage.makeMaskedImage(image=image2, mask=mask2, variance=variance2) self.assertEqual(afwImage.imagesOverlap(mi1, mi2), shouldOverlap) self.assertEqual(afwImage.imagesOverlap(mi2, mi1), shouldOverlap) for bbox1, bbox2 in itertools.product(bboxes, bboxes): with self.subTest(bbox1=bbox1, bbox2=bbox2): subMi1 = afwImage.makeMaskedImage(image=type(image1)(image1, bbox1), mask=afwImage.Mask(mask1, bbox1), variance=afwImage.ImageF(variance1, bbox1)) subMi2 = afwImage.makeMaskedImage(image=type(image2)(image2, bbox2), mask=afwImage.Mask(mask2, bbox2), variance=afwImage.ImageF(variance2, bbox2)) subregionsShouldOverlap = shouldOverlap and bbox1.overlaps(bbox2) self.assertEqual(afwImage.imagesOverlap(subMi1, subMi2), subregionsShouldOverlap) self.assertEqual(afwImage.imagesOverlap(subMi2, subMi1), subregionsShouldOverlap)
def makeGalaxy(width, height, flux, a, b, theta, dx=0.0, dy=0.0, xy0=None, xcen=None, ycen=None): """Make a fake galaxy image. """ gal = afwImage.ImageF(width, height) if xcen is None: xcen = 0.5*width + dx if ycen is None: ycen = 0.5*height + dy I0 = flux/(2*math.pi*a*b) if xy0 is not None: gal.setXY0(xy0) c, s = math.cos(math.radians(theta)), math.sin(math.radians(theta)) ii, iuu, ivv = 0.0, 0.0, 0.0 for y in range(height): for x in range(width): dx, dy = x + gal.getX0() - xcen, y + gal.getY0() - ycen if math.hypot(dx, dy) < 10.5: nsample = 5 subZ = np.linspace(-0.5*(1 - 1/nsample), 0.5*(1 - 1/nsample), nsample) else: nsample = 1 subZ = [0.0] val = 0 for sx in subZ: for sy in subZ: u = c*(dx + sx) + s*(dy + sy) v = -s*(dx + sx) + c*(dy + sy) val += I0*math.exp(-0.5*((u/a)**2 + (v/b)**2)) if val < 0: val = 0 gal[afwGeom.Point2I(x, y), afwImage.LOCAL] = val/nsample**2 ii += val iuu += val*u**2 ivv += val*v**2 iuu /= ii ivv /= ii exp = afwImage.makeExposure(afwImage.makeMaskedImage(gal)) exp.getMaskedImage().getVariance().set(1.0) scale = 1.0e-4*afwGeom.degrees cdMatrix = afwGeom.makeCdMatrix(scale=scale, flipX=True) exp.setWcs(afwGeom.makeSkyWcs(crpix=afwGeom.Point2D(0.0, 0.0), crval=afwGeom.SpherePoint(0.0, 0.0, afwGeom.degrees), cdMatrix=cdMatrix)) # add a dummy Psf. The new SdssCentroid needs one exp.setPsf(afwDetection.GaussianPsf(11, 11, 0.01)) return exp
def writeDefects(self, maskFile, ccd, format=None): """Given a Mask, find the defects for each amp in the specified CCD (0-indexed). If format is provided, it's expected to be used as "format % (ccd, amp)" to generate a .paf filename to write the defects too. If it's "-", write to stdout""" # Metadata should have validity range keywords, but it doesn't. if False: metaData = afwImage.readMetadata(maskFile, 0) hdu = ccd + 2 im = afwImage.ImageF(maskFile, hdu) im -= 1 im *= -1 mask = afwImage.MaskU(im.getBBox(afwImage.PARENT)) mask.set(0x0) mask = afwImage.makeMaskedImage(im, mask) for amp in self.ampList(): subMask = mask.Factory(mask, self.getTrimSecBBox(amp), afwImage.LOCAL) ds = afwDetection.makeFootprintSet(subMask, afwDetection.Threshold(0.5), "INTRP") if False: ds9.setDefaultFrame(amp) ds9.mtv(subMask) ds9.dot("Amp %d" % amp, 0, 0) if not format: return if format == "-": fd = sys.stdout else: fd = open(format % (ccd, amp), "w") print >> fd, """\ #<?cfg paf policy ?> # # Defects for CCD%03d amp %02d generated from %s, HDU %d # # Coordinates are trimmed and per-amp not per-CCD. If you change this, the ISR will have to change # # Generated by $HeadURL$ # """ % (ccd, amp, maskFile, hdu), for foot in ds.getFootprints(): afwDetectionUtils.writeFootprintAsDefects(fd, foot)
def setUp(self): # We create an image that has a ramp (unique values for each pixel), # with a single high pixel that allows for centering self.width, self.height = 50, 50 self.xcen, self.ycen = self.width // 2, self.height // 2 self.image = afwImage.ImageF(afwGeom.ExtentI(self.width, self.height)) for y in range(self.height): for x in range(self.width): self.image.set(x, y, self.width * y + x) self.image.set(self.xcen, self.ycen, 1234567.89) self.exp = afwImage.makeExposure(afwImage.makeMaskedImage(self.image)) self.exp.getMaskedImage().getVariance().set(1.0) scale = 0.2 / 3600 wcs = afwImage.makeWcs( afwCoord.Coord(0 * afwGeom.degrees, 0 * afwGeom.degrees), afwGeom.Point2D(self.xcen, self.ycen), scale, 0, 0, scale) self.exp.setWcs(wcs) if display: frame = 1 ds9.mtv(self.exp, frame=frame, title="Single pixel") # We will use a GaussianCentroid to tweak the center (it should not, for forced measurement) # and a NaiveFlux to measure the single pixel. We'll start offset from the high pixel, # so that a forced measurement should yield a flux of zero, while a measurement that was allowed to # center should yield a flux of unity. # Note that previous versions used NaiveCentroid, which was so nonrobust that it failed to get # right answer when the input value was round-tripped through Wcs and modified by ~1E-8. gaussianCentroid = measAlg.GaussianCentroidControl() naiveFlux = measAlg.NaiveFluxControl() naiveFlux.radius = 0.5 self.x, self.y = self.xcen - 1, self.ycen - 1 self.foot = afwDetection.Footprint(afwGeom.Point2I(self.x, self.y), 2) self.foot.addPeak(self.x, self.y, float("NaN")) schema = afwTable.SourceTable.makeMinimalSchema() msb = measAlg.MeasureSourcesBuilder() msb.addAlgorithm(naiveFlux) msb.setCentroider(gaussianCentroid) self.measurer = msb.build(schema) self.table = afwTable.SourceTable.make(schema) self.table.defineCentroid("centroid.gaussian") schemaF = afwTable.SourceTable.makeMinimalSchema() msbF = measAlg.MeasureSourcesBuilder("", True) msbF.addAlgorithm(naiveFlux) msbF.setCentroider(gaussianCentroid) self.measurerF = msbF.build(schemaF) self.tableF = afwTable.SourceTable.make(schemaF) self.tableF.defineCentroid("centroid.gaussian")
def toCcdBackground(self, detector, bbox): """Produce a background model for a CCD The superpixel background model is warped back to the CCD frame, for application to the individual CCD. Parameters ---------- detector : `lsst.afw.cameraGeom.Detector` CCD for which to produce background model. bbox : `lsst.geom.Box2I` Bounding box of CCD exposure. Returns ------- bg : `lsst.afw.math.BackgroundList` Background model for CCD. """ transform = detector.getTransformMap().getTransform( detector.makeCameraSys(afwCameraGeom.PIXELS), detector.makeCameraSys(afwCameraGeom.FOCAL_PLANE)) binTransform = ( geom.AffineTransform.makeScaling(self.config.binning) * geom.AffineTransform.makeTranslation(geom.Extent2D(0.5, 0.5))) # Binned image on CCD --> unbinned image on CCD --> focal plane --> binned focal plane toSample = afwGeom.makeTransform(binTransform).then(transform).then( self.transform) focalPlane = self.getStatsImage() fpNorm = afwImage.ImageF(focalPlane.getBBox()) fpNorm.set(1.0) image = afwImage.ImageF(bbox.getDimensions() // self.config.binning) norm = afwImage.ImageF(image.getBBox()) ctrl = afwMath.WarpingControl("bilinear") afwMath.warpImage(image, focalPlane, toSample.inverted(), ctrl) afwMath.warpImage(norm, fpNorm, toSample.inverted(), ctrl) image /= norm mask = afwImage.Mask(image.getBBox()) isBad = numpy.isnan(image.getArray()) mask.getArray()[isBad] = mask.getPlaneBitMask("BAD") image.getArray()[isBad] = image.getArray()[~isBad].mean() return afwMath.BackgroundList( (afwMath.BackgroundMI(bbox, afwImage.makeMaskedImage(image, mask)), afwMath.stringToInterpStyle(self.config.interpolation), afwMath.stringToUndersampleStyle("REDUCE_INTERP_ORDER"), afwMath.ApproximateControl.UNKNOWN, 0, 0, False))
def makeGalaxy(width, height, flux, a, b, theta, dx=0.0, dy=0.0, xy0=None, xcen=None, ycen=None): """Make a fake galaxy image""" gal = afwImage.ImageF(width, height) if xcen is None: xcen = 0.5*width + dx if ycen is None: ycen = 0.5*height + dy I0 = flux/(2*math.pi*a*b) if xy0 is not None: gal.setXY0(xy0) c, s = math.cos(math.radians(theta)), math.sin(math.radians(theta)) I, Iuu, Ivv = 0.0, 0.0, 0.0 for y in range(height): for x in range(width): dx, dy = x + gal.getX0() - xcen, y + gal.getY0() - ycen if math.hypot(dx, dy) < 10.5: nsample = float(5) subZ = np.linspace(-0.5*(1 - 1/nsample), 0.5*(1 - 1/nsample), nsample) else: nsample = 1 subZ = [0.0] val = 0 for sx in subZ: for sy in subZ: u = c*(dx + sx) + s*(dy + sy) v = -s*(dx + sx) + c*(dy + sy) val += I0*math.exp(-0.5*((u/a)**2 + (v/b)**2)) if val < 0: val = 0 gal.set(x, y, val/nsample**2) I += val Iuu += val*u**2 Ivv += val*v**2 Iuu /= I; Ivv /= I exp = afwImage.makeExposure(afwImage.makeMaskedImage(gal)) exp.getMaskedImage().getVariance().setXY0(exp.getXY0()) # workaround #2577 exp.getMaskedImage().getVariance().set(1.0) exp.setWcs(afwImage.makeWcs(afwCoord.Coord(0.0*afwGeom.degrees, 0.0*afwGeom.degrees), afwGeom.Point2D(0.0, 0.0), 1.0e-4, 0.0, 0.0, 1.0e-4)) # add a dummy Psf. The new SdssCentroid needs one exp.setPsf(afwDetection.GaussianPsf(11, 11, 0.01)) return exp
def getExposure(self): r"""Construct a test exposure. The test exposure has a simple WCS set, as well as a list of unlikely header keywords that can be removed during ISR processing to exercise that code. Returns ------- exposure : `lsst.afw.exposure.Exposure` Construct exposure containing masked image of the appropriate size. """ camera = self.getCamera() detector = camera[self.config.detectorIndex] image = afwUtils.makeImageFromCcd(detector, isTrimmed=self.config.isTrimmed, showAmpGain=False, rcMarkSize=0, binSize=1, imageFactory=afwImage.ImageF) var = afwImage.ImageF(image.getDimensions()) mask = afwImage.Mask(image.getDimensions()) image.assign(0.0) maskedImage = afwImage.makeMaskedImage(image, mask, var) exposure = afwImage.makeExposure(maskedImage) exposure.setDetector(detector) exposure.setWcs(self.getWcs()) visitInfo = afwImage.VisitInfo(exposureTime=self.config.expTime, darkTime=self.config.darkTime) exposure.getInfo().setVisitInfo(visitInfo) metadata = exposure.getMetadata() metadata.add("SHEEP", 7.3, "number of sheep on farm") metadata.add("MONKEYS", 155, "monkeys per tree") metadata.add("VAMPIRES", 4, "How scary are vampires.") for amp in exposure.getDetector(): amp.setLinearityCoeffs((0., 1., 0., 0.)) amp.setLinearityType("Polynomial") amp.setGain(self.config.gain) exposure.image.array[:] = np.zeros(exposure.getImage().getDimensions()).transpose() exposure.mask.array[:] = np.zeros(exposure.getMask().getDimensions()).transpose() exposure.variance.array[:] = np.zeros(exposure.getVariance().getDimensions()).transpose() return exposure
def testBrighterFatterInterface(self): """Test brighter fatter correction interface using a delta function kernel on a flat image""" image = afwImage.ImageF(100, 100) image.set(100) ref_image = afwImage.ImageF(image, True) mi = afwImage.makeMaskedImage(image) exp = afwImage.makeExposure(mi) with open(self.filename, 'rb') as f: bfKernel = pickle.load(f) isrFunctions.brighterFatterCorrection(exp, bfKernel, 5, 100, False) self.assertImagesEqual(ref_image, image)
def writeDefects(self, maskFile, ccd, format=None): """Given a Mask, find the defects for each amp in the specified CCD (0-indexed). If format is provided, it's expected to be used as "format % (ccd, amp)" to generate a .paf filename to write the defects too. If it's "-", write to stdout""" # Metadata should have validity range keywords, but it doesn't. if False: metaData = afwImage.readMetadata(maskFile, 0) hdu = ccd + 2 im = afwImage.ImageF(maskFile, hdu) im -= 1 im *= -1 mask = afwImage.MaskU(im.getBBox(afwImage.PARENT)); mask.set(0x0) mask = afwImage.makeMaskedImage(im, mask) for amp in self.ampList(): subMask = mask.Factory(mask, self.getTrimSecBBox(amp), afwImage.LOCAL) ds = afwDetection.makeFootprintSet(subMask, afwDetection.Threshold(0.5), "INTRP") if False: ds9.setDefaultFrame(amp) ds9.mtv(subMask) ds9.dot("Amp %d" % amp, 0, 0) if not format: return if format == "-": fd = sys.stdout else: fd = open(format % (ccd, amp), "w") print >> fd, """\ #<?cfg paf policy ?> # # Defects for CCD%03d amp %02d generated from %s, HDU %d # # Coordinates are trimmed and per-amp not per-CCD. If you change this, the ISR will have to change # # Generated by $HeadURL$ # """ % (ccd, amp, maskFile, hdu), for foot in ds.getFootprints(): afwDetectionUtils.writeFootprintAsDefects(fd, foot)
def makeExposure(bbox, scale, psfFwhm, flux): """Make a fake exposure Parameters ---------- bbox : `lsst.afw.geom.Box2I` Bounding box for image. scale : `lsst.afw.geom.Angle` Pixel scale. psfFwhm : `float` PSF FWHM (arcseconds) flux : `float` PSF flux (ADU) Returns ------- exposure : `lsst.afw.image.ExposureF` Fake exposure. center : `lsst.afw.geom.Point2D` Position of fake source. """ image = afwImage.ImageF(bbox) image.set(0) center = afwGeom.Box2D(bbox).getCenter() psfSigma = psfFwhm / SIGMA_TO_FWHM / scale.asArcseconds() psfWidth = 2 * int(4.0 * psfSigma) + 1 psf = afwDetection.GaussianPsf(psfWidth, psfWidth, psfSigma) psfImage = psf.computeImage(center).convertF() psfFlux = psfImage.getArray().sum() psfImage *= flux / psfFlux subImage = afwImage.ImageF(image, psfImage.getBBox(afwImage.PARENT), afwImage.PARENT) subImage += psfImage exp = afwImage.makeExposure(afwImage.makeMaskedImage(image)) exp.setPsf(psf) exp.getMaskedImage().getVariance().set(1.0) exp.getMaskedImage().getMask().set(0) cdMatrix = afwGeom.makeCdMatrix(scale=scale) exp.setWcs( afwGeom.makeSkyWcs(crpix=center, crval=afwGeom.SpherePoint(0.0, 0.0, afwGeom.degrees), cdMatrix=cdMatrix)) return exp, center
def createFringe(width, height, xFreq, xOffset, yFreq, yOffset): """Create a fringe frame @param width, height Size of image @param xFreq, yFreq Frequency of sinusoids in x and y @param xOffset, yOffset Phase of sinusoids in x and y @return Fringe frame """ image = afwImage.ImageF(width, height) array = image.getArray() x, y = numpy.indices(array.shape) array[x,y] = numpy.sin(xFreq*x + xOffset) + numpy.sin(yFreq*y + yOffset) mi = afwImage.makeMaskedImage(image) exp = afwImage.makeExposure(mi) exp.setFilter(afwImage.Filter('FILTER')) return exp
def testMaskedImageFromImage(self): w, h = 10, 20 dims = afwGeom.Extent2I(w, h) im, mask, var = afwImage.ImageF(dims), afwImage.MaskU(dims), afwImage.ImageF(dims) im.set(666) maskedImage = afwImage.MaskedImageF(im, mask, var) maskedImage = afwImage.makeMaskedImage(im, mask, var) maskedImage = afwImage.MaskedImageF(im) self.assertEqual(im.getDimensions(), maskedImage.getImage().getDimensions()) self.assertEqual(im.getDimensions(), maskedImage.getMask().getDimensions()) self.assertEqual(im.getDimensions(), maskedImage.getVariance().getDimensions()) self.assertEqual(maskedImage.get(0, 0), (im.get(0, 0), 0x0, 0.0))
def test_BrighterFatterInterface(self): """Test brighter fatter correction interface using a delta function kernel on a flat image""" image = afwImage.ImageF(100, 100) image.set(100) ref_image = afwImage.ImageF(image, True) mi = afwImage.makeMaskedImage(image) exp = afwImage.makeExposure(mi) self.bfk.makeDetectorKernelFromAmpwiseKernels(self.detector.getName()) kernelToUse = self.bfk.detKernels[self.detector.getName()] isrFunctions.brighterFatterCorrection(exp, kernelToUse, 5, 100, False) self.assertImagesEqual(ref_image, image)
def createFringe(width, height, xFreq, xOffset, yFreq, yOffset): """Create a fringe frame @param width, height Size of image @param xFreq, yFreq Frequency of sinusoids in x and y @param xOffset, yOffset Phase of sinusoids in x and y @return Fringe frame """ image = afwImage.ImageF(width, height) array = image.getArray() x, y = np.indices(array.shape) array[x, y] = np.sin(xFreq * x + xOffset) + np.sin(yFreq * y + yOffset) mi = afwImage.makeMaskedImage(image) exp = afwImage.makeExposure(mi) exp.setFilter(afwImage.Filter('FILTER')) return exp
def testBrighterFatterInterface(self): """Test brighter fatter correction interface using a delta function kernel on a flat image""" image = afwImage.ImageF(100,100) image.set(100) ref_image = afwImage.ImageF(image, True) mi = afwImage.makeMaskedImage(image) exp = afwImage.makeExposure(mi) isrTask = ipIsr.IsrTask() with open(self.filename) as f: bfKernel = pickle.load(f) isrTask.brighterFatterCorrection(exp, bfKernel, 5, 100, False) self.assertTrue(numpy.all(ref_image.getArray() == image.getArray()))
def makeGalaxy(width, height, flux, a, b, theta, dx=0.0, dy=0.0, xy0=None, xcen=None, ycen=None): """Make a fake galaxy image""" gal = afwImage.ImageF(width, height) if xcen is None: xcen = 0.5*width + dx if ycen is None: ycen = 0.5*height + dy I0 = flux/(2*math.pi*a*b) if xy0 is not None: gal.setXY0(xy0) c, s = math.cos(math.radians(theta)), math.sin(math.radians(theta)) I, Iuu, Ivv = 0.0, 0.0, 0.0 for y in range(height): for x in range(width): dx, dy = x + gal.getX0() - xcen, y + gal.getY0() - ycen if math.hypot(dx, dy) < 10.5: nsample = float(5) subZ = np.linspace(-0.5*(1 - 1/nsample), 0.5*(1 - 1/nsample), nsample) else: nsample = 1 subZ = [0.0] val = 0 for sx in subZ: for sy in subZ: u = c*(dx + sx) + s*(dy + sy) v = -s*(dx + sx) + c*(dy + sy) val += I0*math.exp(-0.5*((u/a)**2 + (v/b)**2)) if val < 0: val = 0 gal.set(x, y, val/nsample**2) I += val Iuu += val*u**2 Ivv += val*v**2 Iuu /= I; Ivv /= I exp = afwImage.makeExposure(afwImage.makeMaskedImage(gal)) exp.getMaskedImage().getVariance().setXY0(exp.getXY0()) # workaround #2577 exp.getMaskedImage().getVariance().set(1.0) exp.setWcs(afwImage.makeWcs(afwCoord.Coord(0.0*afwGeom.degrees, 0.0*afwGeom.degrees), afwGeom.Point2D(0.0, 0.0), 1.0e-4, 0.0, 0.0, 1.0e-4)) return exp
def transposeContext(self, maskedImage, defects): """Context manager to potentially transpose an image This applies the ``transpose`` configuration setting. Transposing the image allows us to interpolate along columns instead of rows, which is useful when the saturation trails are typically oriented along rows on the warped/coadded images, instead of along columns as they typically are in raw CCD images. Parameters ---------- maskedImage : `lsst.afw.image.MaskedImage` Image on which to perform interpolation. defects : `lsst.meas.algorithms.Defects` List of defects to interpolate over. Yields ------ useImage : `lsst.afw.image.MaskedImage` Image to use for interpolation; it may have been transposed. useDefects : `lsst.meas.algorithms.Defects` List of defects to use for interpolation; they may have been transposed. """ def transposeImage(image): """Transpose an image""" transposed = image.array.T.copy( ) # Copy to force row-major; required for ndarray+pybind return image.Factory(transposed, False, lsst.geom.Point2I(*reversed(image.getXY0()))) useImage = maskedImage useDefects = defects if self.config.transpose: useImage = afwImage.makeMaskedImage( transposeImage(maskedImage.image), transposeImage(maskedImage.mask), transposeImage(maskedImage.variance)) useDefects = defects.transpose() yield useImage, useDefects if self.config.transpose: maskedImage.image.array = useImage.image.array.T maskedImage.mask.array = useImage.mask.array.T maskedImage.variance.array = useImage.variance.array.T
def std_raw(self, image, dataId): """Standardize a raw dataset by converting it to an Exposure instead of an Image""" if isinstance(image, afwImage.DecoratedImageU) or isinstance(image, afwImage.DecoratedImageI) or \ isinstance(image, afwImage.DecoratedImageF) or isinstance(image, afwImage.DecoratedImageD): exposure = afwImage.makeExposure(afwImage.makeMaskedImage(image.getImage())) else: exposure = image md = image.getMetadata() if True: wcs = afwImage.makeWcs(md, True) # The CASU WCSes use ZPN; our stuff wants TAN # This won't work near the pole, but should be decent away from it. box = afwGeom.BoxD(image.getImage().getBBox()) refPix = box.getCenter() refSky = wcs.pixelToSky(refPix) refSkyOffsetX = wcs.pixelToSky(refPix + afwGeom.Extent2D(1.0, 0.0)) refSkyOffsetY = wcs.pixelToSky(refPix + afwGeom.Extent2D(0.0, 1.0)) xPixelScale = refSky.angularSeparation(refSkyOffsetX).asDegrees() yPixelScale = refSky.angularSeparation(refSkyOffsetY).asDegrees() xPixelScale = yPixelScale = wcs.pixelScale().asDegrees() else: refPix = afwGeom.Point2D(md.get("CRPIX1"), md.get("CRPIX2")) refSky = afwCoord.IcrsCoord(md.get("CRVAL1")*afwGeom.degrees, md.get("CRVAL2")*afwGeom.degrees) xPixelScale = yPixelScale = (0.2*afwGeom.arcseconds).asDegrees() # import pdb;pdb.set_trace() exposure.setMetadata(md) #newWcs = afwImage.makeWcs(refSky, refPix, xPixelScale, 0.0, 0.0, yPixelScale) #wcs = afwImage.makeWcs(md, True) #exposure.setWcs(newWcs) exposure.setWcs(wcs) """ Set up exposure time """ pathId = self._transformId(dataId) expTime = pathId['expTime'] exposure.getCalib().setExptime(expTime) return self._standardizeExposure(self.exposures['raw'], exposure, dataId, trimmed=False)
def readFits(fileName, hdu=0, flags=0): """Read a our list of Backgrounds from a file @param fileName FITS file to read @param hdu First Header/Data Unit to attempt to read from @param flags Flags to control details of reading; currently unused, but present for consistency with afw.table.BaseCatalog.readFits. See also getImage() """ if not isinstance(fileName, MemFileManager) and not os.path.exists(fileName): raise RuntimeError("File not found: %s" % fileName) self = BackgroundList() while True: hdu += 1 md = dafBase.PropertyList() try: img = afwImage.ImageF(fileName, hdu, md); hdu += 1 except FitsError as e: break msk = afwImage.MaskU( fileName, hdu); hdu += 1 var = afwImage.ImageF(fileName, hdu) statsImage = afwImage.makeMaskedImage(img, msk, var) x0 = md.get("BKGD_X0") y0 = md.get("BKGD_Y0") width = md.get("BKGD_WIDTH") height = md.get("BKGD_HEIGHT") imageBBox = afwGeom.BoxI(afwGeom.PointI(x0, y0), afwGeom.ExtentI(width, height)) interpStyle = md.get("INTERPSTYLE") undersampleStyle = md.get("UNDERSAMPLESTYLE") bkgd = afwMath.BackgroundMI(imageBBox, statsImage) self.append((bkgd, interpStyle, undersampleStyle,)) return self
def transposeContext(self, maskedImage, defects): """Context manager to potentially transpose an image This applies the ``transpose`` configuration setting. Transposing the image allows us to interpolate along columns instead of rows, which is useful when the saturation trails are typically oriented along rows on the warped/coadded images, instead of along columns as they typically are in raw CCD images. Parameters ---------- maskedImage : `lsst.afw.image.MaskedImage` Image on which to perform interpolation. defects : `lsst.meas.algorithms.Defects` List of defects to interpolate over. Yields ------ useImage : `lsst.afw.image.MaskedImage` Image to use for interpolation; it may have been transposed. useDefects : `lsst.meas.algorithms.Defects` List of defects to use for interpolation; they may have been transposed. """ def transposeImage(image): """Transpose an image""" transposed = image.array.T.copy() # Copy to force row-major; required for ndarray+pybind return image.Factory(transposed, False, lsst.geom.Point2I(*reversed(image.getXY0()))) useImage = maskedImage useDefects = defects if self.config.transpose: useImage = afwImage.makeMaskedImage(transposeImage(maskedImage.image), transposeImage(maskedImage.mask), transposeImage(maskedImage.variance)) useDefects = defects.transpose() yield useImage, useDefects if self.config.transpose: maskedImage.image.array = useImage.image.array.T maskedImage.mask.array = useImage.mask.array.T maskedImage.variance.array = useImage.variance.array.T
def exposureFromImage(image): """Generate an exposure from a DecoratedImage or similar @param[in] image Image of interest @return (lsst.afw.image.Exposure) Exposure containing input image """ if isinstance(image, afwImage.DecoratedImageU) or isinstance(image, afwImage.DecoratedImageI) or \ isinstance(image, afwImage.DecoratedImageF) or isinstance(image, afwImage.DecoratedImageD): exposure = afwImage.makeExposure(afwImage.makeMaskedImage(image.getImage())) else: exposure = image md = image.getMetadata() exposure.setMetadata(md) wcs = afwImage.makeWcs(md) if wcs is not None: exposure.setWcs(wcs) wcsMetadata = wcs.getFitsMetadata() for kw in wcsMetadata.paramNames(): md.remove(kw) return exposure
def computeIntensity(imageR, imageG=None, imageB=None): """Return a naive total intensity from the red, blue, and green intensities Parameters ---------- imageR : `lsst.afw.image.MaskedImage`, `lsst.afw.image.Image`, or `numpy.ndarray`, (Nx, Ny) intensity of image that'll be mapped to red; or intensity if imageG and imageB are None imageG : `lsst.afw.image.MaskedImage`, `lsst.afw.image.Image`, or `numpy.ndarray`, (Nx, Ny) intensity of image that'll be mapped to green; or None imageB : `lsst.afw.image.MaskedImage`, `lsst.afw.image.Image`, or `numpy.ndarray`, (Nx, Ny) intensity of image that'll be mapped to blue; or None Returns ------- image : type of ``imageR``, ``imageG``, and `imageB`` """ if imageG is None or imageB is None: assert imageG is None and imageB is None, \ "Please specify either a single image or red, green, and blue images" return imageR imageRGB = [imageR, imageG, imageB] for i, c in enumerate(imageRGB): if hasattr(c, "getImage"): c = imageRGB[i] = c.getImage() if hasattr(c, "getArray"): imageRGB[i] = c.getArray() intensity = (imageRGB[0] + imageRGB[1] + imageRGB[2])/float(3) # # Repack into whatever type was passed to us # Image = afwImage.ImageU if intensity.dtype == 'uint16' else afwImage.ImageF if hasattr(imageR, "getImage"): # a maskedImage intensity = afwImage.makeMaskedImage(Image(intensity)) elif hasattr(imageR, "getArray"): intensity = Image(intensity) return intensity
def makeExposure(self, im, mask=None, variance=None): """Method for constructing an exposure object from an image and the information contained in this class to construct the Detector and Calib objects. @param[in] im Image used to construct the exposure @param[in] mask Optional mask plane as a <askU @param[in] variance Optional variance plance as an image of the same type as im @param[out] Exposure object """ if mask is None: mask = afwImage.MaskU(im.getDimensions()) if variance is None: variance = im mi = afwImage.makeMaskedImage(im, mask, variance) detector = self.buildDetector() wcs = afwImage.makeWcs(self.detectorMetadata) calib = self.makeCalib() exp = afwImage.makeExposure(mi, wcs) exp.setCalib(calib) exp.setDetector(detector) return exp
def testMaskedImageFromImage(self): w, h = 10, 20 dims = lsst.geom.Extent2I(w, h) im, mask, var = afwImage.ImageF(dims), \ afwImage.Mask(dims), \ afwImage.ImageF(dims) im.set(666) maskedImage = afwImage.MaskedImageF(im, mask, var) maskedImage = afwImage.makeMaskedImage(im, mask, var) maskedImage = afwImage.MaskedImageF(im) self.assertEqual(im.getDimensions(), maskedImage.image.getDimensions()) self.assertEqual(im.getDimensions(), maskedImage.mask.getDimensions()) self.assertEqual(im.getDimensions(), maskedImage.variance.getDimensions()) self.assertEqual(maskedImage[0, 0, afwImage.LOCAL], (im[0, 0, afwImage.LOCAL], 0x0, 0.0))
def run(self, sensorRefList, *args, **kwargs): """Mask vignetted pixels after combining This returns an Exposure instead of an Image, but upstream shouldn't care, as it just dumps it out via the Butler. """ combined = super(HscFlatCombineTask, self).run(sensorRefList, *args, **kwargs) mi = afwImage.makeMaskedImage(combined.getImage()) mi.getMask().set(0) # Retrieve the detector # XXX It's unfortunate that we have to read an entire image to get the detector, but there's no # public API in the butler to get the same. image = sensorRefList[0].get("postISRCCD") detector = image.getDetector() del image self.maskVignetting(mi.getMask(), detector) self.maskBadAmps(mi.getMask(), detector) return afwImage.makeExposure(mi)
def test1295(self): """A test case for #1295 (failure to interpolate over groups of defects""" im = afwImage.ImageF(afwGeom.ExtentI(100, 100)) mi = afwImage.makeMaskedImage(im) mi.set(100) flat = afwImage.ImageF(im.getDimensions()) flat.set(1) for i in range(100): for j in range(100): if i == 50 or i == 55 or i == 58: flat.set(i,j,0) if i < 60 and i > 50 and j > 50: flat.set(i,j,0) mi /= flat if display: ds9.mtv(mi, frame=0, title="Raw") defectList = algorithms.DefectListT() bbox = afwGeom.BoxI(afwGeom.PointI(50,0), afwGeom.ExtentI(1,100)) defectList.append(algorithms.Defect(bbox)) bbox = afwGeom.BoxI(afwGeom.PointI(55,0), afwGeom.ExtentI(1,100)) defectList.append(algorithms.Defect(bbox)) bbox = afwGeom.BoxI(afwGeom.PointI(58,0), afwGeom.ExtentI(1,100)) defectList.append(algorithms.Defect(bbox)) bbox = afwGeom.BoxI(afwGeom.PointI(51,51), afwGeom.ExtentI(9,49)) defectList.append(algorithms.Defect(bbox)) psf = algorithms.DoubleGaussianPsf(15, 15, 1./(2*math.sqrt(2*math.log(2)))) algorithms.interpolateOverDefects(mi, psf, defectList, 50.) if display: ds9.mtv(mi, frame=1, title="Interpolated") self.assertTrue(numpy.isfinite(mi.getImage().get(56, 51)))