def testWarpingControl(self): """Test the basic mechanics of WarpingControl """ for interpLength in (0, 1, 52): wc = afwMath.WarpingControl("lanczos3", "", 0, interpLength) self.assertFalse(wc.hasMaskWarpingKernel()) self.assertEqual(wc.getInterpLength(), interpLength) for newInterpLength in (3, 7, 9): wc.setInterpLength(newInterpLength) self.assertEqual(wc.getInterpLength(), newInterpLength) for cacheSize in (0, 100): wc = afwMath.WarpingControl("lanczos3", "bilinear", cacheSize) self.assertTrue(wc.hasMaskWarpingKernel()) self.assertEqual(wc.getCacheSize(), cacheSize) self.assertEqual(wc.getWarpingKernel().getCacheSize(), cacheSize) self.assertEqual(wc.getMaskWarpingKernel().getCacheSize(), cacheSize) for newCacheSize in (1, 50): wc.setCacheSize(newCacheSize) self.assertEqual(wc.getCacheSize(), newCacheSize) self.assertEqual(wc.getWarpingKernel().getCacheSize(), newCacheSize) self.assertEqual(wc.getMaskWarpingKernel().getCacheSize(), newCacheSize)
def testTicket2441(self): """Test ticket 2441: warpExposure sometimes mishandles zero-extent dest exposures""" fromWcs = makeWcs( pixelScale=afwGeom.Angle(1.0e-8, afwGeom.degrees), projection="TAN", crPixPos=(0, 0), crValCoord=afwCoord.IcrsCoord(afwGeom.Point2D(359, 0), afwGeom.degrees), ) fromExp = afwImage.ExposureF(afwImage.MaskedImageF(10, 10), fromWcs) toWcs = makeWcs( pixelScale=afwGeom.Angle(0.00011, afwGeom.degrees), projection="CEA", crPixPos=(410000.0, 11441.0), crValCoord=afwCoord.IcrsCoord(afwGeom.Point2D(45, 0), afwGeom.degrees), doFlipX=True, ) toExp = afwImage.ExposureF(afwImage.MaskedImageF(0, 0), toWcs) warpControl = afwMath.WarpingControl("lanczos3") # if a bug described in ticket #2441 is present, this will raise an # exception: numGoodPix = afwMath.warpExposure(toExp, fromExp, warpControl) self.assertEqual(numGoodPix, 0)
def testSmallSrc(self): """Verify that a source image that is too small will not raise an exception This tests another bug that was fixed in ticket #2441 """ fromWcs = makeWcs( pixelScale=afwGeom.Angle(1.0e-8, afwGeom.degrees), projection="TAN", crPixPos=(0, 0), crValCoord=afwCoord.IcrsCoord(afwGeom.Point2D(359, 0), afwGeom.degrees), ) fromExp = afwImage.ExposureF(afwImage.MaskedImageF(1, 1), fromWcs) toWcs = makeWcs( pixelScale=afwGeom.Angle(1.1e-8, afwGeom.degrees), projection="TAN", crPixPos=(0, 0), crValCoord=afwCoord.IcrsCoord(afwGeom.Point2D(358, 0), afwGeom.degrees), ) toExp = afwImage.ExposureF(afwImage.MaskedImageF(10, 10), toWcs) warpControl = afwMath.WarpingControl("lanczos3") # if a bug described in ticket #2441 is present, this will raise an # exception: numGoodPix = afwMath.warpExposure(toExp, fromExp, warpControl) self.assertEqual(numGoodPix, 0) imArr, maskArr, varArr = toExp.getMaskedImage().getArrays() self.assertTrue(np.all(np.isnan(imArr))) self.assertTrue(np.all(np.isinf(varArr))) noDataBitMask = afwImage.Mask.getPlaneBitMask("NO_DATA") self.assertTrue(np.all(maskArr == noDataBitMask))
def testWarpIntoSelf(self, interpLength=10): """Cannot warp in-place """ originalExposure = afwImage.ExposureF(afwGeom.Extent2I(100, 100)) warpingControl = afwMath.WarpingControl("bilinear", "", 0, interpLength) try: afwMath.warpExposure(originalExposure, originalExposure, warpingControl) self.fail("warpExposure in place (dest is src) should fail") except Exception: pass try: afwMath.warpImage(originalExposure.getMaskedImage(), originalExposure.getWcs(), originalExposure.getMaskedImage(), originalExposure.getWcs(), warpingControl) self.fail( "warpImage<MaskedImage> in place (dest is src) should fail") except Exception: pass try: afwMath.warpImage(originalExposure.getImage(), originalExposure.getWcs(), originalExposure.getImage(), originalExposure.getWcs(), warpingControl) self.fail("warpImage<Image> in place (dest is src) should fail") except Exception: pass
def testSmallSrc(self): """Verify that a source image that is too small will not raise an exception This tests another bug that was fixed in ticket #2441 """ fromWcs = afwGeom.makeSkyWcs( crpix=lsst.geom.Point2D(0, 0), crval=lsst.geom.SpherePoint(359, 0, lsst.geom.degrees), cdMatrix=afwGeom.makeCdMatrix(scale=1.0e-8 * lsst.geom.degrees), ) fromExp = afwImage.ExposureF(afwImage.MaskedImageF(1, 1), fromWcs) toWcs = afwGeom.makeSkyWcs( crpix=lsst.geom.Point2D(0, 0), crval=lsst.geom.SpherePoint(358, 0, lsst.geom.degrees), cdMatrix=afwGeom.makeCdMatrix(scale=1.1e-8 * lsst.geom.degrees), ) toExp = afwImage.ExposureF(afwImage.MaskedImageF(10, 10), toWcs) warpControl = afwMath.WarpingControl("lanczos3") # if a bug described in ticket #2441 is present, this will raise an # exception: numGoodPix = afwMath.warpExposure(toExp, fromExp, warpControl) self.assertEqual(numGoodPix, 0) imArr, maskArr, varArr = toExp.getMaskedImage().getArrays() self.assertTrue(np.all(np.isnan(imArr))) self.assertTrue(np.all(np.isinf(varArr))) noDataBitMask = afwImage.Mask.getPlaneBitMask("NO_DATA") self.assertTrue(np.all(maskArr == noDataBitMask))
def testNullWarpExposure(self, interpLength=10): """Test that warpExposure maps an image onto itself. Note: - NO_DATA and off-CCD pixels must be ignored - bad mask pixels get smeared out so we have to excluded all bad mask pixels from the output image when comparing masks. """ filterPolicyFile = pexPolicy.DefaultPolicyFile("afw", "SdssFilters.paf", "tests") filterPolicy = pexPolicy.Policy.createPolicy( filterPolicyFile, filterPolicyFile.getRepositoryPath(), True) imageUtils.defineFiltersFromPolicy(filterPolicy, reset=True) originalExposure = afwImage.ExposureF(originalExposurePath) originalFilter = afwImage.Filter("i") originalCalib = afwImage.Calib() originalCalib.setFluxMag0(1.0e5, 1.0e3) originalExposure.setFilter(originalFilter) originalExposure.setCalib(originalCalib) afwWarpedExposure = afwImage.ExposureF(originalExposure.getBBox(), originalExposure.getWcs()) warpingControl = afwMath.WarpingControl("lanczos4", "", 0, interpLength) afwMath.warpExposure(afwWarpedExposure, originalExposure, warpingControl) if SAVE_FITS_FILES: afwWarpedExposure.writeFits("afwWarpedExposureNull.fits") self.assertEqual(afwWarpedExposure.getFilter().getName(), originalFilter.getName()) self.assertEqual(afwWarpedExposure.getCalib().getFluxMag0(), originalCalib.getFluxMag0()) afwWarpedMaskedImage = afwWarpedExposure.getMaskedImage() afwWarpedMask = afwWarpedMaskedImage.getMask() noDataBitMask = afwWarpedMask.getPlaneBitMask("NO_DATA") afwWarpedMaskedImageArrSet = afwWarpedMaskedImage.getArrays() afwWarpedMaskArr = afwWarpedMaskedImageArrSet[1] # compare all non-DATA pixels of image and variance, but relax specs a bit # because of minor noise introduced by bad pixels noDataMaskArr = afwWarpedMaskArr & noDataBitMask msg = "afw null-warped MaskedImage (all pixels, relaxed tolerance)" self.assertMaskedImagesAlmostEqual(afwWarpedMaskedImage, originalExposure.getMaskedImage(), doMask=False, skipMask=noDataMaskArr, atol=1e-5, msg=msg) # compare good pixels (mask=0) of image, mask and variance using full # tolerance msg = "afw null-warped MaskedImage (good pixels, max tolerance)" self.assertMaskedImagesAlmostEqual(afwWarpedMaskedImage, originalExposure.getMaskedImage(), skipMask=afwWarpedMask, msg=msg)
def main(): DefKernel = "lanczos4" DefVerbosity = 1 usage = """usage: %%prog [options] srcExposure refExposure destExposure Computes destExposure = srcExposure warped to match refExposure's WCS and bounding box, where exposure arguments are paths to Exposure fits files""" parser = optparse.OptionParser(usage) parser.add_option( "-k", "--kernel", type=str, default=DefKernel, help="kernel type: bilinear or lancszosN where N = order; default=%s" % (DefKernel, )) parser.add_option( "-v", "--verbosity", type=int, default=DefVerbosity, help= "verbosity of diagnostic trace messages; 1 for just TRACE1, more for more" + " information; default=%s" % (DefVerbosity, )) (opt, args) = parser.parse_args() log.configure() kernelName = opt.kernel.lower() if len(args) != 3: parser.error("You must supply three arguments") srcExposurePath = args[0] refExposurePath = args[1] destExposurePath = args[2] print("Remapping exposure :", srcExposurePath) print("to match wcs and bbox of:", refExposurePath) print("using", kernelName, "kernel") warpingControl = afwMath.WarpingControl(kernelName) srcExposure = afwImage.ExposureF(srcExposurePath) destExposure = afwImage.ExposureF(refExposurePath) if opt.verbosity > 0: print("Verbosity =", opt.verbosity) logUtils.traceSetAt("afw.math.warp", opt.verbosity) numGoodPixels = afwMath.warpExposure(destExposure, srcExposure, warpingControl) print("Warped exposure has %s good pixels" % (numGoodPixels)) print("Writing warped exposure to %s" % (destExposurePath, )) destExposure.writeFits(destExposurePath)
def testWarpingControl(self): """Test the basic mechanics of WarpingControl """ for interpLength in (0, 1, 52): wc = afwMath.WarpingControl("lanczos3", "", 0, interpLength) self.assertFalse(wc.hasMaskWarpingKernel()) self.assertEqual(wc.getInterpLength(), interpLength) for newInterpLength in (3, 7, 9): wc.setInterpLength(newInterpLength) self.assertEqual(wc.getInterpLength(), newInterpLength) for cacheSize in (0, 100): wc = afwMath.WarpingControl("lanczos3", "bilinear", cacheSize) self.assertTrue(wc.hasMaskWarpingKernel()) self.assertEqual(wc.getCacheSize(), cacheSize) self.assertEqual(wc.getWarpingKernel().getCacheSize(), cacheSize) self.assertEqual(wc.getMaskWarpingKernel().getCacheSize(), cacheSize) for newCacheSize in (1, 50): wc.setCacheSize(newCacheSize) self.assertEqual(wc.getCacheSize(), newCacheSize) self.assertEqual(wc.getWarpingKernel().getCacheSize(), newCacheSize) self.assertEqual(wc.getMaskWarpingKernel().getCacheSize(), newCacheSize) wc = afwMath.WarpingControl("lanczos4", "nearest", 64, 7, 42) self.assertTrue(wc.isPersistable()) with lsst.utils.tests.getTempFilePath(".fits", expectOutput=True) as tempFile: wc.writeFits(tempFile) wc2 = afwMath.WarpingControl.readFits(tempFile) self.assertEqual(wc.getCacheSize(), wc2.getCacheSize()) self.assertEqual(wc.getInterpLength(), wc2.getInterpLength()) self.assertEqual(wc.getWarpingKernel().getBBox(), wc2.getWarpingKernel().getBBox()) self.assertEqual(wc.getWarpingKernel().getKernelParameters(), wc2.getWarpingKernel().getKernelParameters()) self.assertEqual(wc.hasMaskWarpingKernel(), wc2.hasMaskWarpingKernel()) self.assertEqual(wc.getMaskWarpingKernel().getBBox(), wc2.getMaskWarpingKernel().getBBox()) self.assertEqual(wc.getMaskWarpingKernel().getKernelParameters(), wc2.getMaskWarpingKernel().getKernelParameters()) self.assertEqual(wc.getGrowFullMask(), wc2.getGrowFullMask())
def testWarpingControlError(self): """Test error handling of WarpingControl """ # error: mask kernel smaller than main kernel for kernelName, maskKernelName in ( ("bilinear", "lanczos3"), ("bilinear", "lanczos4"), ("lanczos3", "lanczos4"), ): with self.assertRaises(pexExcept.InvalidParameterError): afwMath.WarpingControl(kernelName, maskKernelName) # error: new mask kernel larger than main kernel warpingControl = afwMath.WarpingControl("bilinear") for maskKernelName in ("lanczos3", "lanczos4"): with self.assertRaises(pexExcept.InvalidParameterError): warpingControl.setMaskWarpingKernelName(maskKernelName) # error: new kernel smaller than mask kernel warpingControl = afwMath.WarpingControl("lanczos4", "lanczos4") for kernelName in ("bilinear", "lanczos3"): with self.assertRaises(pexExcept.InvalidParameterError): warpingControl.setWarpingKernelName(kernelName) # OK: main kernel at least as big as mask kernel for kernelName, maskKernelName in ( ("bilinear", "bilinear"), ("lanczos3", "lanczos3"), ("lanczos3", "bilinear"), ("lanczos4", "lanczos3"), ): # this should not raise any exception afwMath.WarpingControl(kernelName, maskKernelName) # invalid kernel names for kernelName, maskKernelName in ( ("badname", ""), ("lanczos", ""), # no digit after lanczos ("lanczos3", "badname"), ("lanczos3", "lanczos"), ): with self.assertRaises(pexExcept.InvalidParameterError): afwMath.WarpingControl(kernelName, maskKernelName)
def testNullWarpExposure(self, interpLength=10): """Test that warpExposure maps an image onto itself. Note: - NO_DATA and off-CCD pixels must be ignored - bad mask pixels get smeared out so we have to excluded all bad mask pixels from the output image when comparing masks. """ originalExposure = afwImage.ExposureF(originalExposurePath) originalExposure.getInfo().setId(10313423) originalExposure.getInfo().setVisitInfo(makeVisitInfo()) originalFilterLabel = afwImage.FilterLabel(band="i") originalPhotoCalib = afwImage.PhotoCalib(1.0e5, 1.0e3) originalExposure.setFilter(originalFilterLabel) originalExposure.setPhotoCalib(originalPhotoCalib) afwWarpedExposure = afwImage.ExposureF(originalExposure.getBBox(), originalExposure.getWcs()) warpingControl = afwMath.WarpingControl("lanczos4", "", 0, interpLength) afwMath.warpExposure(afwWarpedExposure, originalExposure, warpingControl) if SAVE_FITS_FILES: afwWarpedExposure.writeFits("afwWarpedExposureNull.fits") self.assertEqual(afwWarpedExposure.getFilter().bandLabel, originalFilterLabel.bandLabel) self.assertEqual(afwWarpedExposure.getPhotoCalib(), originalPhotoCalib) self.assertEqual(afwWarpedExposure.getInfo().getVisitInfo(), originalExposure.getInfo().getVisitInfo()) afwWarpedMaskedImage = afwWarpedExposure.getMaskedImage() afwWarpedMask = afwWarpedMaskedImage.getMask() noDataBitMask = afwWarpedMask.getPlaneBitMask("NO_DATA") afwWarpedMaskedImageArrSet = afwWarpedMaskedImage.getArrays() afwWarpedMaskArr = afwWarpedMaskedImageArrSet[1] # compare all non-DATA pixels of image and variance, but relax specs a bit # because of minor noise introduced by bad pixels noDataMaskArr = afwWarpedMaskArr & noDataBitMask msg = "afw null-warped MaskedImage (all pixels, relaxed tolerance)" self.assertMaskedImagesAlmostEqual(afwWarpedMaskedImage, originalExposure.getMaskedImage(), doMask=False, skipMask=noDataMaskArr, atol=1e-5, msg=msg) # compare good pixels (mask=0) of image, mask and variance using full # tolerance msg = "afw null-warped MaskedImage (good pixels, max tolerance)" self.assertMaskedImagesAlmostEqual(afwWarpedMaskedImage, originalExposure.getMaskedImage(), skipMask=afwWarpedMask, msg=msg)
def testNonIcrs(self): """Test that warping to a non-ICRS-like coordinate system produces different results It would be better to also test that the results are as expected, but I have not been able to get swarp to perform this operation, so have not found an independent means of generating the expected results. """ kernelName = "lanczos3" rtol = 4e-5 atol = 1e-2 warpingControl = afwMath.WarpingControl(kernelName, ) originalExposure = afwImage.ExposureF(originalExposurePath) originalImage = originalExposure.getMaskedImage().getImage() originalWcs = originalExposure.getWcs() swarpedImageName = "medswarp1%s.fits" % (kernelName, ) swarpedImagePath = os.path.join(dataDir, swarpedImageName) swarpedDecoratedImage = afwImage.DecoratedImageF(swarpedImagePath) swarpedImage = swarpedDecoratedImage.getImage() for changeEquinox in (False, True): swarpedMetadata = swarpedDecoratedImage.getMetadata() if changeEquinox: swarpedMetadata.set("RADECSYS", "FK5") swarpedMetadata.set("EQUINOX", swarpedMetadata.get("EQUINOX") + 1) warpedWcs = afwImage.makeWcs(swarpedMetadata) afwWarpedImage = afwImage.ImageF(swarpedImage.getDimensions()) originalImage = originalExposure.getMaskedImage().getImage() originalWcs = originalExposure.getWcs() numGoodPix = afwMath.warpImage(afwWarpedImage, warpedWcs, originalImage, originalWcs, warpingControl) self.assertGreater(numGoodPix, 50) afwWarpedImageArr = afwWarpedImage.getArray() noDataMaskArr = np.isnan(afwWarpedImageArr) if changeEquinox: with self.assertRaises(AssertionError): self.assertImagesAlmostEqual(afwWarpedImage, swarpedImage, skipMask=noDataMaskArr, rtol=rtol, atol=atol) else: self.assertImagesAlmostEqual(afwWarpedImage, swarpedImage, skipMask=noDataMaskArr, rtol=rtol, atol=atol)
def acsEventCallback(key, source, im, frame): """Callback for event handlers to find COSMOS ACS cutout. \param key Key struck \param source The Source under the cursor \param im The (HSC) image cutout displayed in frame \param frame The frame that the HSC data's displayed in (we'll use the next one) We also use the following static members of utils.EventHandler (if set): sizeCutout The size of the HSC cutout (arcsec; default: 4.0) scale Make the COSMOS image with pixel size scale*HSC's pixel size (default 0.25 => 0.42mas) Use as e.g. utils.eventCallbacks['c'] = cosmos.acsEventCallback """ sizeCutout = utils.EventHandler.sizeCutout if hasattr( utils.EventHandler, "sizeCutout") else 4.0 # arcsec scale = utils.EventHandler.scale if hasattr( utils.EventHandler, "scale") else 0.25 # Pixel size scaling pos = source.get("coord") exp = getCosmosCutout(*pos.getPosition(), sizeX=sizeCutout) if im and exp and exp.getWcs(): # # Resample and rotate to the HSC orientation # warpingControl = afwMath.WarpingControl("lanczos3") rat = im.getWcs().pixelScale().asArcseconds() / exp.getWcs( ).pixelScale().asArcseconds() hsize = int(0.5 * exp.getWidth() / (scale * rat)) rexp = afwImage.ExposureF(2 * hsize + 1, 2 * hsize + 1) rexp.setWcs( afwImage.Wcs(pos.getPosition(), afwGeom.Point2D(hsize, hsize), im.getWcs().getCDMatrix() * scale)) afwMath.warpExposure(rexp, exp, warpingControl) else: print "\nI'm unable to remap the cosmos image to your coordinates, sorry" rexp = exp.getMaskedImage().getImage() frame += 1 rim = rexp if hasattr(rim, "getMaskedImage"): rim = rim.getMaskedImage().getImage() if hasattr(rim, "getImage"): rim = rim.getImage() disp = afwDisplay.Display(frame=frame) disp.mtv(rim) if hasattr(rexp, "getWcs"): cen = rexp.getWcs().skyToPixel(pos) - afwGeom.PointD(rexp.getXY0()) disp.pan(*cen) disp.dot('+', *cen)
def testWarpingControlError(self): """Test error handling of WarpingControl """ # error: mask kernel smaller than main kernel for kernelName, maskKernelName in ( ("bilinear", "lanczos3"), ("bilinear", "lanczos4"), ("lanczos3", "lanczos4"), ): self.assertRaises(pexExcept.LsstCppException, afwMath.WarpingControl, kernelName, maskKernelName) # error: new mask kernel larger than main kernel warpingControl = afwMath.WarpingControl("bilinear") for maskKernelName in ("lanczos3", "lanczos4"): self.assertRaises(pexExcept.LsstCppException, warpingControl.setMaskWarpingKernelName, maskKernelName) # error: new kernel smaller than mask kernel warpingControl = afwMath.WarpingControl("lanczos4", "lanczos4") for kernelName in ("bilinear", "lanczos3"): self.assertRaises(pexExcept.LsstCppException, warpingControl.setWarpingKernelName, kernelName) # error: GPU only works with Lanczos kernels self.assertRaises(pexExcept.LsstCppException, afwMath.WarpingControl, "bilinear", "", 0, 0, afwGpu.USE_GPU) warpingControl = afwMath.WarpingControl("bilinear") self.assertRaises(pexExcept.LsstCppException, warpingControl.setDevicePreference, afwGpu.USE_GPU) # OK: GPU works with Lanczos kernels for kernelName in ("lanczos3", "lanczos4"): afwMath.WarpingControl(kernelName, "", 0, 0, afwGpu.USE_GPU) warpingControl = afwMath.WarpingControl(kernelName) warpingControl.setDevicePreference(afwGpu.USE_GPU) # OK: main kernel at least as big as mask kernel for kernelName, maskKernelName in ( ("bilinear", "bilinear"), ("lanczos3", "lanczos3"), ("lanczos3", "bilinear"), ("lanczos4", "lanczos3"), ): # this should not raise any exception afwMath.WarpingControl(kernelName, maskKernelName) # invalid kernel names for kernelName, maskKernelName in ( ("badname", ""), ("lanczos", ""), # no digit after lanczos ("lanczos3", "badname"), ("lanczos3", "lanczos"), ): self.assertRaises(pexExcept.LsstCppException, afwMath.WarpingControl, kernelName, maskKernelName)
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 testNullWcs(self, interpLength=10): """Cannot warp from or into an exposure without a Wcs. """ exposureWithWcs = afwImage.ExposureF(originalExposurePath) mi = exposureWithWcs.getMaskedImage() exposureWithoutWcs = afwImage.ExposureF(mi.getDimensions()) warpingControl = afwMath.WarpingControl( "bilinear", "", 0, interpLength) with self.assertRaises(pexExcept.InvalidParameterError): afwMath.warpExposure(exposureWithWcs, exposureWithoutWcs, warpingControl) with self.assertRaises(pexExcept.InvalidParameterError): afwMath.warpExposure(exposureWithoutWcs, exposureWithWcs, warpingControl)
def testTransformBasedWarp(self): """Test warping using Transform<Point2Endpoint, Point2Endpoint> """ for interpLength in (0, 1, 2, 4): kernelName = "lanczos3" rtol = 4e-5 atol = 1e-2 warpingControl = afwMath.WarpingControl( warpingKernelName=kernelName, interpLength=interpLength, ) originalExposure = afwImage.ExposureF(originalExposurePath) originalMetadata = afwImage.DecoratedImageF( originalExposurePath).getMetadata() originalSkyWcs = afwGeom.SkyWcs(originalMetadata) swarpedImageName = "medswarp1%s.fits" % (kernelName, ) swarpedImagePath = os.path.join(dataDir, swarpedImageName) swarpedDecoratedImage = afwImage.DecoratedImageF(swarpedImagePath) swarpedImage = swarpedDecoratedImage.getImage() swarpedMetadata = swarpedDecoratedImage.getMetadata() warpedSkyWcs = afwGeom.SkyWcs(swarpedMetadata) # warped image is destination, original image is source # and WCS computes pixels to sky in the forward direction, so... destToSrc = warpedSkyWcs.then(originalSkyWcs.getInverse()) afwWarpedMaskedImage = afwImage.MaskedImageF( swarpedImage.getDimensions()) originalMaskedImage = originalExposure.getMaskedImage() numGoodPix = afwMath.warpImage(afwWarpedMaskedImage, originalMaskedImage, destToSrc, warpingControl) self.assertGreater(numGoodPix, 50) afwWarpedImage = afwWarpedMaskedImage.getImage() afwWarpedImageArr = afwWarpedImage.getArray() noDataMaskArr = np.isnan(afwWarpedImageArr) self.assertImagesAlmostEqual(afwWarpedImage, swarpedImage, skipMask=noDataMaskArr, rtol=rtol, atol=atol)
def testTransformBasedWarp(self): """Test warping using TransformPoint2ToPoint2 """ for interpLength in (0, 1, 2, 4): kernelName = "lanczos3" rtol = 4e-5 atol = 1e-2 warpingControl = afwMath.WarpingControl( warpingKernelName=kernelName, interpLength=interpLength, ) originalExposure = afwImage.ExposureF(originalExposurePath) originalMetadata = afwImage.DecoratedImageF( originalExposurePath).getMetadata() originalSkyWcs = afwGeom.makeSkyWcs(originalMetadata) swarpedImageName = f"medswarp1{kernelName}.fits" swarpedImagePath = os.path.join(dataDir, swarpedImageName) swarpedDecoratedImage = afwImage.DecoratedImageF(swarpedImagePath) swarpedImage = swarpedDecoratedImage.getImage() swarpedMetadata = swarpedDecoratedImage.getMetadata() warpedSkyWcs = afwGeom.makeSkyWcs(swarpedMetadata) # original image is source, warped image is destination srcToDest = afwGeom.makeWcsPairTransform(originalSkyWcs, warpedSkyWcs) afwWarpedMaskedImage = afwImage.MaskedImageF( swarpedImage.getDimensions()) originalMaskedImage = originalExposure.getMaskedImage() numGoodPix = afwMath.warpImage(afwWarpedMaskedImage, originalMaskedImage, srcToDest, warpingControl) self.assertGreater(numGoodPix, 50) afwWarpedImage = afwWarpedMaskedImage.getImage() afwWarpedImageArr = afwWarpedImage.getArray() noDataMaskArr = np.isnan(afwWarpedImageArr) self.assertImagesAlmostEqual(afwWarpedImage, swarpedImage, skipMask=noDataMaskArr, rtol=rtol, atol=atol)
def testWarpIntoSelf(self, interpLength=10): """Cannot warp in-place """ wcs = afwGeom.makeSkyWcs( crpix=afwGeom.Point2D(0, 0), crval=afwGeom.SpherePoint(359, 0, afwGeom.degrees), cdMatrix=afwGeom.makeCdMatrix(1.0e-8*afwGeom.degrees), ) exposure = afwImage.ExposureF(afwGeom.Extent2I(100, 100), wcs) maskedImage = exposure.getMaskedImage() warpingControl = afwMath.WarpingControl( "bilinear", "", 0, interpLength) with self.assertRaises(pexExcept.InvalidParameterError): afwMath.warpExposure(exposure, exposure, warpingControl) with self.assertRaises(pexExcept.InvalidParameterError): afwMath.warpImage(maskedImage, wcs, maskedImage, wcs, warpingControl) with self.assertRaises(pexExcept.InvalidParameterError): afwMath.warpImage(maskedImage.getImage(), wcs, maskedImage.getImage(), wcs, warpingControl)
def testNullWarpImage(self, interpLength=10): """Test that warpImage maps an image onto itself. """ originalExposure = afwImage.ExposureF(originalExposurePath) afwWarpedExposure = afwImage.ExposureF(originalExposurePath) originalImage = originalExposure.getMaskedImage().getImage() afwWarpedImage = afwWarpedExposure.getMaskedImage().getImage() originalWcs = originalExposure.getWcs() afwWarpedWcs = afwWarpedExposure.getWcs() warpingControl = afwMath.WarpingControl( "lanczos4", "", 0, interpLength) afwMath.warpImage(afwWarpedImage, afwWarpedWcs, originalImage, originalWcs, warpingControl) if SAVE_FITS_FILES: afwWarpedImage.writeFits("afwWarpedImageNull.fits") afwWarpedImageArr = afwWarpedImage.getArray() noDataMaskArr = np.isnan(afwWarpedImageArr) # relax specs a bit because of minor noise introduced by bad pixels msg = "afw null-warped Image" self.assertImagesAlmostEqual(originalImage, afwWarpedImage, skipMask=noDataMaskArr, atol=1e-5, msg=msg)
def testTicket2441(self): """Test ticket 2441: warpExposure sometimes mishandles zero-extent dest exposures""" fromWcs = afwGeom.makeSkyWcs( crpix=afwGeom.Point2D(0, 0), crval=afwGeom.SpherePoint(359, 0, afwGeom.degrees), cdMatrix=afwGeom.makeCdMatrix(scale=1.0e-8*afwGeom.degrees), ) fromExp = afwImage.ExposureF(afwImage.MaskedImageF(10, 10), fromWcs) toWcs = afwGeom.makeSkyWcs( crpix=afwGeom.Point2D(410000, 11441), crval=afwGeom.SpherePoint(45, 0, afwGeom.degrees), cdMatrix=afwGeom.makeCdMatrix(scale=0.00011*afwGeom.degrees, flipX=True), projection="CEA", ) toExp = afwImage.ExposureF(afwImage.MaskedImageF(0, 0), toWcs) warpControl = afwMath.WarpingControl("lanczos3") # if a bug described in ticket #2441 is present, this will raise an # exception: numGoodPix = afwMath.warpExposure(toExp, fromExp, warpControl) self.assertEqual(numGoodPix, 0)
def testNullWcs(self, interpLength=10): """Cannot warp from or into an exposure without a Wcs. """ exposureWithWcs = afwImage.ExposureF(originalExposurePath) mi = exposureWithWcs.getMaskedImage() exposureWithoutWcs = afwImage.ExposureF(mi.getDimensions()) warpingControl = afwMath.WarpingControl("bilinear", "", 0, interpLength) try: afwMath.warpExposure(exposureWithWcs, exposureWithoutWcs, warpingControl) self.fail( "warping from a source Exception with no Wcs should fail") except Exception: pass try: afwMath.warpExposure(exposureWithoutWcs, exposureWithWcs, warpingControl) self.fail( "warping into a destination Exception with no Wcs should fail") except Exception: pass
def testNullWarpImage(self, interpLength=10): """Test that warpImage maps an image onto itself. """ originalExposure = afwImage.ExposureF(originalExposurePath) afwWarpedExposure = afwImage.ExposureF(originalExposurePath) originalImage = originalExposure.getMaskedImage().getImage() afwWarpedImage = afwWarpedExposure.getMaskedImage().getImage() originalWcs = originalExposure.getWcs() afwWarpedWcs = afwWarpedExposure.getWcs() warpingControl = afwMath.WarpingControl("lanczos4", "", 0, interpLength) afwMath.warpImage(afwWarpedImage, afwWarpedWcs, originalImage, originalWcs, warpingControl) if SAVE_FITS_FILES: afwWarpedImage.writeFits("afwWarpedImageNull.fits") afwWarpedImageArr = afwWarpedImage.getArray() edgeMaskArr = numpy.isnan(afwWarpedImageArr) originalImageArr = originalImage.getArray() # relax specs a bit because of minor noise introduced by bad pixels errStr = imageTestUtils.imagesDiffer(originalImageArr, originalImageArr, skipMaskArr=edgeMaskArr) if errStr: self.fail("afw null-warped Image: %s" % (errStr, ))
def compareToSwarp(self, kernelName, useWarpExposure=True, useSubregion=False, useDeepCopy=False, interpLength=10, cacheSize=100000, rtol=4e-05, atol=1e-2): """Compare warpExposure to swarp for given warping kernel. Note that swarp only warps the image plane, so only test that plane. Inputs: - kernelName: name of kernel in the form used by afwImage.makeKernel - useWarpExposure: if True, call warpExposure to warp an ExposureF, else call warpImage to warp an ImageF and also call the Transform version - useSubregion: if True then the original source exposure (from which the usual test exposure was extracted) is read and the correct subregion extracted - useDeepCopy: if True then the copy of the subimage is a deep copy, else it is a shallow copy; ignored if useSubregion is False - interpLength: interpLength argument for lsst.afw.math.WarpingControl - cacheSize: cacheSize argument for lsst.afw.math.WarpingControl; 0 disables the cache 10000 gives some speed improvement but less accurate results (atol must be increased) 100000 gives better accuracy but no speed improvement in this test - rtol: relative tolerance as used by np.allclose - atol: absolute tolerance as used by np.allclose """ warpingControl = afwMath.WarpingControl( kernelName, "", # there is no point to a separate mask kernel since we aren't testing the mask plane cacheSize, interpLength, ) if useSubregion: originalFullExposure = afwImage.ExposureF(originalExposurePath) # "medsub" is a subregion of med starting at 0-indexed pixel (40, 150) of size 145 x 200 bbox = lsst.geom.Box2I(lsst.geom.Point2I(40, 150), lsst.geom.Extent2I(145, 200)) originalExposure = afwImage.ExposureF(originalFullExposure, bbox, afwImage.LOCAL, useDeepCopy) swarpedImageName = f"medsubswarp1{kernelName}.fits" else: originalExposure = afwImage.ExposureF(originalExposurePath) swarpedImageName = f"medswarp1{kernelName}.fits" swarpedImagePath = os.path.join(dataDir, swarpedImageName) swarpedDecoratedImage = afwImage.DecoratedImageF(swarpedImagePath) swarpedImage = swarpedDecoratedImage.getImage() swarpedMetadata = swarpedDecoratedImage.getMetadata() warpedWcs = afwGeom.makeSkyWcs(swarpedMetadata) if useWarpExposure: # path for saved afw-warped image afwWarpedImagePath = f"afwWarpedExposure1{kernelName}.fits" afwWarpedMaskedImage = afwImage.MaskedImageF( swarpedImage.getDimensions()) afwWarpedExposure = afwImage.ExposureF(afwWarpedMaskedImage, warpedWcs) afwMath.warpExposure(afwWarpedExposure, originalExposure, warpingControl) afwWarpedMask = afwWarpedMaskedImage.getMask() if SAVE_FITS_FILES: afwWarpedExposure.writeFits(afwWarpedImagePath) if display: afwDisplay.Display(frame=1).mtv(afwWarpedExposure, title="Warped") swarpedMaskedImage = afwImage.MaskedImageF(swarpedImage) if display: afwDisplay.Display(frame=2).mtv(swarpedMaskedImage, title="SWarped") msg = f"afw and swarp {kernelName}-warped differ (ignoring bad pixels)" try: self.assertMaskedImagesAlmostEqual(afwWarpedMaskedImage, swarpedMaskedImage, doImage=True, doMask=False, doVariance=False, skipMask=afwWarpedMask, rtol=rtol, atol=atol, msg=msg) except Exception: if SAVE_FAILED_FITS_FILES: afwWarpedExposure.writeFits(afwWarpedImagePath) print( f"Saved failed afw-warped exposure as: {afwWarpedImagePath}" ) raise else: # path for saved afw-warped image afwWarpedImagePath = f"afwWarpedImage1{kernelName}.fits" afwWarpedImage2Path = f"afwWarpedImage1{kernelName}_xyTransform.fits" afwWarpedImage = afwImage.ImageF(swarpedImage.getDimensions()) originalImage = originalExposure.getMaskedImage().getImage() originalWcs = originalExposure.getWcs() afwMath.warpImage(afwWarpedImage, warpedWcs, originalImage, originalWcs, warpingControl) if display: afwDisplay.Display(frame=1).mtv(afwWarpedImage, title="Warped") afwDisplay.Display(frame=2).mtv(swarpedImage, title="SWarped") diff = swarpedImage.Factory(swarpedImage, True) diff -= afwWarpedImage afwDisplay.Display(frame=3).mtv(diff, title="swarp - afw") if SAVE_FITS_FILES: afwWarpedImage.writeFits(afwWarpedImagePath) afwWarpedImageArr = afwWarpedImage.getArray() noDataMaskArr = np.isnan(afwWarpedImageArr) msg = f"afw and swarp {kernelName}-warped images do not match (ignoring NaN pixels)" try: self.assertImagesAlmostEqual(afwWarpedImage, swarpedImage, skipMask=noDataMaskArr, rtol=rtol, atol=atol, msg=msg) except Exception: if SAVE_FAILED_FITS_FILES: # save the image anyway afwWarpedImage.writeFits(afwWarpedImagePath) print( f"Saved failed afw-warped image as: {afwWarpedImagePath}" ) raise afwWarpedImage2 = afwImage.ImageF(swarpedImage.getDimensions()) srcToDest = afwGeom.makeWcsPairTransform(originalWcs, warpedWcs) afwMath.warpImage(afwWarpedImage2, originalImage, srcToDest, warpingControl) msg = f"afw transform-based and WCS-based {kernelName}-warped images do not match" try: self.assertImagesAlmostEqual(afwWarpedImage2, afwWarpedImage, rtol=rtol, atol=atol, msg=msg) except Exception: if SAVE_FAILED_FITS_FILES: # save the image anyway afwWarpedImage.writeFits(afwWarpedImage2) print( f"Saved failed afw-warped image as: {afwWarpedImage2Path}" ) raise
def verifyMaskWarp(self, kernelName, maskKernelName, growFullMask, interpLength=10, cacheSize=100000, rtol=4e-05, atol=1e-2): """Verify that using a separate mask warping kernel produces the correct results Inputs: - kernelName: name of warping kernel in the form used by afwImage.makeKernel - maskKernelName: name of mask warping kernel in the form used by afwImage.makeKernel - interpLength: interpLength argument for lsst.afw.math.WarpingControl - cacheSize: cacheSize argument for lsst.afw.math.WarpingControl; 0 disables the cache 10000 gives some speed improvement but less accurate results (atol must be increased) 100000 gives better accuracy but no speed improvement in this test - rtol: relative tolerance as used by numpy.allclose - atol: absolute tolerance as used by numpy.allclose """ srcWcs = makeWcs( pixelScale=afwGeom.Angle(0.2, afwGeom.degrees), crPixPos=(10.0, 11.0), crValCoord=afwCoord.IcrsCoord(afwGeom.Point2D(41.7, 32.9), afwGeom.degrees), ) destWcs = makeWcs( pixelScale=afwGeom.Angle(0.17, afwGeom.degrees), crPixPos=(9.0, 10.0), crValCoord=afwCoord.IcrsCoord(afwGeom.Point2D(41.65, 32.95), afwGeom.degrees), posAng=afwGeom.Angle(31, afwGeom.degrees), ) srcMaskedImage = afwImage.MaskedImageF(100, 101) srcExposure = afwImage.ExposureF(srcMaskedImage, srcWcs) destMaskedImage = afwImage.MaskedImageF(110, 121) destExposure = afwImage.ExposureF(destMaskedImage, destWcs) srcArrays = srcMaskedImage.getArrays() shape = srcArrays[0].shape numpy.random.seed(0) srcArrays[0][:] = numpy.random.normal(10000, 1000, size=shape) srcArrays[2][:] = numpy.random.normal(9000, 900, size=shape) srcArrays[1][:] = numpy.reshape( numpy.arange(0, shape[0] * shape[1], 1, dtype=numpy.uint16), shape) warpControl = afwMath.WarpingControl(kernelName, maskKernelName, cacheSize, interpLength, afwGpu.DEFAULT_DEVICE_PREFERENCE, growFullMask) afwMath.warpExposure(destExposure, srcExposure, warpControl) afwArrays = [ numpy.copy(arr) for arr in destExposure.getMaskedImage().getArrays() ] # now compute with two separate mask planes warpControl.setGrowFullMask(0) afwMath.warpExposure(destExposure, srcExposure, warpControl) narrowArrays = [ numpy.copy(arr) for arr in destExposure.getMaskedImage().getArrays() ] warpControl.setMaskWarpingKernelName("") afwMath.warpExposure(destExposure, srcExposure, warpControl) broadArrays = [ numpy.copy(arr) for arr in destExposure.getMaskedImage().getArrays() ] if (kernelName != maskKernelName) and (growFullMask != 0xFFFF): # we expect the mask planes to differ if numpy.allclose(broadArrays[1], narrowArrays[1]): self.fail("No difference between broad and narrow mask") predMask = (broadArrays[1] & growFullMask) | (narrowArrays[1] & ~growFullMask) predArraySet = (broadArrays[0], predMask, broadArrays[2]) errStr = imageTestUtils.maskedImagesDiffer(afwArrays, predArraySet, doImage=True, doMask=True, doVariance=True, rtol=rtol, atol=atol) if errStr: self.fail("Separate mask warping failed; warpingKernel=%s; maskWarpingKernel=%s; error=%s" % \ (kernelName, maskKernelName, errStr))
def compareToSwarp(self, kernelName, useWarpExposure=True, useSubregion=False, useDeepCopy=False, interpLength=10, cacheSize=100000, rtol=4e-05, atol=1e-2): """Compare warpExposure to swarp for given warping kernel. Note that swarp only warps the image plane, so only test that plane. Inputs: - kernelName: name of kernel in the form used by afwImage.makeKernel - useWarpExposure: if True, call warpExposure to warp an ExposureF, else call warpImage to warp an ImageF - useSubregion: if True then the original source exposure (from which the usual test exposure was extracted) is read and the correct subregion extracted - useDeepCopy: if True then the copy of the subimage is a deep copy, else it is a shallow copy; ignored if useSubregion is False - interpLength: interpLength argument for lsst.afw.math.WarpingControl - cacheSize: cacheSize argument for lsst.afw.math.WarpingControl; 0 disables the cache 10000 gives some speed improvement but less accurate results (atol must be increased) 100000 gives better accuracy but no speed improvement in this test - rtol: relative tolerance as used by numpy.allclose - atol: absolute tolerance as used by numpy.allclose """ warpingControl = afwMath.WarpingControl( kernelName, "", # there is no point to a separate mask kernel since we aren't testing the mask plane cacheSize, interpLength, ) if useSubregion: originalFullExposure = afwImage.ExposureF(originalExposurePath) # "medsub" is a subregion of med starting at 0-indexed pixel (40, 150) of size 145 x 200 bbox = afwGeom.Box2I(afwGeom.Point2I(40, 150), afwGeom.Extent2I(145, 200)) originalExposure = afwImage.ExposureF(originalFullExposure, bbox, afwImage.LOCAL, useDeepCopy) swarpedImageName = "medsubswarp1%s.fits" % (kernelName, ) else: originalExposure = afwImage.ExposureF(originalExposurePath) swarpedImageName = "medswarp1%s.fits" % (kernelName, ) swarpedImagePath = os.path.join(dataDir, swarpedImageName) swarpedDecoratedImage = afwImage.DecoratedImageF(swarpedImagePath) swarpedImage = swarpedDecoratedImage.getImage() swarpedMetadata = swarpedDecoratedImage.getMetadata() warpedWcs = afwImage.makeWcs(swarpedMetadata) if useWarpExposure: # path for saved afw-warped image afwWarpedImagePath = "afwWarpedExposure1%s" % (kernelName, ) afwWarpedMaskedImage = afwImage.MaskedImageF( swarpedImage.getDimensions()) afwWarpedExposure = afwImage.ExposureF(afwWarpedMaskedImage, warpedWcs) afwMath.warpExposure(afwWarpedExposure, originalExposure, warpingControl) if SAVE_FITS_FILES: afwWarpedExposure.writeFits(afwWarpedImagePath) if display: ds9.mtv(afwWarpedExposure, frame=1, title="Warped") afwWarpedMask = afwWarpedMaskedImage.getMask() edgeBitMask = afwWarpedMask.getPlaneBitMask("EDGE") if edgeBitMask == 0: self.fail("warped mask has no EDGE bit") afwWarpedMaskedImageArrSet = afwWarpedMaskedImage.getArrays() afwWarpedMaskArr = afwWarpedMaskedImageArrSet[1] swarpedMaskedImage = afwImage.MaskedImageF(swarpedImage) swarpedMaskedImageArrSet = swarpedMaskedImage.getArrays() if display: ds9.mtv(swarpedMaskedImage, frame=2, title="SWarped") errStr = imageTestUtils.maskedImagesDiffer( afwWarpedMaskedImageArrSet, swarpedMaskedImageArrSet, doImage=True, doMask=False, doVariance=False, skipMaskArr=afwWarpedMaskArr, rtol=rtol, atol=atol) if errStr: if SAVE_FAILED_FITS_FILES: afwWarpedExposure.writeFits(afwWarpedImagePath) print "Saved failed afw-warped exposure as: %s" % ( afwWarpedImagePath, ) self.fail("afw and swarp %s-warped %s (ignoring bad pixels)" % (kernelName, errStr)) else: # path for saved afw-warped image afwWarpedImagePath = "afwWarpedImage1%s.fits" % (kernelName, ) afwWarpedImage = afwImage.ImageF(swarpedImage.getDimensions()) originalImage = originalExposure.getMaskedImage().getImage() originalWcs = originalExposure.getWcs() afwMath.warpImage(afwWarpedImage, warpedWcs, originalImage, originalWcs, warpingControl) if display: ds9.mtv(afwWarpedImage, frame=1, title="Warped") ds9.mtv(swarpedImage, frame=2, title="SWarped") diff = swarpedImage.Factory(swarpedImage, True) diff -= afwWarpedImage ds9.mtv(diff, frame=3, title="swarp - afw") if SAVE_FITS_FILES: afwWarpedImage.writeFits(afwWarpedImagePath) afwWarpedImageArr = afwWarpedImage.getArray() swarpedImageArr = swarpedImage.getArray() edgeMaskArr = numpy.isnan(afwWarpedImageArr) errStr = imageTestUtils.imagesDiffer(afwWarpedImageArr, swarpedImageArr, skipMaskArr=edgeMaskArr, rtol=rtol, atol=atol) if errStr: if SAVE_FAILED_FITS_FILES: # save the image anyway afwWarpedImage.writeFits(afwWarpedImagePath) print "Saved failed afw-warped image as: %s" % ( afwWarpedImagePath, ) self.fail("afw and swarp %s-warped images do not match (ignoring NaN pixels): %s" % \ (kernelName, errStr))
def testNullWarpExposure(self, interpLength=10): """Test that warpExposure maps an image onto itself. Note: - edge pixels must be ignored - bad mask pixels get smeared out so we have to excluded all bad mask pixels from the output image when comparing masks. """ filterPolicyFile = pexPolicy.DefaultPolicyFile("afw", "SdssFilters.paf", "tests") filterPolicy = pexPolicy.Policy.createPolicy( filterPolicyFile, filterPolicyFile.getRepositoryPath(), True) imageUtils.defineFiltersFromPolicy(filterPolicy, reset=True) originalExposure = afwImage.ExposureF(originalExposurePath) originalFilter = afwImage.Filter("i") originalCalib = afwImage.Calib() originalCalib.setFluxMag0(1.0e5, 1.0e3) originalExposure.setFilter(originalFilter) originalExposure.setCalib(originalCalib) afwWarpedExposure = afwImage.ExposureF(originalExposure.getBBox(), originalExposure.getWcs()) warpingControl = afwMath.WarpingControl("lanczos4", "", 0, interpLength) afwMath.warpExposure(afwWarpedExposure, originalExposure, warpingControl) if SAVE_FITS_FILES: afwWarpedExposure.writeFits("afwWarpedExposureNull.fits") self.assertEquals(afwWarpedExposure.getFilter().getName(), originalFilter.getName()) self.assertEquals(afwWarpedExposure.getCalib().getFluxMag0(), originalCalib.getFluxMag0()) afwWarpedMaskedImage = afwWarpedExposure.getMaskedImage() afwWarpedMask = afwWarpedMaskedImage.getMask() edgeBitMask = afwWarpedMask.getPlaneBitMask("EDGE") if edgeBitMask == 0: self.fail("warped mask has no EDGE bit") afwWarpedMaskedImageArrSet = afwWarpedMaskedImage.getArrays() afwWarpedMaskArr = afwWarpedMaskedImageArrSet[1] # compare all non-edge pixels of image and variance, but relax specs a bit # because of minor noise introduced by bad pixels edgeMaskArr = afwWarpedMaskArr & edgeBitMask originalMaskedImageArrSet = originalExposure.getMaskedImage( ).getArrays() errStr = imageTestUtils.maskedImagesDiffer(afwWarpedMaskedImageArrSet, originalMaskedImageArrSet, doMask=False, skipMaskArr=edgeMaskArr, atol=1e-5) if errStr: self.fail( "afw null-warped MaskedImage (all pixels, relaxed tolerance): %s" % (errStr, )) # compare good pixels of image, mask and variance using full tolerance errStr = imageTestUtils.maskedImagesDiffer( afwWarpedMaskedImageArrSet, originalMaskedImageArrSet, doImage=False, doVariance=False, skipMaskArr=afwWarpedMaskArr) if errStr: self.fail( "afw null-warped MaskedImage (good pixels, max tolerance): %s" % (errStr, ))
def verifyMaskWarp(self, kernelName, maskKernelName, growFullMask, interpLength=10, cacheSize=100000, rtol=4e-05, atol=1e-2): """Verify that using a separate mask warping kernel produces the correct results Inputs: - kernelName: name of warping kernel in the form used by afwImage.makeKernel - maskKernelName: name of mask warping kernel in the form used by afwImage.makeKernel - interpLength: interpLength argument for lsst.afw.math.WarpingControl - cacheSize: cacheSize argument for lsst.afw.math.WarpingControl; 0 disables the cache 10000 gives some speed improvement but less accurate results (atol must be increased) 100000 gives better accuracy but no speed improvement in this test - rtol: relative tolerance as used by np.allclose - atol: absolute tolerance as used by np.allclose """ srcWcs = afwGeom.makeSkyWcs( crpix=lsst.geom.Point2D(10, 11), crval=lsst.geom.SpherePoint(41.7, 32.9, lsst.geom.degrees), cdMatrix=afwGeom.makeCdMatrix(scale=0.2 * lsst.geom.degrees), ) destWcs = afwGeom.makeSkyWcs( crpix=lsst.geom.Point2D(9, 10), crval=lsst.geom.SpherePoint(41.65, 32.95, lsst.geom.degrees), cdMatrix=afwGeom.makeCdMatrix(scale=0.17 * lsst.geom.degrees), ) srcMaskedImage = afwImage.MaskedImageF(100, 101) srcExposure = afwImage.ExposureF(srcMaskedImage, srcWcs) srcArrays = srcMaskedImage.getArrays() shape = srcArrays[0].shape srcArrays[0][:] = np.random.normal(10000, 1000, size=shape) srcArrays[2][:] = np.random.normal(9000, 900, size=shape) srcArrays[1][:] = np.reshape( np.arange(0, shape[0] * shape[1], 1, dtype=np.uint16), shape) warpControl = afwMath.WarpingControl(kernelName, maskKernelName, cacheSize, interpLength, growFullMask) destMaskedImage = afwImage.MaskedImageF(110, 121) destExposure = afwImage.ExposureF(destMaskedImage, destWcs) afwMath.warpExposure(destExposure, srcExposure, warpControl) # now compute with two separate mask planes warpControl.setGrowFullMask(0) narrowMaskedImage = afwImage.MaskedImageF(110, 121) narrowExposure = afwImage.ExposureF(narrowMaskedImage, destWcs) afwMath.warpExposure(narrowExposure, srcExposure, warpControl) narrowArrays = narrowExposure.getMaskedImage().getArrays() warpControl.setMaskWarpingKernelName("") broadMaskedImage = afwImage.MaskedImageF(110, 121) broadExposure = afwImage.ExposureF(broadMaskedImage, destWcs) afwMath.warpExposure(broadExposure, srcExposure, warpControl) broadArrays = broadExposure.getMaskedImage().getArrays() if (kernelName != maskKernelName) and (growFullMask != 0xFFFF): # we expect the mask planes to differ if np.all(narrowArrays[1] == broadArrays[1]): self.fail("No difference between broad and narrow mask") predMask = (broadArrays[1] & growFullMask) | ( narrowArrays[1] & ~growFullMask).astype(np.uint16) predArraySet = (broadArrays[0], predMask, broadArrays[2]) predExposure = afwImage.makeMaskedImageFromArrays(*predArraySet) msg = f"Separate mask warping failed; warpingKernel={kernelName}; maskWarpingKernel={maskKernelName}" self.assertMaskedImagesAlmostEqual(destExposure.getMaskedImage(), predExposure, doImage=True, doMask=True, doVariance=True, rtol=rtol, atol=atol, msg=msg)
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 run(): if len(sys.argv) < 2: srcExposure = afwImage.ExposureF(InputExposurePath) if WarpSubregion: bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(2000, 2000)) srcExposure = afwImage.ExposureF(srcExposure, bbox, afwImage.LOCAL, False) else: srcExposure = afwImage.ExposureF(sys.argv[1]) srcWcs = srcExposure.getWcs() srcDim = srcExposure.getDimensions() srcCtrInd = [int(d / 2) for d in srcDim] # make the destination exposure small enough that even after rotation and offset # (by reasonable amounts) there are no edge pixels destDim = afwGeom.Extent2I(*[int(sd * 0.5) for sd in srcDim]) destExposure = afwImage.ExposureF(destDim) destCtrInd = [int(d / 2) for d in destDim] maskKernelName = "" cacheSize = 0 print("Warping", InputExposurePath) print("Source (sub)image size:", srcDim) print("Destination image size:", destDim) print() print( "test# interp scaleFac skyOffset rotAng kernel goodPix time/iter" ) print( ' (pix) (RA, Dec ") (deg) (sec)' ) testNum = 1 for interpLength in (0, 1, 5, 10): for scaleFac in (1.2, ): # (1.0, 1.5): # ((0.0, 0.0), (10.5, -5.5)): for skyOffsetArcSec in ((0.0, 0.0), ): skyOffset = [so / 3600.0 for so in skyOffsetArcSec] for rotAng, kernelName in ( (0.0, "bilinear"), (0.0, "lanczos2"), (0.0, "lanczos3"), (45.0, "lanczos3"), ): warpingControl = afwMath.WarpingControl( kernelName, maskKernelName, cacheSize, interpLength, ) destWcs = makeWcs( projName="TAN", destCtrInd=destCtrInd, skyOffset=skyOffset, rotAng=rotAng, scaleFac=scaleFac, srcWcs=srcWcs, srcCtrInd=srcCtrInd, ) destExposure.setWcs(destWcs) dTime, nIter, goodPix = timeWarp(destExposure, srcExposure, warpingControl) print( "%4d %5d %8.1f %6.1f, %6.1f %7.1f %10s %8d %6.2f" % (testNum, interpLength, scaleFac, skyOffsetArcSec[0], skyOffsetArcSec[1], rotAng, kernelName, goodPix, dTime / float(nIter))) if SaveImages: destExposure.writeFits("warpedExposure%03d.fits" % (testNum, )) testNum += 1
def run(): if len(sys.argv) < 2: srcExposure = afwImage.ExposureF(InputExposurePath) if WarpSubregion: bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(2000, 2000)) srcExposure = afwImage.ExposureF(srcExposure, bbox, afwImage.LOCAL, False) else: srcExposure = afwImage.ExposureF(sys.argv[1]) srcMaskedImage = srcExposure.getMaskedImage() srcMetadata = afwImage.DecoratedImageF(InputExposurePath).getMetadata() srcWcs = afwGeom.SkyWcs(srcMetadata) srcDim = srcExposure.getDimensions() srcCtrPos = afwGeom.Box2D(srcMaskedImage.getBBox()).getCenter() srcCtrSky = srcWcs.applyForward(srcCtrPos) srcScale = srcWcs.getPixelScale() # make the destination exposure small enough that even after rotation and offset # (by reasonable amounts) there are no edge pixels destDim = afwGeom.Extent2I(*[int(sd * 0.5) for sd in srcDim]) destMaskedImage = afwImage.MaskedImageF(destDim) destCrPix = afwGeom.Box2D(destMaskedImage.getBBox()).getCenter() maskKernelName = "" cacheSize = 0 print("Warping", InputExposurePath) print("Source (sub)image size:", srcDim) print("Destination image size:", destDim) print() print( "test# interp scaleFac destSkyOff rotAng kernel goodPix time/iter" ) print( ' (pix) (bear°, len") (deg) (sec)' ) testNum = 1 for interpLength in (0, 1, 5, 10): for scaleFac in (1.2, ): destScale = srcScale / scaleFac for offsetOrientDegLenArcsec in (( 0.0, 0.0), ): # ((0.0, 0.0), (-35.0, 10.5)): # offset (bearing, length) from sky at center of source to sky at center of dest offset = (offsetOrientDegLenArcsec[0] * afwGeom.degrees, offsetOrientDegLenArcsec[1] * afwGeom.arcseconds) destCtrSky = srcCtrSky.offset(*offset) for rotAngDeg, kernelName in ( (0.0, "bilinear"), (0.0, "lanczos2"), (0.0, "lanczos3"), (45.0, "lanczos3"), ): warpingControl = afwMath.WarpingControl( kernelName, maskKernelName, cacheSize, interpLength, ) destWcs = afwGeom.SkyWcs( crpix=destCrPix, crval=destCtrSky, cdMatrix=afwGeom.makeCdMatrix(scale=destScale, orientation=rotAngDeg * afwGeom.degrees, flipX=False)) destToSrc = destWcs.then(srcWcs.getInverse()) dTime, nIter, goodPix = timeWarp(destMaskedImage, srcMaskedImage, destToSrc, warpingControl) print( "%4d %5d %8.1f %6.1f, %6.1f %7.1f %10s %8d %6.2f" % (testNum, interpLength, scaleFac, offsetOrientDegLenArcsec[0], offsetOrientDegLenArcsec[1], rotAngDeg, kernelName, goodPix, dTime / float(nIter))) if SaveImages: destMaskedImage.writeFits( "warpedMaskedImage%03d.fits" % (testNum, )) testNum += 1