def rotated(self, exp): nQuarter = exp.getDetector().getOrientation().getNQuarter() exp.setMaskedImage(afwMath.rotateImageBy90(exp.getMaskedImage(), nQuarter)) try: yield exp finally: exp.setMaskedImage(afwMath.rotateImageBy90(exp.getMaskedImage(), 4 - nQuarter))
def rotated(self, exp): nQuarter = exp.getDetector().getOrientation().getNQuarter() exp.setMaskedImage( afwMath.rotateImageBy90(exp.getMaskedImage(), 4 - nQuarter)) try: yield exp finally: exp.setMaskedImage( afwMath.rotateImageBy90(exp.getMaskedImage(), nQuarter))
def makeImageFromCamera(camera, detectorNameList=None, background=numpy.nan, bufferSize=10, imageSource=FakeImageDataSource(), imageFactory=afwImage.ImageU, binSize=1): """!Make an Image of a Camera @param[in] camera Camera object to use to make the image @param[in] detectorNameList List of detector names to use in building the image. Use all Detectors if None. @param[in] background Value to use where there is no Detector @param[in] bufferSize Size of border in binned pixels to make around the camera image @param[in] imageSource Source to get ccd images. Must have a getCcdImage method @param[in] imageFactory Type of image to build @param[in] binSize bin factor @return an image of the camera """ if detectorNameList is None: ccdList = camera else: ccdList = [camera[name] for name in detectorNameList] if detectorNameList is None: camBbox = camera.getFpBBox() else: camBbox = afwGeom.Box2D() for detName in detectorNameList: for corner in camera[detName].getCorners(FOCAL_PLANE): camBbox.include(corner) pixelSize_o = camera[next(camera.getNameIter())].getPixelSize() camBbox = getCameraImageBBox(camBbox, pixelSize_o, bufferSize * binSize) origin = camBbox.getMin() camIm = imageFactory( int(math.ceil(camBbox.getDimensions().getX() / binSize)), int(math.ceil(camBbox.getDimensions().getY() / binSize))) camIm[:] = imageSource.background assert imageSource.isTrimmed, "isTrimmed is False isn't supported by getCcdInCamBBoxList" boxList = getCcdInCamBBoxList(ccdList, binSize, pixelSize_o, origin) for det, bbox in zip(ccdList, boxList): im = imageSource.getCcdImage(det, imageFactory, binSize)[0] nQuarter = det.getOrientation().getNQuarter() im = afwMath.rotateImageBy90(im, nQuarter) imView = camIm.Factory(camIm, bbox, afwImage.LOCAL) import lsst.pex.exceptions as pexExceptions try: imView[:] = im except pexExceptions.LengthError: print( "Unable to fit image for detector \"%s\" into image of camera" % (det.getName())) return camIm
def showCcd(ccd, imageSource=FakeImageDataSource(), frame=None, overlay=True, imageFactory=afwImage.ImageU, binSize=1, inCameraCoords=False): """!Show a CCD on ds9 @param[in] ccd Detector to use in display @param[in] imageSource Source for producing images to display. Must have a getCcdImage method. @param[in] frame ds9 frame to use, defaults to frame zero @param[in] overlay Show amp bounding boxes on the displayed image? @param[in] imageFactory The image factory to use in generating the images. @param[in] binSize Binning factor @param[in] inCameraCoords Show the Detector in camera coordinates? """ ccdOrigin = afwGeom.Point2I(0,0) nQuarter = 0 ccdImage = imageSource.getCcdImage(ccd, imageFactory=imageFactory, binSize=binSize) ccdBbox = ccdImage.getBBox() if ccdBbox.getDimensions() == ccd.getBBox().getDimensions(): isTrimmed = True else: isTrimmed = False if inCameraCoords: nQuarter = ccd.getOrientation().getNQuarter() ccdImage = afwMath.rotateImageBy90(ccdImage, nQuarter) title = ccd.getName() if isTrimmed: title += "(trimmed)" ds9.mtv(ccdImage, frame=frame, title=title) if overlay: overlayCcdBoxes(ccd, ccdBbox, nQuarter, isTrimmed, ccdOrigin, frame, binSize)
def testRotate(self): """Test that we end up with the correct image after rotating by 90 degrees""" for nQuarter, x, y in [(0, 0, 0), (1, 9, 0), (2, 19, 9), (3, 0, 19)]: outImage = afwMath.rotateImageBy90(self.inImage, nQuarter) if display: ds9.mtv(outImage, frame=nQuarter, title="out %d" % nQuarter) self.assertEqual(self.inImage.get(0, 0), outImage.get(x, y))
def _prepareImage(self, ccd, im, binSize, allowRotate=True): if binSize > 1: im = afwMath.binImage(im, binSize) if allowRotate: im = afwMath.rotateImageBy90(im, ccd.getOrientation().getNQuarter()) return im
def testRotate(self): """Test that we end up with the correct image after rotating by 90 degrees. """ for nQuarter, x, y in [(0, 0, 0), (1, 9, 0), (2, 19, 9), (3, 0, 19)]: outImage = afwMath.rotateImageBy90(self.inImage, nQuarter) if display: afwDisplay.Display(frame=nQuarter).mtv(outImage, title=f"out {nQuarter}") self.assertEqual(self.inImage[0, 0, afwImage.LOCAL], outImage[x, y, afwImage.LOCAL])
def eimageCallback(im, ccd=None, imageSource=None): """A callback to handle eimages""" im = im.convertF() nQuarter = 1 im = rotateImageBy90(im, nQuarter) im = flipImage(im, True, False) return im
def showCcd(ccd, imageSource=FakeImageDataSource(), display=None, overlay=True, imageFactory=afwImage.ImageF, binSize=1, inCameraCoords=False): """Show a CCD on display. Parameters ---------- ccd : `lsst.afw.cameraGeom.Detector` Detector to use in display. imageSource : `FakeImageDataSource` or `None` Source to get ccd images. Must have a ``getCcdImage()`` method. display : `lsst.afw.display.Display` image display to use. overlay : `bool` Show amp bounding boxes on the displayed image? imageFactory : callable like `lsst.afw.image.Image` The image factory to use in generating the images. binSize : `int` Bin the image by this factor in both dimensions. inCameraCoords : `bool` Show the Detector in camera coordinates? """ display = _getDisplayFromDisplayOrFrame(display) ccdOrigin = lsst.geom.Point2I(0, 0) nQuarter = 0 ccdImage, ccd = imageSource.getCcdImage(ccd, imageFactory=imageFactory, binSize=binSize) ccdBbox = ccdImage.getBBox() if ccdBbox.getDimensions() == ccd.getBBox().getDimensions(): isTrimmed = True else: isTrimmed = False if inCameraCoords: nQuarter = ccd.getOrientation().getNQuarter() ccdImage = afwMath.rotateImageBy90(ccdImage, nQuarter) title = ccd.getName() if isTrimmed: title += "(trimmed)" if display: display.mtv(ccdImage, title=title) if overlay: overlayCcdBoxes(ccd, ccdBbox, nQuarter, isTrimmed, ccdOrigin, display, binSize) return ccdImage
def showCcd(ccd, imageSource=FakeImageDataSource(), display=None, frame=None, overlay=True, imageFactory=afwImage.ImageF, binSize=1, inCameraCoords=False): """Show a CCD on display. Parameters ---------- ccd : `lsst.afw.cameraGeom.Detector` Detector to use in display. imageSource : `FakeImageDataSource` or `None` Source to get ccd images. Must have a ``getCcdImage()`` method. display : `lsst.afw.display.Display` image display to use. frame : `None` frame ID on which to display. **Deprecated** in v12. overlay : `bool` Show amp bounding boxes on the displayed image? imageFactory : callable like `lsst.afw.image.Image` The image factory to use in generating the images. binSize : `int` Bin the image by this factor in both dimensions. inCameraCoords : `bool` Show the Detector in camera coordinates? """ if frame is not None: warnings.warn("The frame kwarg is deprecated; use the `lsst.afw.display` system instead.", DeprecationWarning) display = _getDisplayFromDisplayOrFrame(display, frame) ccdOrigin = lsst.geom.Point2I(0, 0) nQuarter = 0 ccdImage, ccd = imageSource.getCcdImage( ccd, imageFactory=imageFactory, binSize=binSize) ccdBbox = ccdImage.getBBox() if ccdBbox.getDimensions() == ccd.getBBox().getDimensions(): isTrimmed = True else: isTrimmed = False if inCameraCoords: nQuarter = ccd.getOrientation().getNQuarter() ccdImage = afwMath.rotateImageBy90(ccdImage, nQuarter) title = ccd.getName() if isTrimmed: title += "(trimmed)" if display: display.mtv(ccdImage, title=title) if overlay: overlayCcdBoxes(ccd, ccdBbox, nQuarter, isTrimmed, ccdOrigin, display, binSize) return ccdImage
def getDonut(icRecord, icExp, donutConfig): """Return numpy array containing donut cutout. """ nquarter = icExp.getDetector().getOrientation().getNQuarter() if donutConfig.flip: nquarter += 2 maskedImage = getCutout(icRecord.getX(), icRecord.getY(), icExp, donutConfig.stampSize) maskedImage = afwMath.rotateImageBy90(maskedImage, nquarter) return maskedImage.getImage().getArray()
def fitOneRecord(self, record, icExp, camera, nquarter=None, pupilFactory=None, wavelength=None, detector=None, pixelScale=None, alpha=1.0, oversampling=1.0, padFactor=1.0): if pixelScale is None: pixelScale = icExp.getWcs().pixelScale() if detector is None: detector = icExp.getDetector() if wavelength is None: wavelength = self.getWavelength(icExp) if pupilFactory is None: visitInfo = icExp.getInfo().getVisitInfo() pupilFactory = self.getPupilFactory(camera, wavelength * alpha, pixelScale, visitInfo, oversampling, padFactor) if nquarter is None: nquarter = detector.getOrientation().getNQuarter() imX = record.getX() imY = record.getY() point = afwGeom.Point2D(record.getX(), record.getY()) if self.config.doJacobian: jacobian = _getJacobian(detector, point) else: jacobian = np.eye(2) # Need to apply quarter rotations transformation to Jacobian. th = np.pi / 2 * nquarter sth, cth = np.sin(th), np.cos(th) rot = np.array([[cth, sth], [-sth, cth]]) jacobian = np.dot(rot.T, np.dot(jacobian, rot)) fpX = record['base_FPPosition_x'] fpY = record['base_FPPosition_y'] self.log.info("Donut is at {}, {}".format(fpX, fpY)) subMaskedImage = afwMath.rotateImageBy90( getCutout(imX, imY, icExp, self.config.stampSize), nquarter) pupil = pupilFactory.getPupil(afwGeom.Point2D(fpX, fpY)) return self.fitOneDonut(subMaskedImage, wavelength, pupil, camera, pixelScale, jacobian, alpha=alpha)
def testRotate(self): """Test that we end up with the correct image after rotating by 90 degrees. """ for nQuarter, x, y in [(0, 0, 0), (1, 9, 0), (2, 19, 9), (3, 0, 19)]: outImage = afwMath.rotateImageBy90(self.inImage, nQuarter) if display: afwDisplay.Display(frame=nQuarter).mtv(outImage, title="out %d" % nQuarter) self.assertEqual(self.inImage[0, 0, afwImage.LOCAL], outImage[x, y, afwImage.LOCAL])
def makeImageFromCamera(camera, detectorNameList=None, background=numpy.nan, bufferSize=10, imageSource=FakeImageDataSource(), imageFactory=afwImage.ImageU, binSize=1): """!Make an Image of a Camera @param[in] camera Camera object to use to make the image @param[in] detectorNameList List of detector names to use in building the image. Use all Detectors if None. @param[in] background Value to use where there is no Detector @param[in] bufferSize Size of border in binned pixels to make around the camera image @param[in] imageSource Source to get ccd images. Must have a getCcdImage method @param[in] imageFactory Type of image to build @param[in] binSize bin factor @return an image of the camera """ if detectorNameList is None: ccdList = camera else: ccdList = [camera[name] for name in detectorNameList] if detectorNameList is None: camBbox = camera.getFpBBox() else: camBbox = afwGeom.Box2D() for detName in detectorNameList: for corner in camera[detName].getCorners(FOCAL_PLANE): camBbox.include(corner) pixelSize_o = camera[camera.getNameIter().next()].getPixelSize() camBbox = getCameraImageBBox(camBbox, pixelSize_o, bufferSize*binSize) origin = camBbox.getMin() camIm = imageFactory(int(math.ceil(camBbox.getDimensions().getX()/binSize)), int(math.ceil(camBbox.getDimensions().getY()/binSize))) camIm[:] = imageSource.background assert imageSource.isTrimmed, "isTrimmed is False isn't supported by getCcdInCamBBoxList" boxList = getCcdInCamBBoxList(ccdList, binSize, pixelSize_o, origin) for det, bbox in itertools.izip(ccdList, boxList): im = imageSource.getCcdImage(det, imageFactory, binSize) nQuarter = det.getOrientation().getNQuarter() im = afwMath.rotateImageBy90(im, nQuarter) imView = camIm.Factory(camIm, bbox, afwImage.LOCAL) try: imView[:] = im except Exception: pass return camIm
def run(self, expRef, butler): """Make summary plots of full focalplane images. """ sbi = SimButlerImage(butler, type=expRef.butlerSubset.datasetType, visit=expRef.dataId['visit']) # Get the per ccd images def parse_name_to_dataId(name_str): raft, sensor = name_str.split() return {'raft': raft[-3:], 'sensor': sensor[-3:]} for ccd in butler.get('camera'): data_id = parse_name_to_dataId(ccd.getName()) data_id.update(expRef.dataId) try: binned_im = sbi.getCcdImage(ccd, binSize=self.config.sensorBinSize, as_masked_image=True)[0] binned_im = rotateImageBy90(binned_im, ccd.getOrientation().getNQuarter()) if self.config.putFullSensors: butler.put(binned_im, 'binned_sensor_fits', **data_id) except (TypeError, RuntimeError): # butler couldn't put the image or there was no image to put continue (x, y) = binned_im.getDimensions() boxes = { 'A': afwGeom.Box2I(afwGeom.PointI(0, y / 2), afwGeom.ExtentI(x, y / 2)), 'B': afwGeom.Box2I(afwGeom.PointI(0, 0), afwGeom.ExtentI(x, y / 2)) } for half in ('A', 'B'): box = boxes[half] butler.put(afwImage.MaskedImageF(binned_im, box), 'binned_sensor_fits_halves', half=half, **data_id) im = cgu.showCamera(butler.get('camera'), imageSource=sbi, binSize=self.config.binSize) expRef.put(im, 'focalplane_summary_fits') im = flipImage(im, False, True) zmap = ZScaleMapping(im, contrast=self.config.contrast) rgb = zmap.makeRgbImage(im, im, im) file_name = expRef.get('focalplane_summary_png_filename') writeRGB(file_name[0], rgb)
def makeImageFromCamera(camera, detectorNameList=None, background=numpy.nan, bufferSize=10, imageSource=FakeImageDataSource(), imageFactory=afwImage.ImageU, binSize=1): """!Make an Image of a Camera @param[in] camera Camera object to use to make the image @param[in] detectorNameList List of detector names to use in building the image. Use all Detectors if None. @param[in] background Value to use where there is no Detector @param[in] bufferSize Size of border in binned pixels to make around the camera image @param[in] imageSource Source to get ccd images. Must have a getCcdImage method @param[in] imageFactory Type of image to build @param[in] binSize bin factor @return an image of the camera """ if detectorNameList is None: ccdList = camera else: ccdList = [camera[name] for name in detectorNameList] if detectorNameList is None: camBbox = camera.getFpBBox() else: camBbox = afwGeom.Box2D() for detName in detectorNameList: for corner in camera[detName].getCorners(FOCAL_PLANE): camBbox.include(corner) pixelSize_o = camera[camera.getNameIter().next()].getPixelSize() camBbox = getCameraImageBBox(camBbox, pixelSize_o, bufferSize * binSize) origin = camBbox.getMin() camIm = imageFactory( int(math.ceil(camBbox.getDimensions().getX() / binSize)), int(math.ceil(camBbox.getDimensions().getY() / binSize))) boxList = getCcdInCamBBoxList(ccdList, binSize, pixelSize_o, origin) for det, bbox in itertools.izip(ccdList, boxList): im = imageSource.getCcdImage(det, imageFactory, binSize) nQuarter = det.getOrientation().getNQuarter() im = afwMath.rotateImageBy90(im, nQuarter) imView = camIm.Factory(camIm, bbox, afwImage.LOCAL) imView <<= im return camIm
def showCcd(ccd, imageSource=FakeImageDataSource(), display=None, frame=None, overlay=True, imageFactory=afwImage.ImageF, binSize=1, inCameraCoords=False): """!Show a CCD on display @param[in] ccd Detector to use in display @param[in] imageSource Source for producing images to display. Must have a getCcdImage method. @param[in] display image display to use @param[in] frame frame ID on which to display @param[in] overlay Show amp bounding boxes on the displayed image? @param[in] imageFactory The image factory to use in generating the images. @param[in] binSize Binning factor @param[in] inCameraCoords Show the Detector in camera coordinates? """ display = _getDisplayFromDisplayOrFrame(display, frame) ccdOrigin = afwGeom.Point2I(0, 0) nQuarter = 0 ccdImage = imageSource.getCcdImage(ccd, imageFactory=imageFactory, binSize=binSize) ccdBbox = ccdImage.getBBox() if ccdBbox.getDimensions() == ccd.getBBox().getDimensions(): isTrimmed = True else: isTrimmed = False if inCameraCoords: nQuarter = ccd.getOrientation().getNQuarter() ccdImage = afwMath.rotateImageBy90(ccdImage, nQuarter) title = ccd.getName() if isTrimmed: title += "(trimmed)" if display: display.mtv(ccdImage, title=title) if overlay: overlayCcdBoxes(ccd, ccdBbox, nQuarter, isTrimmed, ccdOrigin, display, binSize) return ccdImage
def getCcdImage(self, detector, imageFactory, binSize): """Provide image of CCD to makeImageFromCamera Parameters ---------- detector : `int` Detector ID to get image data for. imageFactory : `lsst.afw.image.Image` Type of image to construct. binSize : `int` Binsize to use to recompute dimensions. Returns ------- image : `lsst.afw.image.Image` Appropriately rotated, binned, and transformed image to be mosaicked. detector : `lsst.afw.cameraGeom.Detector` Camera detector that the returned image data belongs to. """ detId = detector.getId() if detId not in self.exposures: dims = detector.getBBox().getDimensions() / binSize image = imageFactory(*[int(xx) for xx in dims]) image.set(self.background) else: image = self.exposures[detector.getId()] if hasattr(image, "getMaskedImage"): image = image.getMaskedImage() if hasattr(image, "getMask"): mask = image.getMask() isBad = mask.getArray() & mask.getPlaneBitMask("NO_DATA") > 0 image = image.clone() image.getImage().getArray()[isBad] = self.background if hasattr(image, "getImage"): image = image.getImage() # afwMath.rotateImageBy90 checks NQuarter values, # so we don't need to here. image = afwMath.rotateImageBy90( image, detector.getOrientation().getNQuarter()) return image, detector
def applyMosaicResultsExposure(dataRef, calexp=None): """Update an Exposure with the Wcs, Calib, and flux scaling from meas_mosaic. If None, the calexp will be loaded from the dataRef. Otherwise it is updated in-place. This assumes that the mosaic solution exists; an exception will be raised in the event that it does not. """ if calexp is None: calexp = dataRef.get("calexp", immediate=True) nQuarter = calexp.getDetector().getOrientation().getNQuarter() dims = calexp.getDimensions() hscRun = mosaicUtils.checkHscStack(calexp.getMetadata()) # Need the dimensions in coordinates used by meas_mosaic which defines 0,0 as the # lower-left hand corner on the sky if hscRun is None: if nQuarter % 2 != 0: width, height = calexp.getDimensions() dims = afwGeom.Extent2I(height, width) # return results in meas_mosaic coordinate system mosaic = getMosaicResults(dataRef, dims) # rotate wcs back to LSST coordinate system if nQuarter % 4 != 0 and hscRun is None: import lsst.meas.astrom as measAstrom mosaic.wcs = measAstrom.rotateWcsPixelsBy90(mosaic.wcs, 4 - nQuarter, dims) calexp.setWcs(mosaic.wcs) fluxMag0 = mosaic.calib.getInstFluxAtZeroMagnitude() calexp.setPhotoCalib( afwImage.makePhotoCalibFromCalibZeroPoint(fluxMag0, 0.0)) mi = calexp.getMaskedImage() # rotate photometric correction to LSST coordiantes if nQuarter % 4 != 0 and hscRun is None: mosaic.fcor = afwMath.rotateImageBy90(mosaic.fcor, 4 - nQuarter) mi *= mosaic.fcor return Struct(exposure=calexp, mosaic=mosaic)
def makeImageFromCcd(ccd, imageSource=SynthesizeCcdImage(), amp=None, isTrimmed=None, imageFactory=afwImage.ImageU, bin=1, natural=False): """Make an Image of a Ccd (or just a single amp) If natural is True, return the CCD image without worrying about whether it's rotated when placed into the camera """ if isTrimmed is None: isTrimmed = ccd.isTrimmed() imageSource.setTrimmed(isTrimmed) if amp: ampImage = imageFactory(amp.getAllPixels(isTrimmed).getDimensions()) ampImage <<= imageSource.getImage(ccd, amp, imageFactory=imageFactory) if bin > 1: ampImage = afwMath.binImage(ampImage, bin) return ampImage # # Start by building the image in "Natural" (non-rotated) orientation # (unless it's 'raw', in which case it's just easier to prepareAmpData) # if imageSource.isRaw: ccdImage = imageFactory(ccd.getAllPixelsNoRotation(isTrimmed)) for a in ccd: im = ccdImage.Factory(ccdImage, a.getAllPixels(isTrimmed), afwImage.LOCAL) im <<= a.prepareAmpData(imageSource.getImage(ccd, a, imageFactory=imageFactory)) else: ccdImage = imageSource.getImage(ccd, imageFactory=imageFactory) if bin > 1: ccdImage = afwMath.binImage(ccdImage, bin) # # Now rotate to the as-installed orientation # if not natural and not imageSource.isRaw: ccdImage = afwMath.rotateImageBy90(ccdImage, ccd.getOrientation().getNQuarter()) return ccdImage
def applyMosaicResultsExposure(dataRef, calexp=None): """Update an Exposure with the Wcs, Calib, and flux scaling from meas_mosaic. If None, the calexp will be loaded from the dataRef. Otherwise it is updated in-place. This assumes that the mosaic solution exists; an exception will be raised in the event that it does not. """ if calexp is None: calexp = dataRef.get("calexp", immediate=True) nQuarter = calexp.getDetector().getOrientation().getNQuarter() dims = calexp.getDimensions() hscRun = mosaicUtils.checkHscStack(calexp.getMetadata()) # Need the dimensions in coordinates used by meas_mosaic which defines 0,0 as the # lower-left hand corner on the sky if hscRun is None: if nQuarter%2 != 0: width, height = calexp.getDimensions() dims = afwGeom.Extent2I(height, width) # return results in meas_mosaic coordinate system mosaic = getMosaicResults(dataRef, dims) # rotate wcs back to LSST coordinate system if nQuarter%4 != 0 and hscRun is None: import lsst.meas.astrom as measAstrom mosaic.wcs = measAstrom.rotateWcsPixelsBy90(mosaic.wcs, 4 - nQuarter, dims) calexp.setWcs(mosaic.wcs) fluxMag0 = mosaic.calib.getInstFluxAtZeroMagnitude() calexp.setPhotoCalib(afwImage.makePhotoCalibFromCalibZeroPoint(fluxMag0, 0.0)) mi = calexp.getMaskedImage() # rotate photometric correction to LSST coordiantes if nQuarter%4 != 0 and hscRun is None: mosaic.fcor = afwMath.rotateImageBy90(mosaic.fcor, 4 - nQuarter) mi *= mosaic.fcor return Struct(exposure=calexp, mosaic=mosaic)
def getCcdImage(self, det, imageFactory, binSize): """Return a CCD image for the detector and the (possibly updated) Detector. Parameters ---------- det : `lsst.afw.cameraGeom.Detector` Detector to use for making the image. imageFactory : callable like `lsst.afw.image.Image` Image constructor for making the image. binSize : `int` Bin the image by this factor in both dimensions. Returns ------- ccdImage : `lsst.afw.image.Image` The constructed image. """ ccdImage = makeImageFromCcd(det, isTrimmed=self.isTrimmed, showAmpGain=self.showAmpGain, imageFactory=imageFactory, binSize=binSize) return afwMath.rotateImageBy90(ccdImage, det.getOrientation().getNQuarter()), det
def getCcdImage(self, ccd, imageFactory=afwImage.ImageF, binSize=1): bbox = ccd.getBBox() try: ffp = self.ffp[ccd.getId()] wcs = self.wcs[ccd.getId()] except KeyError: result = imageFactory(bbox) return afwMath.binImage(result, binSize), ccd nQuarter = ccd.getOrientation().getNQuarter() # Rotate WCS from persisted LSST coords to meas_mosaic coords if nQuarter % 4 != 0: # Have to put this import here due to circular dependencies import lsst.meas.astrom as measAstrom wcs = measAstrom.rotateWcsPixelsBy90(wcs, nQuarter, bbox.getDimensions()) if nQuarter % 2: width, height = bbox.getHeight(), bbox.getWidth() else: width, height = bbox.getWidth(), bbox.getHeight() if self.fcor: result = getFCorImg(ffp, width, height) if self.jacobian: result *= getJImg(wcs, width, height) elif self.jacobian: result = getJImg(wcs, width, height) else: result = imageFactory(bbox) return afwMath.binImage(result, binSize), ccd # Rotate images to LSST coords if nQuarter % 4 != 0: result = afwMath.rotateImageBy90(result, 4 - nQuarter) result.setXY0(bbox.getMin()) assert bbox == result.getBBox(), "%s != %s" % (bbox, result.getBBox()) assert type(result) == imageFactory return afwMath.binImage(result, binSize), ccd
def getCcdImage(self, ccd, imageFactory=afwImage.ImageF, binSize=1): bbox = ccd.getBBox() try: ffp = self.ffp[ccd.getId()] wcs = self.wcs[ccd.getId()] except KeyError: result = imageFactory(bbox) return afwMath.binImage(result, binSize), ccd nQuarter = ccd.getOrientation().getNQuarter() # Rotate WCS from persisted LSST coords to meas_mosaic coords if nQuarter%4 != 0: # Have to put this import here due to circular dependencies import lsst.meas.astrom as measAstrom wcs = measAstrom.rotateWcsPixelsBy90(wcs, nQuarter, bbox.getDimensions()) if nQuarter%2: width, height = bbox.getHeight(), bbox.getWidth() else: width, height = bbox.getWidth(), bbox.getHeight() if self.fcor: result = getFCorImg(ffp, width, height) if self.jacobian: result *= getJImg(wcs, width, height) elif self.jacobian: result = getJImg(wcs, width, height) else: result = imageFactory(bbox) return afwMath.binImage(result, binSize), ccd # Rotate images to LSST coords if nQuarter%4 != 0: result = afwMath.rotateImageBy90(result, 4 - nQuarter) result.setXY0(bbox.getMin()) assert bbox == result.getBBox(), "%s != %s" % (bbox, result.getBBox()) assert type(result) == imageFactory return afwMath.binImage(result, binSize), ccd
def getCcdImage(self, detector, imageFactory, binSize): """Provide image of CCD to makeImageFromCamera""" detId = detector.getId() if detId not in self.exposures: dims = detector.getBBox().getDimensions() / binSize image = imageFactory(*[int(xx) for xx in dims]) image.set(self.background) else: image = self.exposures[detector.getId()] if hasattr(image, "getMaskedImage"): image = image.getMaskedImage() if hasattr(image, "getMask"): mask = image.getMask() isBad = mask.getArray() & mask.getPlaneBitMask("NO_DATA") > 0 image = image.clone() image.getImage().getArray()[isBad] = self.background if hasattr(image, "getImage"): image = image.getImage() image = afwMath.rotateImageBy90( image, detector.getOrientation().getNQuarter()) return image, detector
def trimCcd(ccd, ccdImage=""): """Trim a Ccd and maybe the image of the untrimmed Ccd""" if ccdImage == "": ccdImage = cameraGeomUtils.makeImageFromCcd(ccd, natural=True) if ccd.isTrimmed(): return ccdImage ccd.setTrimmed(True) if ccdImage is not None: trimmedImage = ccdImage.Factory(ccd.getAllPixelsNoRotation()) for a in ccd: data = ccdImage.Factory(ccdImage, a.getDataSec(False), afwImage.LOCAL) tdata = trimmedImage.Factory(trimmedImage, a.getDataSec(), afwImage.LOCAL) tdata <<= data else: trimmedImage = None if trimmedImage: trimmedImage = afwMath.rotateImageBy90(trimmedImage, ccd.getOrientation().getNQuarter()) return trimmedImage
def testRaw(self): """Test retrieval of raw image""" frame = 1 for ccdNum, rotated in zip(self.ccdList, self.rotated): butler = getButler(self.datadir) raw = butler.get("raw", visit=self.expId, ccd=ccdNum) ccd = raw.getDetector() print "Visit: ", self.expId print "width: ", raw.getWidth() print "height: ", raw.getHeight() ccdName = ccd.getId().getName() print "detector name: ", ccdName self.assertEqual(raw.getWidth(), self.untrimmedSize[0]) self.assertEqual(raw.getHeight(), self.untrimmedSize[1]) self.assertEqual(raw.getFilter().getFilterProperty().getName(), "g") self.assertEqual(ccd.getId().getName(), "hsc%03d" % ccdNum) # CCD size trimmed = ccd.getAllPixelsNoRotation(True).getDimensions() self.assertEqual(trimmed.getX(), self.trimmedSize[0]) self.assertEqual(trimmed.getY(), self.trimmedSize[1]) # Size in camera coordinates camera = ccd.getAllPixels(True).getDimensions() self.assertEqual(camera.getX(), self.trimmedSize[0] if not rotated else self.trimmedSize[1]) self.assertEqual(camera.getY(), self.trimmedSize[1] if not rotated else self.trimmedSize[0]) for i, amp in enumerate(ccd): amp = cameraGeom.cast_Amp(amp) print "amp: %s %i"%(amp.getId(), i) # Amplifier on CCD datasec = amp.getAllPixels(True) self.assertEqual(datasec.getWidth(), self.ampSize[0] if not rotated else self.ampSize[1]) self.assertEqual(datasec.getHeight(), self.ampSize[1] if not rotated else self.ampSize[0]) self.assertEqual(datasec.getMinX(), i*self.ampSize[0] if not rotated else 0) self.assertEqual(datasec.getMinY(), 0 if not rotated else i*self.ampSize[0]) # Amplifier on disk datasec = amp.getRawDataBBox() self.assertEqual(datasec.getWidth(), self.ampSize[0]) self.assertEqual(datasec.getHeight(), self.ampSize[1]) if display: ds9.mtv(raw, frame=frame, title="Raw %s" % ccdName) frame += 1 for amp in ccd: amp = cameraGeom.cast_Amp(amp) print ccd.getId(), amp.getId(), amp.getDataSec().toString(), \ amp.getBiasSec().toString(), amp.getElectronicParams().getGain() ccdIm = afwMath.rotateImageBy90(raw.getMaskedImage().getImage(), ccd.getOrientation().getNQuarter()) cameraGeomUtils.showCcd(ccd, ccdImage=ccdIm, frame=frame) frame += 1 if assemble: ccdIm = ca.assembleCcd([raw], ccd, reNorm=False, imageFactory=afwImage.ImageU) if display: cameraGeomUtils.showCcd(ccd, ccdImage=ccdIm, frame=frame) frame += 1 # If you'd like the image in un-rotated coordinates... rotCcdIm = afwMath.rotateImageBy90(ccdIm.getMaskedImage().getImage(), -ccd.getOrientation().getNQuarter()) ds9.mtv(rotCcdIm, frame=frame, title="Assembled derotated %s" % ccdName) frame += 1
def runDataRef(self, expRefList, butler): """Make summary plots of full focalplane images. """ if len(expRefList) == 0: return pipeBase.Struct(exitStatus=1) lsst.afw.fits.setAllowImageCompression( self.config.allowFitsCompression) dstype = expRefList[0].butlerSubset.datasetType if dstype == "raw": def callback(im, ccd, imageSource): return cgu.rawCallback(im, ccd, imageSource, correctGain=True, subtractBias=True) elif dstype == "eimage": callback = eimageCallback elif self.config.doApplySkyCorr: callback = skyCorrCallback else: callback = None for visit in set([er.dataId["visit"] for er in expRefList]): self.log.info("Processing visit %d", visit) expRefListForVisit = [ er for er in expRefList if er.dataId["visit"] == visit ] dataId = expRefListForVisit[0].dataId bi = cgu.ButlerImage(butler, dstype, visit=visit, callback=callback, verbose=True) if self.config.doSensorImages: for dataId in (er.dataId for er in expRefListForVisit): ccd = butler.get('calexp_detector', **dataId) try: md = butler.get('calexp_md', **dataId) except RuntimeError: md = None if md: afwGeom.makeSkyWcs( md, strip=True ) # strip WCS cards; they're invalidated by binning try: binned_im = bi.getCcdImage( ccd, binSize=self.config.sensorBinSize, asMaskedImage=True)[0] binned_im = rotateImageBy90( binned_im, ccd.getOrientation().getNQuarter()) if self.config.putFullSensors: binned_exp = afwImage.ExposureF(binned_im) binned_exp.setMetadata(md) butler.put(binned_exp, 'binned_sensor_fits', **dataId, dstype=dstype) except (TypeError, RuntimeError) as e: # butler couldn't put the image or there was no image to put self.log.warn("Unable to make binned image: %s", e) continue (x, y) = binned_im.getDimensions() boxes = { 'A': afwGeom.Box2I(afwGeom.PointI(0, y / 2), afwGeom.ExtentI(x, y / 2)), 'B': afwGeom.Box2I(afwGeom.PointI(0, 0), afwGeom.ExtentI(x, y / 2)) } for half in ('A', 'B'): box = boxes[half] binned_exp = afwImage.ExposureF(binned_im[box]) binned_exp.setMetadata(md) butler.put(binned_exp, 'binned_sensor_fits_halves', half=half, **dataId, dstype=dstype) im = cgu.showCamera(butler.get('camera'), imageSource=bi, binSize=self.config.binSize) dstypeName = "%s-%s" % ( dstype, self.config.fpId) if self.config.fpId else dstype butler.put(im, 'focal_plane_fits', visit=visit, dstype=dstypeName) # Compute the zscale stretch for just the CCDs that have data. detectorNameList = [ "%s_%s" % (er.dataId["raftName"], er.dataId["detectorName"]) for er in expRefListForVisit ] im_scaling = cgu.showCamera(butler.get('camera'), imageSource=bi, binSize=self.config.binSize, detectorNameList=detectorNameList) zmap = ZScaleMapping(im_scaling, contrast=self.config.contrast) im = flipImage(im, False, True) rgb = zmap.makeRgbImage(im, im, im) file_name = butler.get('focal_plane_png_filename', visit=visit, dstype=dstypeName) writeRGB(file_name[0], rgb) return pipeBase.Struct(exitStatus=0)
def makeImageFromCamera(camera, detectorNameList=None, background=numpy.nan, bufferSize=10, imageSource=FakeImageDataSource(), imageFactory=afwImage.ImageU, binSize=1): """Make an Image of a Camera. Put each detector's image in the correct location and orientation on the focal plane. The input images can be binned to an integer fraction of their original bboxes. Parameters ---------- camera : `lsst.afw.cameraGeom.Camera` Camera object to use to make the image. detectorNameList : `list` of `str` List of detector names from `camera` to use in building the image. Use all Detectors if None. background : `float` Value to use where there is no Detector. bufferSize : `int` Size of border in binned pixels to make around the camera image. imageSource : `FakeImageDataSource` or None Source to get ccd images. Must have a ``getCcdImage()`` method. imageFactory : callable like `lsst.afw.image.Image` Type of image to build. binSize : `int` Bin the image by this factor in both dimensions. Returns ------- image : `lsst.afw.image.Image` Image of the entire camera. """ log = lsst.log.Log.getLogger("afw.cameraGeom.utils.makeImageFromCamera") if detectorNameList is None: ccdList = camera else: ccdList = [camera[name] for name in detectorNameList] if detectorNameList is None: camBbox = camera.getFpBBox() else: camBbox = lsst.geom.Box2D() for detName in detectorNameList: for corner in camera[detName].getCorners(FOCAL_PLANE): camBbox.include(corner) pixelSize_o = camera[next(camera.getNameIter())].getPixelSize() camBbox = getCameraImageBBox(camBbox, pixelSize_o, bufferSize * binSize) origin = camBbox.getMin() camIm = imageFactory( int(math.ceil(camBbox.getDimensions().getX() / binSize)), int(math.ceil(camBbox.getDimensions().getY() / binSize))) camIm[:] = imageSource.background assert imageSource.isTrimmed, "isTrimmed is False isn't supported by getCcdInCamBBoxList" boxList = getCcdInCamBBoxList(ccdList, binSize, pixelSize_o, origin) for det, bbox in zip(ccdList, boxList): im = imageSource.getCcdImage(det, imageFactory, binSize)[0] if im is None: continue nQuarter = det.getOrientation().getNQuarter() im = afwMath.rotateImageBy90(im, nQuarter) imView = camIm.Factory(camIm, bbox, afwImage.LOCAL) try: imView[:] = im except pexExceptions.LengthError as e: log.error( "Unable to fit image for detector \"%s\" into image of camera: %s" % (det.getName(), e)) return camIm
def rawCallback(im, ccd=None, imageSource=None, correctGain=False, subtractBias=False, convertToFloat=False, obeyNQuarter=True): """A callback function that may or may not subtract bias/correct gain/trim a raw image. Parameters ---------- im : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage` or `lsst.afw.image.Exposure` An image of a chip, ready to be binned and maybe rotated. ccd : `lsst.afw.cameraGeom.Detector` or `None` The Detector; if `None` assume that im is an exposure and extract its Detector. imageSource : `FakeImageDataSource` or `None` Source to get ccd images. Must have a `getCcdImage()` method. correctGain : `bool` Correct each amplifier for its gain? subtractBias : `bool` Subtract the bias from each amplifier? convertToFloat : `bool` Convert ``im`` to floating point if possible. obeyNQuarter : `bool` Obey nQuarter from the Detector (default: True) Returns ------- image : `lsst.afw.image.Image` like The constructed image (type returned by ``im.Factory``). Notes ----- If imageSource is derived from ButlerImage, imageSource.butler is available. """ if ccd is None: ccd = im.getDetector() if hasattr(im, "getMaskedImage"): im = im.getMaskedImage() if convertToFloat and hasattr(im, "convertF"): im = im.convertF() isTrimmed = imageSource.isTrimmed if isTrimmed: bbox = ccd.getBBox() else: bbox = calcRawCcdBBox(ccd) ampImages = [] for a in ccd: if isTrimmed: data = im[a.getRawDataBBox()] else: data = im if subtractBias: bias = im[a.getRawHorizontalOverscanBBox()] data -= afwMath.makeStatistics(bias, afwMath.MEANCLIP).getValue() if correctGain: data *= a.getGain() ampImages.append(data) ccdImage = im.Factory(bbox) for ampImage, amp in zip(ampImages, ccd): if isTrimmed: assembleAmplifierImage(ccdImage, ampImage, amp) else: assembleAmplifierRawImage(ccdImage, ampImage, amp) if obeyNQuarter: nQuarter = ccd.getOrientation().getNQuarter() ccdImage = afwMath.rotateImageBy90(ccdImage, nQuarter) return ccdImage
def warpStamps(self, stamps, pixCenters): """Warps and shifts all given stamps so they are sampled on the same pixel grid and centered on the central pixel. This includes rotating the stamp depending on detector orientation. Parameters ---------- stamps : `collections.abc.Sequence` [`afwImage.exposure.exposure.ExposureF`] Image cutouts centered on a single object. pixCenters : `collections.abc.Sequence` [`geom.Point2D`] Positions of each object's center (as obtained from the refCat), in pixels. Returns ------- warpedStars : `list` [`afwImage.maskedImage.maskedImage.MaskedImage`] """ # warping control; only contains shiftingALg provided in config warpCont = afwMath.WarpingControl(self.config.warpingKernelName) # Compare model to star stamp sizes bufferPix = (self.modelStampSize[0] - self.config.stampSize[0], self.modelStampSize[1] - self.config.stampSize[1]) # Initialize detector instance (note all stars were extracted from an # exposure from the same detector) det = stamps[0].getDetector() # Define correction for optical distortions if self.config.doApplyTransform: pixToTan = det.getTransform(cg.PIXELS, cg.TAN_PIXELS) else: pixToTan = tFactory.makeIdentityTransform() # Array of all possible rotations for detector orientation: possibleRots = np.array([k*np.pi/2 for k in range(4)]) # determine how many, if any, rotations are required yaw = det.getOrientation().getYaw() nb90Rots = np.argmin(np.abs(possibleRots - float(yaw))) # apply transformation to each star warpedStars = [] for star, cent in zip(stamps, pixCenters): # (re)create empty destination image destImage = afwImage.MaskedImageF(*self.modelStampSize) bottomLeft = geom.Point2D(star.image.getXY0()) newBottomLeft = pixToTan.applyForward(bottomLeft) newBottomLeft.setX(newBottomLeft.getX() - bufferPix[0]/2) newBottomLeft.setY(newBottomLeft.getY() - bufferPix[1]/2) # Convert to int newBottomLeft = geom.Point2I(newBottomLeft) # Set origin destImage.setXY0(newBottomLeft) # Define linear shifting to recenter stamps newCenter = pixToTan.applyForward(cent) # center of warped star shift = self.modelCenter[0] + newBottomLeft[0] - newCenter[0],\ self.modelCenter[1] + newBottomLeft[1] - newCenter[1] affineShift = geom.AffineTransform(shift) shiftTransform = tFactory.makeTransform(affineShift) # Define full transform (warp and shift) starWarper = pixToTan.then(shiftTransform) # Apply it goodPix = afwMath.warpImage(destImage, star.getMaskedImage(), starWarper, warpCont) if not goodPix: self.log.debug("Warping of a star failed: no good pixel in output") # Arbitrarily set origin of shifted star to 0 destImage.setXY0(0, 0) # Apply rotation if apropriate if nb90Rots: destImage = afwMath.rotateImageBy90(destImage, nb90Rots) warpedStars.append(destImage.clone()) return warpedStars
def getCcdImage(self, ccd, imageFactory=afwImage.ImageF, binSize=1, as_masked_image=False): """Return an image of the specified ccd, and also the (possibly updated) ccd Parameters ---------- ccd : `afwImage.CameraGeom.Detector` Detector for the constructed image imageFactory : `afwImage.Image`, optional Image like factory for producing default images (`afwImage.ImageF` by default). binSize : `int`, optional Pixels to bin together. Symmetric in x and y (1 by default) as_masked_image : `bool`, optional Return the image as an `afwImage.MaskedImage`? (False by default. This returns an `afwImage.Image`) """ bbox = ccd.getBBox() def parse_name_to_dataId(name_str): raft, sensor = name_str.split() return {'raft': raft[-3:], 'sensor': sensor[-3:]} im = None cid = ccd.getName() did = parse_name_to_dataId(cid) if self.butler is not None and did['raft'] not in [ '0,0', '0,4', '4,0', '4,4' ]: self.kwargs.update(did) try: im = self.butler.get(self.type, **self.kwargs) ccd = im.getDetector() # possibly modified by assembleCcdTask if self.type == 'eimage' or self.type == 'calexp': im.setMaskedImage(rotateImageBy90(im.getMaskedImage(), 2)) else: raise ValueError( "Only valid dataset types are 'eimage' and 'calexp'") except (NoResults, RuntimeError): pass else: return None, ccd if im is None: if not as_masked_image: im = self._prepareImage(ccd, imageFactory(*bbox.getDimensions()), binSize) return rotateImageBy90(im, ccd.getOrientation().getNQuarter()), ccd else: im = self._prepareImage( ccd, afwImage.makeMaskedImage( imageFactory(*bbox.getDimensions())), binSize) return rotateImageBy90(im, ccd.getOrientation().getNQuarter()), ccd if self.type == "raw": raise ValueError("This class only handles ccd size images") if not as_masked_image: return self._prepareImage(ccd, im.getMaskedImage().getImage(), binSize), ccd else: return self._prepareImage(ccd, im.getMaskedImage(), binSize), ccd