def make_stamps(n_stamps=3, use_archive=False): stampSize = 25 # create dummy stamp stamps stampImages = [ afwImage.maskedImage.MaskedImageF(stampSize, stampSize) for _ in range(n_stamps) ] for stampIm in stampImages: stampImArray = stampIm.image.array stampImArray += np.random.rand(stampSize, stampSize) stampMaskArray = stampIm.mask.array stampMaskArray += 10 stampVarArray = stampIm.variance.array stampVarArray += 1000. ras = np.random.rand(n_stamps) * 360. decs = np.random.rand(n_stamps) * 180 - 90 archive_elements = [ tF.makeTransform(geom.AffineTransform(np.random.rand(2))) if use_archive else None for _ in range(n_stamps) ] stamp_list = [ stamps.Stamp(stamp_im=stampIm, position=geom.SpherePoint(geom.Angle(ra, geom.degrees), geom.Angle(dec, geom.degrees)), archive_element=ae) for stampIm, ra, dec, ae in zip( stampImages, ras, decs, archive_elements) ] metadata = PropertyList() metadata['RA_DEG'] = ras metadata['DEC_DEG'] = decs return stamps.Stamps(stamp_list, metadata=metadata, use_archive=True)
def makeTransformDict(nativeSys, transformDict, plateScale): """Make a dictionary of TransformPoint2ToPoint2s from yaml, mapping from nativeSys Parameters ---------- nativeSys : `lsst.afw.cameraGeom.CameraSys` transformDict : `dict` A dict specifying parameters of transforms; keys are camera system names. plateScale : `lsst.geom.Angle` The size of a pixel in angular units/mm (e.g. 20 arcsec/mm for LSST) Returns ------- transforms : `dict` A dict of `lsst.afw.cameraGeom.CameraSys` : `lsst.afw.geom.TransformPoint2ToPoint2` The resulting dict's keys are `~lsst.afw.cameraGeom.CameraSys`, and the values are Transforms *from* NativeSys *to* CameraSys """ # As other comments note this is required, and this is one function where # it's assumed assert nativeSys == cameraGeom.FOCAL_PLANE, "Cameras with nativeSys != FOCAL_PLANE are not supported." resMap = dict() for key, transform in transformDict.items(): transformType = transform["transformType"] knownTransformTypes = ["affine", "radial"] if transformType not in knownTransformTypes: raise RuntimeError("Saw unknown transform type for %s: %s (known types are: [%s])" % ( key, transform["transformType"], ", ".join(knownTransformTypes))) if transformType == "affine": affine = geom.AffineTransform(np.array(transform["linear"]), np.array(transform["translation"])) transform = afwGeom.makeTransform(affine) elif transformType == "radial": # radial coefficients of the form [0, 1 (no units), C2 (rad), # usually 0, C3 (rad^2), ...] # Radial distortion is modeled as a radial polynomial that converts # from focal plane radius (in mm) to field angle (in radians). # The provided coefficients are divided by the plate # scale (in radians/mm) meaning that C1 is always 1. radialCoeffs = np.array(transform["coeffs"]) radialCoeffs *= plateScale.asRadians() transform = afwGeom.makeRadialTransform(radialCoeffs) else: raise RuntimeError("Impossible condition \"%s\" is not in: [%s])" % ( transform["transformType"], ", ".join(knownTransformTypes))) resMap[cameraGeom.CameraSys(key)] = transform return resMap
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