def testNullWarpExposure(self, interpLength=10): """Test that warpExposure maps an image onto itself. Note: - edge 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.assertEquals(afwWarpedExposure.getFilter().getName(), originalFilter.getName()) self.assertEquals(afwWarpedExposure.getCalib().getFluxMag0(), originalCalib.getFluxMag0()) afwWarpedMaskedImage = afwWarpedExposure.getMaskedImage() afwWarpedMask = afwWarpedMaskedImage.getMask() edgeBitMask = afwWarpedMask.getPlaneBitMask("EDGE") noDataBitMask = afwWarpedMask.getPlaneBitMask("NO_DATA") if edgeBitMask == 0: self.fail("warped mask has no EDGE bit") if noDataBitMask == 0: self.fail("warped mask has no NO_DATA 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 maskArr = afwWarpedMaskArr & (edgeBitMask | noDataBitMask) originalMaskedImageArrSet = originalExposure.getMaskedImage().getArrays() errStr = imageTestUtils.maskedImagesDiffer(afwWarpedMaskedImageArrSet, originalMaskedImageArrSet, doMask=False, skipMaskArr=maskArr, 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 testUnityConvolution(self): """Verify that convolution with a centered delta function reproduces the original. """ # create a delta function kernel that has 1,1 in the center kFunc = afwMath.IntegerDeltaFunction2D(0.0, 0.0) kernel = afwMath.AnalyticKernel(3, 3, kFunc) doNormalize = False doCopyEdge = False afwMath.convolve(self.cnvImage, self.maskedImage.getImage(), kernel, doNormalize, doCopyEdge) cnvImArr = self.cnvImage.getArray() afwMath.convolve(self.cnvMaskedImage, self.maskedImage, kernel, doNormalize, doCopyEdge) cnvImMaskVarArr = self.cnvMaskedImage.getArrays() refCnvImMaskVarArr = self.maskedImage.getArrays() skipMaskArr = numpy.isnan(cnvImMaskVarArr[0]) kernelDescr = "Centered DeltaFunctionKernel (testing unity convolution)" errStr = imTestUtils.imagesDiffer(cnvImArr, refCnvImMaskVarArr[0], skipMaskArr=skipMaskArr) if errStr: self.fail("convolve(Image, kernel=%s, doNormalize=%s, doCopyEdge=%s) failed:\n%s" % \ (kernelDescr, doNormalize, doCopyEdge, errStr)) errStr = imTestUtils.maskedImagesDiffer(cnvImMaskVarArr, refCnvImMaskVarArr, skipMaskArr=skipMaskArr) if errStr: self.fail("convolve(MaskedImage, kernel=%s, doNormalize=%s, doCopyEdge=%s) failed:\n%s" % \ (kernelDescr, doNormalize, doCopyEdge, errStr)) self.assert_(sameMaskPlaneDicts(self.cnvMaskedImage, self.maskedImage), "convolve(MaskedImage, kernel=%s, doNormalize=%s, doCopyEdge=%s) failed:\n%s" % \ (kernelDescr, doNormalize, doCopyEdge, "convolved mask dictionary does not match input"))
def runBasicConvolveEdgeTest(self, kernel, kernelDescr): """Verify that basicConvolve does not write to edge pixels for this kind of kernel """ fullBox = afwGeom.Box2I( afwGeom.Point2I(0, 0), ShiftedBBox.getDimensions(), ) goodBox = kernel.shrinkBBox(fullBox) cnvMaskedImage = afwImage.MaskedImageF(FullMaskedImage, ShiftedBBox, afwImage.LOCAL, True) cnvMaskedImageCopy = afwImage.MaskedImageF(cnvMaskedImage, fullBox, afwImage.LOCAL, True) cnvMaskedImageCopyViewOfGoodRegion = afwImage.MaskedImageF(cnvMaskedImageCopy, goodBox, afwImage.LOCAL, False) # convolve with basicConvolve, which should leave the edge pixels alone convControl = afwMath.ConvolutionControl() mathDetail.basicConvolve(cnvMaskedImage, self.maskedImage, kernel, convControl) # reset the good region to the original convolved image; # this should reset the entire convolved image to its original self cnvMaskedImageGoodView = afwImage.MaskedImageF(cnvMaskedImage, goodBox, afwImage.LOCAL, False) cnvMaskedImageGoodView <<= cnvMaskedImageCopyViewOfGoodRegion # assert that these two are equal cnvImMaskVarArr = cnvMaskedImage.getArrays() desCnvImMaskVarArr = cnvMaskedImageCopy.getArrays() errStr = imTestUtils.maskedImagesDiffer(cnvImMaskVarArr, desCnvImMaskVarArr, doVariance = True, rtol=0, atol=0) shortKernelDescr = kernelDescr.translate(NullTranslator, GarbageChars) if errStr: cnvMaskedImage.writeFits("actBasicConvolve%s" % (shortKernelDescr,)) cnvMaskedImageCopy.writeFits("desBasicConvolve%s" % (shortKernelDescr,)) self.fail("basicConvolve(MaskedImage, kernel=%s) wrote to edge pixels:\n%s" % \ (kernelDescr, errStr))
def runScaledAddTest(self, coeff0, coeff1): """Run one test of scaledPlus Inputs: - coeff0: coefficient of image 0 - coeff1: coefficient of image 1 """ im0ArrSet = self.maskedImage0.getArrays() im1ArrSet = self.maskedImage1.getArrays() desMaskedImage = afwImage.MaskedImageF(self.maskedImage0.getDimensions()) desMaskedImage <<= self.maskedImage0 desMaskedImage *= coeff0 desMaskedImage.scaledPlus(coeff1, self.maskedImage1) desImArrSet = desMaskedImage.getArrays() actMaskedImage = afwImage.MaskedImageF(afwGeom.Extent2I(self.imWidth, self.imHeight)) afwMath.randomUniformImage(actMaskedImage.getImage(), self.random) afwMath.randomUniformImage(actMaskedImage.getVariance(), self.random) afwMath.scaledPlus(actMaskedImage, coeff0, self.maskedImage0, coeff1, self.maskedImage1) actImArrSet = actMaskedImage.getArrays() actImage = afwImage.ImageF(afwGeom.Extent2I(self.imWidth, self.imHeight)) afwMath.randomUniformImage(actImage, self.random) afwMath.scaledPlus(actImage, coeff0, self.maskedImage0.getImage(), coeff1, self.maskedImage1.getImage()) actImArr = actImage.getArray() errStr = imTestUtils.imagesDiffer(actImArr, desImArrSet[0]) if errStr: self.fail("scaledPlus failed in images; coeff0=%s, coeff1=%s:\n%s" % (coeff0, coeff1, errStr,)) errStr = imTestUtils.maskedImagesDiffer(actImArrSet, desImArrSet) if errStr: self.fail("scaledPlus failed on masked images; coeff0=%s, coeff1=%s:\n%s" % (coeff0, coeff1, errStr,))
def runScaledAddTest(self, coeff0, coeff1): """Run one test of scaledPlus Inputs: - coeff0: coefficient of image 0 - coeff1: coefficient of image 1 """ im0ArrSet = self.maskedImage0.getArrays() im1ArrSet = self.maskedImage1.getArrays() desMaskedImage = afwImage.MaskedImageF( self.maskedImage0.getDimensions()) desMaskedImage <<= self.maskedImage0 desMaskedImage *= coeff0 desMaskedImage.scaledPlus(coeff1, self.maskedImage1) desImArrSet = desMaskedImage.getArrays() actMaskedImage = afwImage.MaskedImageF( afwGeom.Extent2I(self.imWidth, self.imHeight)) afwMath.randomUniformImage(actMaskedImage.getImage(), self.random) afwMath.randomUniformImage(actMaskedImage.getVariance(), self.random) afwMath.scaledPlus(actMaskedImage, coeff0, self.maskedImage0, coeff1, self.maskedImage1) actImArrSet = actMaskedImage.getArrays() actImage = afwImage.ImageF( afwGeom.Extent2I(self.imWidth, self.imHeight)) afwMath.randomUniformImage(actImage, self.random) afwMath.scaledPlus(actImage, coeff0, self.maskedImage0.getImage(), coeff1, self.maskedImage1.getImage()) actImArr = actImage.getArray() errStr = imTestUtils.imagesDiffer(actImArr, desImArrSet[0]) if errStr: self.fail( "scaledPlus failed in images; coeff0=%s, coeff1=%s:\n%s" % ( coeff0, coeff1, errStr, )) errStr = imTestUtils.maskedImagesDiffer(actImArrSet, desImArrSet) if errStr: self.fail( "scaledPlus failed on masked images; coeff0=%s, coeff1=%s:\n%s" % ( coeff0, coeff1, 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. """ originalExposure = afwImage.ExposureF(originalExposurePath) afwWarpedExposure = afwImage.ExposureF(originalExposurePath) warpingKernel = afwMath.LanczosWarpingKernel(4) afwMath.warpExposure(afwWarpedExposure, originalExposure, warpingKernel, interpLength) if SAVE_FITS_FILES: afwWarpedExposure.writeFits("afwWarpedExposureNull") 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 testAdditionAllGood(self): """Test the case where all pixels are valid """ config = SnapCombineTask.ConfigClass() config.doRepair = False config.doDiffIm = False task = SnapCombineTask(config=config) snap0 = makeRandomExposure(25, 25, 10000, 5000, 0) snap1 = makeRandomExposure(25, 25, 10000, 5000, 0) resExp = task.run(snap0, snap1).exposure resMi = resExp.getMaskedImage() predMi = snap0.getMaskedImage().Factory(snap0.getMaskedImage(), True) predMi += snap1.getMaskedImage() errMsg = afwTestUtils.maskedImagesDiffer(resMi.getArrays(), predMi.getArrays()) if errMsg: self.fail(errMsg)
def testAddition(self): """Test addition with bad pixels """ config = SnapCombineTask.ConfigClass() config.doRepair = False config.doDiffIm = False config.badMaskPlanes = ("BAD", "SAT", "NO_DATA", "CR") badPixelMask = afwImage.MaskU.getPlaneBitMask(config.badMaskPlanes) task = SnapCombineTask(config=config) snap0 = makeRandomExposure(25, 25, 10000, 5000, badPixelMask) snap1 = makeRandomExposure(25, 25, 10000, 5000, badPixelMask) resExp = task.run(snap0, snap1).exposure resMi = resExp.getMaskedImage() predExp = simpleAdd(snap0, snap1, badPixelMask) predMi = predExp.getMaskedImage() errMsg = afwTestUtils.maskedImagesDiffer(resMi.getArrays(), predMi.getArrays()) if errMsg: self.fail(errMsg)
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.warpExposure - cacheSize: cacheSize argument for lsst.afw.math.SeparableKernel.computeCache; 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 """ warpingKernel = afwMath.makeWarpingKernel(kernelName) warpingKernel.computeCache(cacheSize) 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, warpingKernel, interpLength) 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, warpingKernel, interpLength) 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 runBasicTest(self, kernel, convControl, refKernel=None, kernelDescr="", rtol=1.0e-05, atol=1e-08): """Assert that afwMath::convolve gives the same result as reference convolution for a given kernel. Inputs: - kernel: convolution kernel - convControl: convolution control parameters (afwMath.ConvolutionControl) - refKernel: kernel to use for refConvolve (if None then kernel is used) - kernelDescr: description of kernel - rtol: relative tolerance (see below) - atol: absolute tolerance (see below) rtol and atol are positive, typically very small numbers. The relative difference (rtol * abs(b)) and the absolute difference "atol" are added together to compare against the absolute difference between "a" and "b". """ if refKernel == None: refKernel = kernel # strip garbage characters (whitespace and punctuation) to make a short description for saving files shortKernelDescr = kernelDescr.translate(NullTranslator, GarbageChars) doNormalize = convControl.getDoNormalize() doCopyEdge = convControl.getDoCopyEdge() maxInterpDist = convControl.getMaxInterpolationDistance() imMaskVar = self.maskedImage.getArrays() xy0 = self.maskedImage.getXY0() refCnvImMaskVarArr = refConvolve(imMaskVar, xy0, refKernel, doNormalize, doCopyEdge) afwMath.convolve(self.cnvImage, self.maskedImage.getImage(), kernel, convControl) self.assertEqual(self.cnvImage.getXY0(), self.xy0) cnvImArr = self.cnvImage.getArray() afwMath.convolve(self.cnvMaskedImage, self.maskedImage, kernel, convControl) cnvImMaskVarArr = self.cnvMaskedImage.getArrays() if display and False: refMaskedImage = afwImage.makeMaskedImageFromArrays(*refCnvImMaskVarArr) ds9.mtv(displayUtils.Mosaic().makeMosaic([ self.maskedImage, refMaskedImage, self.cnvMaskedImage]), frame=0) if False: for (x, y) in ((0, 0), (1, 0), (0, 1), (50, 50)): print "Mask(%d,%d) 0x%x 0x%x" % (x, y, refMaskedImage.getMask().get(x, y), self.cnvMaskedImage.getMask().get(x, y)) errStr = imTestUtils.imagesDiffer(cnvImArr, refCnvImMaskVarArr[0], rtol=rtol, atol=atol) if errStr: self.cnvImage.writeFits("act%s.fits" % (shortKernelDescr,)) refMaskedImage = afwImage.makeMaskedImageFromArrays(*refCnvImMaskVarArr) refMaskedImage.getImage().writeFits("des%s.fits" % (shortKernelDescr,)) self.fail("convolve(Image, kernel=%s, doNormalize=%s, doCopyEdge=%s, maxInterpDist=%s) failed:\n%s" % \ (kernelDescr, doNormalize, doCopyEdge, maxInterpDist, errStr)) errStr = imTestUtils.maskedImagesDiffer(cnvImMaskVarArr, refCnvImMaskVarArr, doVariance = True, rtol=rtol, atol=atol) if errStr: self.cnvMaskedImage.writeFits("act%s" % (shortKernelDescr,)) refMaskedImage = afwImage.makeMaskedImageFromArrays(*refCnvImMaskVarArr) refMaskedImage.writeFits("des%s" % (shortKernelDescr,)) self.fail("convolve(MaskedImage, kernel=%s, doNormalize=%s, doCopyEdge=%s, maxInterpDist=%s) failed:\n%s" % \ (kernelDescr, doNormalize, doCopyEdge, maxInterpDist, errStr)) if not sameMaskPlaneDicts(self.cnvMaskedImage, self.maskedImage): self.cnvMaskedImage.writeFits("act%s" % (shortKernelDescr,)) refMaskedImage = afwImage.makeMaskedImageFromArrays(*refCnvImMaskVarArr) refMaskedImage.writeFits("des%s" % (shortKernelDescr,)) self.fail("convolve(MaskedImage, kernel=%s, doNormalize=%s, doCopyEdge=%s, maxInterpDist=%s) failed:\n%s" % \ (kernelDescr, doNormalize, doCopyEdge, maxInterpDist, "convolved mask dictionary does not match input"))
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: if SAVE_FAILED_FITS_FILES: computedExposure.writeFits(computedExposurePath) expectedExposure.writeFits(expectedExposurePath) print "Saved failed afw-warped exposures as: %s and %s" % \ (computedExposurePath, expectedExposure) self.fail("Separate mask warping failed; warpingKernel=%s; maskWarpingKernel=%s; error=%s" % \ (kernelName, maskKernelName, errStr))
def runBasicTest(self, kernel, convControl, refKernel=None, kernelDescr="", rtol=1.0e-05, atol=1e-08): """Assert that afwMath::convolve gives the same result as reference convolution for a given kernel. Inputs: - kernel: convolution kernel - convControl: convolution control parameters (afwMath.ConvolutionControl) - refKernel: kernel to use for refConvolve (if None then kernel is used) - kernelDescr: description of kernel - rtol: relative tolerance (see below) - atol: absolute tolerance (see below) rtol and atol are positive, typically very small numbers. The relative difference (rtol * abs(b)) and the absolute difference "atol" are added together to compare against the absolute difference between "a" and "b". """ if refKernel == None: refKernel = kernel # strip garbage characters (whitespace and punctuation) to make a short description for saving files shortKernelDescr = kernelDescr.translate(NullTranslator, GarbageChars) doNormalize = convControl.getDoNormalize() doCopyEdge = convControl.getDoCopyEdge() maxInterpDist = convControl.getMaxInterpolationDistance() imMaskVar = self.maskedImage.getArrays() xy0 = self.maskedImage.getXY0() refCnvImMaskVarArr = refConvolve(imMaskVar, xy0, refKernel, doNormalize, doCopyEdge) afwMath.convolve(self.cnvImage, self.maskedImage.getImage(), kernel, convControl) self.assertEqual(self.cnvImage.getXY0(), self.xy0) cnvImArr = self.cnvImage.getArray() afwMath.convolve(self.cnvMaskedImage, self.maskedImage, kernel, convControl) cnvImMaskVarArr = self.cnvMaskedImage.getArrays() if display and False: refMaskedImage = afwImage.makeMaskedImageFromArrays( *refCnvImMaskVarArr) ds9.mtv(displayUtils.Mosaic().makeMosaic( [self.maskedImage, refMaskedImage, self.cnvMaskedImage]), frame=0) if False: for (x, y) in ((0, 0), (1, 0), (0, 1), (50, 50)): print "Mask(%d,%d) 0x%x 0x%x" % ( x, y, refMaskedImage.getMask().get( x, y), self.cnvMaskedImage.getMask().get(x, y)) errStr = imTestUtils.imagesDiffer(cnvImArr, refCnvImMaskVarArr[0], rtol=rtol, atol=atol) if errStr: self.cnvImage.writeFits("act%s.fits" % (shortKernelDescr, )) refMaskedImage = afwImage.makeMaskedImageFromArrays( *refCnvImMaskVarArr) refMaskedImage.getImage().writeFits("des%s.fits" % (shortKernelDescr, )) self.fail("convolve(Image, kernel=%s, doNormalize=%s, doCopyEdge=%s, maxInterpDist=%s) failed:\n%s" % \ (kernelDescr, doNormalize, doCopyEdge, maxInterpDist, errStr)) errStr = imTestUtils.maskedImagesDiffer(cnvImMaskVarArr, refCnvImMaskVarArr, doVariance=True, rtol=rtol, atol=atol) if errStr: self.cnvMaskedImage.writeFits("act%s" % (shortKernelDescr, )) refMaskedImage = afwImage.makeMaskedImageFromArrays( *refCnvImMaskVarArr) refMaskedImage.writeFits("des%s" % (shortKernelDescr, )) self.fail("convolve(MaskedImage, kernel=%s, doNormalize=%s, doCopyEdge=%s, maxInterpDist=%s) failed:\n%s" % \ (kernelDescr, doNormalize, doCopyEdge, maxInterpDist, errStr)) if not sameMaskPlaneDicts(self.cnvMaskedImage, self.maskedImage): self.cnvMaskedImage.writeFits("act%s" % (shortKernelDescr, )) refMaskedImage = afwImage.makeMaskedImageFromArrays( *refCnvImMaskVarArr) refMaskedImage.writeFits("des%s" % (shortKernelDescr, )) self.fail("convolve(MaskedImage, kernel=%s, doNormalize=%s, doCopyEdge=%s, maxInterpDist=%s) failed:\n%s" % \ (kernelDescr, doNormalize, doCopyEdge, maxInterpDist, "convolved mask dictionary does not match input"))
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, ))