def testMakeBadKernels(self): """Attempt to make various invalid kernels; make sure the constructor shows an exception """ kWidth = 4 kHeight = 3 gaussFunc1 = afwMath.GaussianFunction1D(1.0) gaussFunc2 = afwMath.GaussianFunction2D(1.0, 1.0, 0.0) spFunc = afwMath.PolynomialFunction2D(1) kernelList = [] kernelList.append(afwMath.FixedKernel( afwImage.ImageD(lsst.geom.Extent2I(kWidth, kHeight), 0.1))) kernelList.append(afwMath.FixedKernel( afwImage.ImageD(lsst.geom.Extent2I(kWidth, kHeight), 0.2))) for numKernelParams in (2, 4): spFuncList = [] for ii in range(numKernelParams): spFuncList.append(spFunc.clone()) try: afwMath.AnalyticKernel(kWidth, kHeight, gaussFunc2, spFuncList) self.fail("Should have failed with wrong # of spatial functions") except pexExcept.Exception: pass for numKernelParams in (1, 3): spFuncList = [] for ii in range(numKernelParams): spFuncList.append(spFunc.clone()) try: afwMath.LinearCombinationKernel(kernelList, spFuncList) self.fail("Should have failed with wrong # of spatial functions") except pexExcept.Exception: pass kParamList = [0.2]*numKernelParams try: afwMath.LinearCombinationKernel(kernelList, kParamList) self.fail("Should have failed with wrong # of kernel parameters") except pexExcept.Exception: pass try: afwMath.SeparableKernel( kWidth, kHeight, gaussFunc1, gaussFunc1, spFuncList) self.fail("Should have failed with wrong # of spatial functions") except pexExcept.Exception: pass for pointX in range(-1, kWidth+2): for pointY in range(-1, kHeight+2): if (0 <= pointX < kWidth) and (0 <= pointY < kHeight): continue try: afwMath.DeltaFunctionKernel( kWidth, kHeight, lsst.geom.Point2I(pointX, pointY)) self.fail("Should have failed with point not on kernel") except pexExcept.Exception: pass
def testRefactorDeltaLinearCombinationKernel(self): """Test LinearCombinationKernel.refactor with delta function basis kernels """ kWidth = 4 kHeight = 3 for spOrder in (0, 1, 2): spFunc = afwMath.PolynomialFunction2D(spOrder) numSpParams = spFunc.getNParameters() basisKernelList = makeDeltaFunctionKernelList(kWidth, kHeight) kernel = afwMath.LinearCombinationKernel(basisKernelList, spFunc) numBasisKernels = kernel.getNKernelParameters() maxVal = 1.01 + ((numSpParams - 1) * 0.1) sParamList = [ numpy.arange(kInd + 1.0, kInd + maxVal, 0.1) for kInd in range(numBasisKernels) ] kernel.setSpatialParameters(sParamList) refKernel = kernel.refactor() self.assert_(refKernel) errStr = self.compareKernels(kernel, refKernel, compareParams=False) if errStr: self.fail("failed with %s for spOrder=%s (numSpCoeff=%s)" % (errStr, spOrder, numSpParams))
def testSpatiallyVaryingDeltaFunctionLinearCombination(self): """Test convolution with a spatially varying LinearCombinationKernel of delta function basis kernels. """ kWidth = 2 kHeight = 2 # create spatially model sFunc = afwMath.PolynomialFunction2D(1) # spatial parameters are a list of entries, one per kernel parameter; # each entry is a list of spatial parameters sParams = ( (1.0, -0.5 / self.width, -0.5 / self.height), (0.0, 1.0 / self.width, 0.0 / self.height), (0.0, 0.0 / self.width, 1.0 / self.height), (0.5, 0.0, 0.0), ) basisKernelList = makeDeltaFunctionKernelList(kWidth, kHeight) kernel = afwMath.LinearCombinationKernel(basisKernelList, sFunc) kernel.setSpatialParameters(sParams) for maxInterpDist, rtol, methodStr in ( (0, 1.0e-5, "brute force"), (10, 1.0e-3, "interpolation over 10 x 10 pixels"), ): self.runStdTest( kernel, kernelDescr= "Spatially varying LinearCombinationKernel of delta function kernels using %s" % (methodStr, ), maxInterpDist=maxInterpDist, rtol=rtol)
def testLinearCombinationKernelDelta(self): """Test LinearCombinationKernel using a set of delta basis functions """ kWidth = 3 kHeight = 2 # create list of kernels basisKernelList = makeDeltaFunctionKernelList(kWidth, kHeight) basisImArrList = [] for basisKernel in basisKernelList: basisImage = afwImage.ImageD(basisKernel.getDimensions()) basisKernel.computeImage(basisImage, True) basisImArrList.append(basisImage.getArray()) kParams = [0.0] * len(basisKernelList) kernel = afwMath.LinearCombinationKernel(basisKernelList, kParams) self.assert_(kernel.isDeltaFunctionBasis()) self.basicTests(kernel, len(kParams)) for ii in range(len(basisKernelList)): kParams = [0.0] * len(basisKernelList) kParams[ii] = 1.0 kernel.setKernelParameters(kParams) kIm = afwImage.ImageD(kernel.getDimensions()) kernel.computeImage(kIm, True) kImArr = kIm.getArray() if not numpy.allclose(kImArr, basisImArrList[ii]): self.fail("%s = %s != %s for the %s'th basis kernel" % \ (kernel.__class__.__name__, kImArr, basisImArrList[ii], ii)) kernelClone = kernel.clone() errStr = self.compareKernels(kernel, kernelClone) if errStr: self.fail(errStr) self.verifyCache(kernel, hasCache=False)
def testRefactorGaussianLinearCombinationKernel(self): """Test LinearCombinationKernel.refactor with Gaussian basis kernels """ kWidth = 4 kHeight = 3 for spOrder in (0, 1, 2): spFunc = afwMath.PolynomialFunction2D(spOrder) numSpParams = spFunc.getNParameters() gaussParamsList = [ (1.5, 1.5, 0.0), (2.5, 1.5, 0.0), (2.5, 1.5, math.pi / 2.0), ] gaussBasisKernelList = makeGaussianKernelList( kWidth, kHeight, gaussParamsList) kernel = afwMath.LinearCombinationKernel( gaussBasisKernelList, spFunc) numBasisKernels = kernel.getNKernelParameters() maxVal = 1.01 + ((numSpParams - 1) * 0.1) sParamList = [np.arange(kInd + 1.0, kInd + maxVal, 0.1) for kInd in range(numBasisKernels)] kernel.setSpatialParameters(sParamList) refKernel = kernel.refactor() self.assertTrue(refKernel) errStr = self.compareKernels( kernel, refKernel, compareParams=False) if errStr: self.fail(f"failed with {errStr} for spOrder={spOrder}, numSpParams={numSpParams}")
def makeSpatialKernel(self, order): basicGaussian1 = afwMath.GaussianFunction2D(2., 2., 0.) basicKernel1 = afwMath.AnalyticKernel(self.ksize, self.ksize, basicGaussian1) basicGaussian2 = afwMath.GaussianFunction2D(5., 3., 0.5 * num.pi) basicKernel2 = afwMath.AnalyticKernel(self.ksize, self.ksize, basicGaussian2) basisList = [] basisList.append(basicKernel1) basisList.append(basicKernel2) basisList = ipDiffim.renormalizeKernelList(basisList) spatialKernelFunction = afwMath.PolynomialFunction2D(order) spatialKernel = afwMath.LinearCombinationKernel( basisList, spatialKernelFunction) kCoeffs = [ [ 0.0 for x in range(1, spatialKernelFunction.getNParameters() + 1) ], [ 0.01 * x for x in range(1, spatialKernelFunction.getNParameters() + 1) ] ] kCoeffs[0][ 0] = 1.0 # it does not vary spatially; constant across image spatialKernel.setSpatialParameters(kCoeffs) return spatialKernel
def testLinearCombinationKernelAnalytic(self): """Test LinearCombinationKernel using analytic basis kernels. The basis kernels are mutable so that we can verify that the LinearCombinationKernel has private copies of the basis kernels. """ kWidth = 5 kHeight = 8 # create list of kernels basisImArrList = [] basisKernelList = [] for basisKernelParams in [(1.2, 0.3, 1.570796), (1.0, 0.2, 0.0)]: basisKernelFunction = afwMath.GaussianFunction2D( *basisKernelParams) basisKernel = afwMath.AnalyticKernel( kWidth, kHeight, basisKernelFunction) basisImage = afwImage.ImageD(basisKernel.getDimensions()) basisKernel.computeImage(basisImage, True) basisImArrList.append(basisImage.getArray()) basisKernelList.append(basisKernel) kParams = [0.0]*len(basisKernelList) kernel = afwMath.LinearCombinationKernel(basisKernelList, kParams) self.assertTrue(not kernel.isDeltaFunctionBasis()) self.basicTests(kernel, len(kParams)) kernelResized = self.verifyResized(kernel) self.basicTests(kernelResized, len(kParams)) # make sure the linear combination kernel has private copies of its basis kernels # by altering the local basis kernels and making sure the new images do # NOT match modBasisImArrList = [] for basisKernel in basisKernelList: basisKernel.setKernelParameters((0.4, 0.5, 0.6)) modBasisImage = afwImage.ImageD(basisKernel.getDimensions()) basisKernel.computeImage(modBasisImage, True) modBasisImArrList.append(modBasisImage.getArray()) for ii in range(len(basisKernelList)): kParams = [0.0]*len(basisKernelList) kParams[ii] = 1.0 kernel.setKernelParameters(kParams) kIm = afwImage.ImageD(kernel.getDimensions()) kernel.computeImage(kIm, True) kImArr = kIm.getArray() if not np.allclose(kImArr, basisImArrList[ii]): self.fail(f"{kernel.__class__.__name__} = {kImArr} != " f"{basisImArrList[ii]} for the {ii}'th basis kernel") if np.allclose(kImArr, modBasisImArrList[ii]): self.fail(f"{kernel.__class__.__name__} = {kImArr} != " f"{modBasisImArrList[ii]} for *modified* {ii}'th basis kernel") kernelClone = kernel.clone() errStr = self.compareKernels(kernel, kernelClone) if errStr: self.fail(errStr) self.verifyCache(kernel, hasCache=False)
def _computeVaryingPsf(self): """Compute a varying PSF as a linear combination of PCA (== Karhunen-Loeve) basis functions We simply desire a PSF that is not constant across the image, so the precise choice of parameters (e.g., sigmas, setSpatialParameters) are not crucial. """ kernelSize = 31 sigma1 = 1.75 sigma2 = 2.0 * sigma1 basisKernelList = [] for sigma in (sigma1, sigma2): basisKernel = afwMath.AnalyticKernel( kernelSize, kernelSize, afwMath.GaussianFunction2D(sigma, sigma)) basisImage = afwImage.ImageD(basisKernel.getDimensions()) basisKernel.computeImage(basisImage, True) basisImage /= np.sum(basisImage.getArray()) if sigma == sigma1: basisImage0 = basisImage else: basisImage -= basisImage0 basisKernelList.append(afwMath.FixedKernel(basisImage)) order = 1 spFunc = afwMath.PolynomialFunction2D(order) exactKernel = afwMath.LinearCombinationKernel(basisKernelList, spFunc) exactKernel.setSpatialParameters([[1.0, 0, 0], [0.0, 0.5E-2, 0.2E-2]]) exactPsf = measAlg.PcaPsf(exactKernel) return exactPsf
def testSVLinearCombinationKernel(self): """Test a spatially varying LinearCombinationKernel """ kWidth = 3 kHeight = 2 # create image arrays for the basis kernels basisImArrList = [] imArr = np.zeros((kWidth, kHeight), dtype=float) imArr += 0.1 imArr[kWidth // 2, :] = 0.9 basisImArrList.append(imArr) imArr = np.zeros((kWidth, kHeight), dtype=float) imArr += 0.2 imArr[:, kHeight // 2] = 0.8 basisImArrList.append(imArr) # create a list of basis kernels from the images kVec = [] for basisImArr in basisImArrList: basisImage = afwImage.makeImageFromArray( basisImArr.transpose().copy()) kernel = afwMath.FixedKernel(basisImage) kVec.append(kernel) # create spatially varying linear combination kernel spFunc = afwMath.PolynomialFunction2D(1) # spatial parameters are a list of entries, one per kernel parameter; # each entry is a list of spatial parameters sParams = ( (0.0, 1.0, 0.0), (0.0, 0.0, 1.0), ) k = afwMath.LinearCombinationKernel(kVec, spFunc) k.setSpatialParameters(sParams) with lsst.utils.tests.getTempFilePath(".fits") as filename: k.writeFits(filename) k2 = afwMath.LinearCombinationKernel.readFits(filename) self.kernelCheck(k, k2) kImage = afwImage.ImageD(lsst.geom.Extent2I(kWidth, kHeight)) for colPos, rowPos, coeff0, coeff1 in [ (0.0, 0.0, 0.0, 0.0), (1.0, 0.0, 1.0, 0.0), (0.0, 1.0, 0.0, 1.0), (1.0, 1.0, 1.0, 1.0), (0.5, 0.5, 0.5, 0.5), ]: k2.computeImage(kImage, False, colPos, rowPos) kImArr = kImage.getArray().transpose() refKImArr = (basisImArrList[0] * coeff0) + \ (basisImArrList[1] * coeff1) if not np.allclose(kImArr, refKImArr): self.fail(f"{k2.__class__.__name__} = {kImArr} != {refKImArr} " f"at colPos={colPos}, rowPos={rowPos}")
def testLinearCombinationKernel(self): """Test LinearCombinationKernel using a set of delta basis functions """ kWidth = 3 kHeight = 2 pol = pexPolicy.Policy() additionalData = dafBase.PropertySet() loc = dafPersist.LogicalLocation( os.path.join(testPath, "data", "kernel5.boost")) persistence = dafPersist.Persistence.getPersistence(pol) # create list of kernels basisImArrList = [] kVec = afwMath.KernelList() for row in range(kHeight): for col in range(kWidth): kernel = afwMath.DeltaFunctionKernel(kWidth, kHeight, afwGeom.Point2I(col, row)) basisImage = afwImage.ImageD(kernel.getDimensions()) kernel.computeImage(basisImage, True) basisImArrList.append(basisImage.getArray().transpose().copy()) kVec.append(kernel) kParams = [0.0] * len(kVec) k = afwMath.LinearCombinationKernel(kVec, kParams) for ii in range(len(kVec)): kParams = [0.0] * len(kVec) kParams[ii] = 1.0 k.setKernelParameters(kParams) storageList = dafPersist.StorageList() storage = persistence.getPersistStorage("XmlStorage", loc) storageList.append(storage) persistence.persist(k, storageList, additionalData) storageList2 = dafPersist.StorageList() storage2 = persistence.getRetrieveStorage("XmlStorage", loc) storageList2.append(storage2) x = persistence.unsafeRetrieve("LinearCombinationKernel", storageList2, additionalData) k2 = afwMath.LinearCombinationKernel.swigConvert(x) self.kernelCheck(k, k2) kIm = afwImage.ImageD(k2.getDimensions()) k2.computeImage(kIm, True) kImArr = kIm.getArray().transpose() if not np.allclose(kImArr, basisImArrList[ii]): self.fail( "%s = %s != %s for the %s'th basis kernel" % (k2.__class__.__name__, kImArr, basisImArrList[ii], ii))
def testTicket873(self): """Demonstrate ticket 873: convolution of a MaskedImage with a spatially varying LinearCombinationKernel of basis kernels with low covariance gives incorrect variance. """ # create spatial model sFunc = afwMath.PolynomialFunction2D(1) # spatial parameters are a list of entries, one per kernel parameter; # each entry is a list of spatial parameters sParams = ( (1.0, -0.5/self.width, -0.5/self.height), (0.0, 1.0/self.width, 0.0/self.height), (0.0, 0.0/self.width, 1.0/self.height), ) # create three kernels with some non-overlapping pixels # (non-zero pixels in one kernel vs. zero pixels in other kernels); # note: the extreme example of this is delta function kernels, but this # is less extreme basisKernelList = [] kImArr = numpy.zeros([5, 5], dtype=float) kImArr[1:4, 1:4] = 0.5 kImArr[2, 2] = 1.0 kImage = afwImage.makeImageFromArray(kImArr) basisKernelList.append(afwMath.FixedKernel(kImage)) kImArr[:, :] = 0.0 kImArr[0:2, 0:2] = 0.125 kImArr[3:5, 3:5] = 0.125 kImage = afwImage.makeImageFromArray(kImArr) basisKernelList.append(afwMath.FixedKernel(kImage)) kImArr[:, :] = 0.0 kImArr[0:2, 3:5] = 0.125 kImArr[3:5, 0:2] = 0.125 kImage = afwImage.makeImageFromArray(kImArr) basisKernelList.append(afwMath.FixedKernel(kImage)) kernel = afwMath.LinearCombinationKernel(basisKernelList, sFunc) kernel.setSpatialParameters(sParams) for maxInterpDist, rtol, methodStr in ( (0, 1.0e-5, "brute force"), (10, 3.0e-3, "interpolation over 10 x 10 pixels"), ): self.runStdTest( kernel, kernelDescr="Spatially varying LinearCombinationKernel of basis " "kernels with low covariance, using %s" % ( methodStr,), maxInterpDist=maxInterpDist, rtol=rtol)
def getDeltaLinearCombinationKernel(kSize, imSize, spOrder): """Return a LinearCombinationKernel of delta functions @param kSize: kernel size (scalar; height = width) @param x, y imSize: image size """ kernelList = afwMath.KernelList() for ctrX in range(kSize): for ctrY in range(kSize): kernelList.append(afwMath.DeltaFunctionKernel(kSize, kSize, afwGeom.Point2I(ctrX, ctrY))) polyFunc = afwMath.PolynomialFunction2D(spOrder) kernel = afwMath.LinearCombinationKernel(kernelList, polyFunc) spParams = getSpatialParameters(len(kernelList), polyFunc) kernel.setSpatialParameters(spParams); return kernel
def testZeroWidthKernel(self): """Convolution by a 0x0 kernel should raise an exception. The only way to produce a 0x0 kernel is to use the default constructor (which exists only to support persistence; it does not produce a useful kernel). """ kernelList = [ afwMath.FixedKernel(), afwMath.AnalyticKernel(), afwMath.SeparableKernel(), # afwMath.DeltaFunctionKernel(), # DeltaFunctionKernel has no default constructor afwMath.LinearCombinationKernel(), ] convolutionControl = afwMath.ConvolutionControl() for kernel in kernelList: self.assertRaises(Exception, afwMath.convolve, self.cnvMaskedImage, self.maskedImage, kernel, convolutionControl)
def testBad(self): ti = afwImage.MaskedImageF(geom.Extent2I(100, 100)) ti.getVariance().set(0.1) ti[50, 50, afwImage.LOCAL] = (1., 0x0, 1.) sKernel = self.makeSpatialKernel(2) si = afwImage.MaskedImageF(ti.getDimensions()) convolutionControl = afwMath.ConvolutionControl() convolutionControl.setDoNormalize(True) afwMath.convolve(si, ti, sKernel, convolutionControl) bbox = geom.Box2I(geom.Point2I(25, 25), geom.Point2I(75, 75)) si = afwImage.MaskedImageF(si, bbox, origin=afwImage.LOCAL) ti = afwImage.MaskedImageF(ti, bbox, origin=afwImage.LOCAL) kc = ipDiffim.KernelCandidateF(50., 50., ti, si, self.ps) badGaussian = afwMath.GaussianFunction2D(1., 1., 0.) badKernel = afwMath.AnalyticKernel(self.ksize, self.ksize, badGaussian) basisList = [] basisList.append(badKernel) badSpatialKernelFunction = afwMath.PolynomialFunction2D(0) badSpatialKernel = afwMath.LinearCombinationKernel( basisList, badSpatialKernelFunction) badSpatialKernel.setSpatialParameters([[ 1, ]]) sBg = afwMath.PolynomialFunction2D(1) bgCoeffs = [10., 10., 10.] sBg.setParameters(bgCoeffs) # must be initialized bskv = ipDiffim.BuildSingleKernelVisitorF(self.kList, self.ps) bskv.processCandidate(kc) self.assertEqual(kc.isInitialized(), True) askv = ipDiffim.AssessSpatialKernelVisitorF(badSpatialKernel, sBg, self.ps) askv.processCandidate(kc) self.assertEqual(askv.getNProcessed(), 1) self.assertEqual(askv.getNRejected(), 1) self.assertEqual(kc.getStatus(), afwMath.SpatialCellCandidate.BAD)
def testSpatiallyVaryingGaussianLinerCombination(self): """Test convolution with a spatially varying LinearCombinationKernel of two Gaussian basis kernels. """ kWidth = 5 kHeight = 5 # create spatial model for nBasisKernels in (3, 4): # at 3 the kernel will not be refactored, at 4 it will be sFunc = afwMath.PolynomialFunction2D(1) # spatial parameters are a list of entries, one per kernel parameter; # each entry is a list of spatial parameters sParams = ( (1.0, -0.01 / self.width, -0.01 / self.height), (0.0, 0.01 / self.width, 0.0 / self.height), (0.0, 0.0 / self.width, 0.01 / self.height), (0.5, 0.005 / self.width, -0.005 / self.height), )[:nBasisKernels] gaussParamsList = ( (1.5, 1.5, 0.0), (2.5, 1.5, 0.0), (2.5, 1.5, math.pi / 2.0), (2.5, 2.5, 0.0), )[:nBasisKernels] basisKernelList = makeGaussianKernelList(kWidth, kHeight, gaussParamsList) kernel = afwMath.LinearCombinationKernel(basisKernelList, sFunc) kernel.setSpatialParameters(sParams) for maxInterpDist, rtol, methodStr in ( (0, 1.0e-5, "brute force"), (10, 1.0e-5, "interpolation over 10 x 10 pixels"), ): self.runStdTest( kernel, kernelDescr="%s with %d basis kernels convolved using %s" % ("Spatially Varying Gaussian Analytic Kernel", nBasisKernels, methodStr), maxInterpDist=maxInterpDist, rtol=rtol)
def testCast(self): instances = [] kVec = makeGaussianKernelList(9, 9, [(2.0, 2.0, 0.0)]) kParams = [0.0] * len(kVec) instances.append(afwMath.LinearCombinationKernel(kVec, kParams)) instances.append( afwMath.AnalyticKernel(7, 7, afwMath.GaussianFunction2D(2.0, 2.0, 0.0))) instances.append( afwMath.DeltaFunctionKernel(5, 5, afwGeom.Point2I(1, 1))) instances.append( afwMath.FixedKernel(afwImage.ImageD(afwGeom.Extent2I(7, 7)))) instances.append( afwMath.SeparableKernel(3, 3, afwMath.PolynomialFunction1D(0), afwMath.PolynomialFunction1D(0))) for instance in instances: Class = type(instance) base = instance.clone() self.assertEqual(type(base), afwMath.Kernel) derived = Class.cast(base) self.assertEqual(type(derived), Class)
def testComputeImageRaise(self): """Test Kernel.computeImage raises OverflowException iff doNormalize True and kernel sum exactly 0 """ kWidth = 4 kHeight = 3 polyFunc1 = afwMath.PolynomialFunction1D(0) polyFunc2 = afwMath.PolynomialFunction2D(0) analKernel = afwMath.AnalyticKernel(kWidth, kHeight, polyFunc2) kImage = afwImage.ImageD(analKernel.getDimensions()) for coeff in (-1, -1e-99, 0, 1e99, 1): analKernel.setKernelParameters([coeff]) analKernel.computeImage(kImage, False) fixedKernel = afwMath.FixedKernel(kImage) sepKernel = afwMath.SeparableKernel( kWidth, kHeight, polyFunc1, polyFunc1) sepKernel.setKernelParameters([coeff, coeff]) kernelList = [] kernelList.append(analKernel) lcKernel = afwMath.LinearCombinationKernel(kernelList, [1]) self.assertFalse(lcKernel.isDeltaFunctionBasis()) doRaise = (coeff == 0) self.basicTestComputeImageRaise( analKernel, doRaise, "AnalyticKernel") self.basicTestComputeImageRaise( fixedKernel, doRaise, "FixedKernel") self.basicTestComputeImageRaise( sepKernel, doRaise, "SeparableKernel") self.basicTestComputeImageRaise( lcKernel, doRaise, "LinearCombinationKernel") lcKernel.setKernelParameters([0]) self.basicTestComputeImageRaise( lcKernel, True, "LinearCombinationKernel")
def testLinearCombinationKernel(self): """Test LinearCombinationKernel using a set of delta basis functions """ kWidth = 3 kHeight = 2 # create list of kernels basisImArrList = [] kVec = [] for row in range(kHeight): for col in range(kWidth): kernel = afwMath.DeltaFunctionKernel( kWidth, kHeight, lsst.geom.Point2I(col, row)) basisImage = afwImage.ImageD(kernel.getDimensions()) kernel.computeImage(basisImage, True) basisImArrList.append(basisImage.getArray().transpose().copy()) kVec.append(kernel) kParams = [0.0] * len(kVec) k = afwMath.LinearCombinationKernel(kVec, kParams) for ii in range(len(kVec)): kParams = [0.0] * len(kVec) kParams[ii] = 1.0 k.setKernelParameters(kParams) with lsst.utils.tests.getTempFilePath(".fits") as filename: k.writeFits(filename) k2 = afwMath.LinearCombinationKernel.readFits(filename) self.kernelCheck(k, k2) kIm = afwImage.ImageD(k2.getDimensions()) k2.computeImage(kIm, True) kImArr = kIm.getArray().transpose() if not np.allclose(kImArr, basisImArrList[ii]): self.fail( f"{k2.__class__.__name__} = {kImArr} != {basisImArrList[ii]} " f"for the {ii}'th basis kernel")
def getGaussianLinearCombinationKernel(kSize, imSize, spOrder): """Return a LinearCombinationKernel with 5 bases, each a Gaussian @param kSize: kernel size (scalar; height = width) @param x, y imSize: image size """ kernelList = afwMath.KernelList() for fwhmX, fwhmY, angle in ( (2.0, 2.0, 0.0), (0.5, 4.0, 0.0), (0.5, 4.0, math.pi / 4.0), (0.5, 4.0, math.pi / 2.0), (4.0, 4.0, 0.0), ): gaussFunc = afwMath.GaussianFunction2D(fwhmX, fwhmY, angle) kernelList.append(afwMath.AnalyticKernel(kSize, kSize, gaussFunc)) polyFunc = afwMath.PolynomialFunction2D(spOrder) kernel = afwMath.LinearCombinationKernel(kernelList, polyFunc) spParams = getSpatialParameters(len(kernelList), polyFunc) kernel.setSpatialParameters(spParams); return kernel
def testSVLinearCombinationKernel(self): """Test a spatially varying LinearCombinationKernel """ kWidth = 3 kHeight = 2 pol = pexPolicy.Policy() additionalData = dafBase.PropertySet() loc = dafPersist.LogicalLocation( os.path.join(testPath, "data", "kernel6.boost")) persistence = dafPersist.Persistence.getPersistence(pol) # create image arrays for the basis kernels basisImArrList = [] imArr = np.zeros((kWidth, kHeight), dtype=float) imArr += 0.1 imArr[kWidth // 2, :] = 0.9 basisImArrList.append(imArr) imArr = np.zeros((kWidth, kHeight), dtype=float) imArr += 0.2 imArr[:, kHeight // 2] = 0.8 basisImArrList.append(imArr) # create a list of basis kernels from the images kVec = [] for basisImArr in basisImArrList: basisImage = afwImage.makeImageFromArray( basisImArr.transpose().copy()) kernel = afwMath.FixedKernel(basisImage) kVec.append(kernel) # create spatially varying linear combination kernel spFunc = afwMath.PolynomialFunction2D(1) # spatial parameters are a list of entries, one per kernel parameter; # each entry is a list of spatial parameters sParams = ( (0.0, 1.0, 0.0), (0.0, 0.0, 1.0), ) k = afwMath.LinearCombinationKernel(kVec, spFunc) k.setSpatialParameters(sParams) storageList = dafPersist.StorageList() storage = persistence.getPersistStorage("XmlStorage", loc) storageList.append(storage) persistence.persist(k, storageList, additionalData) storageList2 = dafPersist.StorageList() storage2 = persistence.getRetrieveStorage("XmlStorage", loc) storageList2.append(storage2) k2 = persistence.unsafeRetrieve("LinearCombinationKernel", storageList2, additionalData) self.kernelCheck(k, k2) kImage = afwImage.ImageD(afwGeom.Extent2I(kWidth, kHeight)) for colPos, rowPos, coeff0, coeff1 in [ (0.0, 0.0, 0.0, 0.0), (1.0, 0.0, 1.0, 0.0), (0.0, 1.0, 0.0, 1.0), (1.0, 1.0, 1.0, 1.0), (0.5, 0.5, 0.5, 0.5), ]: k2.computeImage(kImage, False, colPos, rowPos) kImArr = kImage.getArray().transpose() refKImArr = (basisImArrList[0] * coeff0) + \ (basisImArrList[1] * coeff1) if not np.allclose(kImArr, refKImArr): self.fail( "%s = %s != %s at colPos=%s, rowPos=%s" % (k2.__class__.__name__, kImArr, refKImArr, colPos, rowPos))
def showPsfCandidates(exposure, psfCellSet, psf=None, frame=None, normalize=True, showBadCandidates=True, variance=None, chi=None): """Display the PSF candidates. If psf is provided include PSF model and residuals; if normalize is true normalize the PSFs (and residuals) If chi is True, generate a plot of residuals/sqrt(variance), i.e. chi """ if chi is None: if variance is not None: # old name for chi chi = variance # # Show us the ccandidates # mos = displayUtils.Mosaic() # candidateCenters = [] candidateCentersBad = [] candidateIndex = 0 for cell in psfCellSet.getCellList(): for cand in cell.begin(False): # include bad candidates cand = algorithmsLib.cast_PsfCandidateF(cand) rchi2 = cand.getChi2() if rchi2 > 1e100: rchi2 = numpy.nan if not showBadCandidates and cand.isBad(): continue if psf: im_resid = displayUtils.Mosaic(gutter=0, background=-5, mode="x") try: im = cand.getMaskedImage() # copy of this object's image xc, yc = cand.getXCenter(), cand.getYCenter() margin = 0 if True else 5 w, h = im.getDimensions() bbox = afwGeom.BoxI(afwGeom.PointI(margin, margin), im.getDimensions()) if margin > 0: bim = im.Factory(w + 2*margin, h + 2*margin) stdev = numpy.sqrt(afwMath.makeStatistics(im.getVariance(), afwMath.MEAN).getValue()) afwMath.randomGaussianImage(bim.getImage(), afwMath.Random()) bim *= stdev var = bim.getVariance(); var.set(stdev**2); del var sbim = im.Factory(bim, bbox) sbim <<= im del sbim im = bim xc += margin; yc += margin im = im.Factory(im, True) im.setXY0(cand.getMaskedImage().getXY0()) except: continue if not variance: im_resid.append(im.Factory(im, True)) # residuals using spatial model chi2 = algorithmsLib.subtractPsf(psf, im, xc, yc) resid = im if variance: resid = resid.getImage() var = im.getVariance() var = var.Factory(var, True) numpy.sqrt(var.getArray(), var.getArray()) # inplace sqrt resid /= var im_resid.append(resid) # Fit the PSF components directly to the data (i.e. ignoring the spatial model) im = cand.getMaskedImage() im = im.Factory(im, True) im.setXY0(cand.getMaskedImage().getXY0()) noSpatialKernel = afwMath.cast_LinearCombinationKernel(psf.getKernel()) candCenter = afwGeom.PointD(cand.getXCenter(), cand.getYCenter()) fit = algorithmsLib.fitKernelParamsToImage(noSpatialKernel, im, candCenter) params = fit[0] kernels = afwMath.KernelList(fit[1]) outputKernel = afwMath.LinearCombinationKernel(kernels, params) outImage = afwImage.ImageD(outputKernel.getDimensions()) outputKernel.computeImage(outImage, False) im -= outImage.convertF() resid = im if margin > 0: bim = im.Factory(w + 2*margin, h + 2*margin) afwMath.randomGaussianImage(bim.getImage(), afwMath.Random()) bim *= stdev sbim = im.Factory(bim, bbox) sbim <<= resid del sbim resid = bim if variance: resid = resid.getImage() resid /= var im_resid.append(resid) im = im_resid.makeMosaic() else: im = cand.getMaskedImage() if normalize: im /= afwMath.makeStatistics(im, afwMath.MAX).getValue() objId = splitId(cand.getSource().getId(), True)["objId"] if psf: lab = "%d chi^2 %.1f" % (objId, rchi2) ctype = ds9.RED if cand.isBad() else ds9.GREEN else: lab = "%d flux %8.3g" % (objId, cand.getSource().getPsfFlux()) ctype = ds9.GREEN mos.append(im, lab, ctype) if False and numpy.isnan(rchi2): ds9.mtv(cand.getMaskedImage().getImage(), title="candidate", frame=1) print "amp", cand.getAmplitude() im = cand.getMaskedImage() center = (candidateIndex, xc - im.getX0(), yc - im.getY0()) candidateIndex += 1 if cand.isBad(): candidateCentersBad.append(center) else: candidateCenters.append(center) if variance: title = "chi(Psf fit)" else: title = "Stars & residuals" mosaicImage = mos.makeMosaic(frame=frame, title=title) with ds9.Buffering(): for centers, color in ((candidateCenters, ds9.GREEN), (candidateCentersBad, ds9.RED)): for cen in centers: bbox = mos.getBBox(cen[0]) ds9.dot("+", cen[1] + bbox.getMinX(), cen[2] + bbox.getMinY(), frame=frame, ctype=color) return mosaicImage
def showPsfCandidates(exposure, psfCellSet, psf=None, display=None, normalize=True, showBadCandidates=True, fitBasisComponents=False, variance=None, chi=None): """Display the PSF candidates. If psf is provided include PSF model and residuals; if normalize is true normalize the PSFs (and residuals) If chi is True, generate a plot of residuals/sqrt(variance), i.e. chi If fitBasisComponents is true, also find the best linear combination of the PSF's components (if they exist) """ if not display: display = afwDisplay.Display() if chi is None: if variance is not None: # old name for chi chi = variance # # Show us the ccandidates # mos = displayUtils.Mosaic() # candidateCenters = [] candidateCentersBad = [] candidateIndex = 0 for cell in psfCellSet.getCellList(): for cand in cell.begin(False): # include bad candidates rchi2 = cand.getChi2() if rchi2 > 1e100: rchi2 = numpy.nan if not showBadCandidates and cand.isBad(): continue if psf: im_resid = displayUtils.Mosaic(gutter=0, background=-5, mode="x") try: im = cand.getMaskedImage() # copy of this object's image xc, yc = cand.getXCenter(), cand.getYCenter() margin = 0 if True else 5 w, h = im.getDimensions() bbox = lsst.geom.BoxI(lsst.geom.PointI(margin, margin), im.getDimensions()) if margin > 0: bim = im.Factory(w + 2*margin, h + 2*margin) stdev = numpy.sqrt(afwMath.makeStatistics(im.getVariance(), afwMath.MEAN).getValue()) afwMath.randomGaussianImage(bim.getImage(), afwMath.Random()) bim.getVariance().set(stdev**2) bim.assign(im, bbox) im = bim xc += margin yc += margin im = im.Factory(im, True) im.setXY0(cand.getMaskedImage().getXY0()) except Exception: continue if not variance: im_resid.append(im.Factory(im, True)) if True: # tweak up centroids mi = im psfIm = mi.getImage() config = measBase.SingleFrameMeasurementTask.ConfigClass() config.slots.centroid = "base_SdssCentroid" schema = afwTable.SourceTable.makeMinimalSchema() measureSources = measBase.SingleFrameMeasurementTask(schema, config=config) catalog = afwTable.SourceCatalog(schema) extra = 10 # enough margin to run the sdss centroider miBig = mi.Factory(im.getWidth() + 2*extra, im.getHeight() + 2*extra) miBig[extra:-extra, extra:-extra, afwImage.LOCAL] = mi miBig.setXY0(mi.getX0() - extra, mi.getY0() - extra) mi = miBig del miBig exp = afwImage.makeExposure(mi) exp.setPsf(psf) footprintSet = afwDet.FootprintSet(mi, afwDet.Threshold(0.5*numpy.max(psfIm.getArray())), "DETECTED") footprintSet.makeSources(catalog) if len(catalog) == 0: raise RuntimeError("Failed to detect any objects") measureSources.run(catalog, exp) if len(catalog) == 1: source = catalog[0] else: # more than one source; find the once closest to (xc, yc) dmin = None # an invalid value to catch logic errors for i, s in enumerate(catalog): d = numpy.hypot(xc - s.getX(), yc - s.getY()) if i == 0 or d < dmin: source, dmin = s, d xc, yc = source.getCentroid() # residuals using spatial model try: subtractPsf(psf, im, xc, yc) except Exception: continue resid = im if variance: resid = resid.getImage() var = im.getVariance() var = var.Factory(var, True) numpy.sqrt(var.getArray(), var.getArray()) # inplace sqrt resid /= var im_resid.append(resid) # Fit the PSF components directly to the data (i.e. ignoring the spatial model) if fitBasisComponents: im = cand.getMaskedImage() im = im.Factory(im, True) im.setXY0(cand.getMaskedImage().getXY0()) try: noSpatialKernel = psf.getKernel() except Exception: noSpatialKernel = None if noSpatialKernel: candCenter = lsst.geom.PointD(cand.getXCenter(), cand.getYCenter()) fit = fitKernelParamsToImage(noSpatialKernel, im, candCenter) params = fit[0] kernels = afwMath.KernelList(fit[1]) outputKernel = afwMath.LinearCombinationKernel(kernels, params) outImage = afwImage.ImageD(outputKernel.getDimensions()) outputKernel.computeImage(outImage, False) im -= outImage.convertF() resid = im if margin > 0: bim = im.Factory(w + 2*margin, h + 2*margin) afwMath.randomGaussianImage(bim.getImage(), afwMath.Random()) bim *= stdev bim.assign(resid, bbox) resid = bim if variance: resid = resid.getImage() resid /= var im_resid.append(resid) im = im_resid.makeMosaic() else: im = cand.getMaskedImage() if normalize: im /= afwMath.makeStatistics(im, afwMath.MAX).getValue() objId = splitId(cand.getSource().getId(), True)["objId"] if psf: lab = "%d chi^2 %.1f" % (objId, rchi2) ctype = afwDisplay.RED if cand.isBad() else afwDisplay.GREEN else: lab = "%d flux %8.3g" % (objId, cand.getSource().getPsfInstFlux()) ctype = afwDisplay.GREEN mos.append(im, lab, ctype) if False and numpy.isnan(rchi2): display.mtv(cand.getMaskedImage().getImage(), title="showPsfCandidates: candidate") print("amp", cand.getAmplitude()) im = cand.getMaskedImage() center = (candidateIndex, xc - im.getX0(), yc - im.getY0()) candidateIndex += 1 if cand.isBad(): candidateCentersBad.append(center) else: candidateCenters.append(center) if variance: title = "chi(Psf fit)" else: title = "Stars & residuals" mosaicImage = mos.makeMosaic(display=display, title=title) with display.Buffering(): for centers, color in ((candidateCenters, afwDisplay.GREEN), (candidateCentersBad, afwDisplay.RED)): for cen in centers: bbox = mos.getBBox(cen[0]) display.dot("+", cen[1] + bbox.getMinX(), cen[2] + bbox.getMinY(), ctype=color) return mosaicImage
def setUp(self): self.schema = afwTable.SourceTable.makeMinimalSchema() config = measBase.SingleFrameMeasurementConfig() config.algorithms.names = [ "base_PixelFlags", "base_SdssCentroid", "base_GaussianFlux", "base_SdssShape", "base_CircularApertureFlux", "base_PsfFlux", ] config.algorithms["base_CircularApertureFlux"].radii = [3.0] config.slots.centroid = "base_SdssCentroid" config.slots.psfFlux = "base_PsfFlux" config.slots.apFlux = "base_CircularApertureFlux_3_0" config.slots.modelFlux = None config.slots.instFlux = None config.slots.calibFlux = None config.slots.shape = "base_SdssShape" self.measureTask = measBase.SingleFrameMeasurementTask(self.schema, config=config) width, height = 110, 301 self.mi = afwImage.MaskedImageF(afwGeom.ExtentI(width, height)) self.mi.set(0) sd = 3 # standard deviation of image self.mi.getVariance().set(sd * sd) self.mi.getMask().addMaskPlane("DETECTED") self.FWHM = 5 self.ksize = 31 # size of desired kernel sigma1 = 1.75 sigma2 = 2 * sigma1 self.exposure = afwImage.makeExposure(self.mi) self.exposure.setPsf( measAlg.DoubleGaussianPsf(self.ksize, self.ksize, 1.5 * sigma1, 1, 0.1)) self.exposure.setDetector(DetectorWrapper().detector) # # Make a kernel with the exactly correct basis functions. Useful for debugging # basisKernelList = [] for sigma in (sigma1, sigma2): basisKernel = afwMath.AnalyticKernel( self.ksize, self.ksize, afwMath.GaussianFunction2D(sigma, sigma)) basisImage = afwImage.ImageD(basisKernel.getDimensions()) basisKernel.computeImage(basisImage, True) basisImage /= np.sum(basisImage.getArray()) if sigma == sigma1: basisImage0 = basisImage else: basisImage -= basisImage0 basisKernelList.append(afwMath.FixedKernel(basisImage)) order = 1 # 1 => up to linear spFunc = afwMath.PolynomialFunction2D(order) exactKernel = afwMath.LinearCombinationKernel(basisKernelList, spFunc) exactKernel.setSpatialParameters([[1.0, 0, 0], [0.0, 0.5 * 1e-2, 0.2e-2]]) self.exactPsf = measAlg.PcaPsf(exactKernel) rand = afwMath.Random() # make these tests repeatable by setting seed addNoise = True if addNoise: im = self.mi.getImage() afwMath.randomGaussianImage(im, rand) # N(0, 1) im *= sd # N(0, sd^2) del im xarr, yarr = [], [] for x, y in [ (20, 20), (60, 20), (30, 35), (50, 50), (20, 90), (70, 160), (25, 265), (75, 275), (85, 30), (50, 120), (70, 80), (60, 210), (20, 210), ]: xarr.append(x) yarr.append(y) for x, y in zip(xarr, yarr): dx = rand.uniform() - 0.5 # random (centered) offsets dy = rand.uniform() - 0.5 k = exactKernel.getSpatialFunction(1)( x, y) # functional variation of Kernel ... b = (k * sigma1**2 / ((1 - k) * sigma2**2) ) # ... converted double Gaussian's "b" # flux = 80000 - 20*x - 10*(y/float(height))**2 flux = 80000 * (1 + 0.1 * (rand.uniform() - 0.5)) I0 = flux * (1 + b) / (2 * np.pi * (sigma1**2 + b * sigma2**2)) for iy in range(y - self.ksize // 2, y + self.ksize // 2 + 1): if iy < 0 or iy >= self.mi.getHeight(): continue for ix in range(x - self.ksize // 2, x + self.ksize // 2 + 1): if ix < 0 or ix >= self.mi.getWidth(): continue intensity = I0 * psfVal(ix, iy, x + dx, y + dy, sigma1, sigma2, b) Isample = rand.poisson( intensity) if addNoise else intensity self.mi.getImage().set( ix, iy, self.mi.getImage().get(ix, iy) + Isample) self.mi.getVariance().set( ix, iy, self.mi.getVariance().get(ix, iy) + intensity) # bbox = afwGeom.BoxI(afwGeom.PointI(0, 0), afwGeom.ExtentI(width, height)) self.cellSet = afwMath.SpatialCellSet(bbox, 100) self.footprintSet = afwDetection.FootprintSet( self.mi, afwDetection.Threshold(100), "DETECTED") self.catalog = self.measure(self.footprintSet, self.exposure) for source in self.catalog: try: cand = measAlg.makePsfCandidate(source, self.exposure) self.cellSet.insertCandidate(cand) except Exception as e: print(e) continue
def convertpsField(infile, filt, trim=True, rcscale=0.001, MAX_ORDER_B=5, LSST_ORDER=4): if filt not in filtToHdu: print("INVALID FILTER", filt) sys.exit(1) buff = open(infile, "rb") pstruct = fits.getdata(buff, ext=filtToHdu[filt]) spaParList = [[]]*len(pstruct) kernelList = [] for i in range(len(pstruct)): nrow_b = pstruct[i][0] # ny ncol_b = pstruct[i][1] # nx cmat = pstruct[i][2].reshape((MAX_ORDER_B, MAX_ORDER_B)) krow = pstruct[i][4] # RNROW kcol = pstruct[i][5] # RNCOL # This is *not* transposed karr = pstruct[i][7].reshape((krow, kcol)).astype(num.float64) if trim: karr = karr[10:41, 10:41] kim = afwImage.ImageD(karr) kern = afwMath.FixedKernel(kim) kernelList.append(kern) # NOTES: # Afw has the polynomial terms like: # # * f(x,y) = c0 (0th order) # * + c1 x + c2 y (1st order) # * + c3 x^2 + c4 x y + c5 y^2 (2nd order) # * + c6 x^3 + c7 x^2 y + c8 x y^2 + c9 y^3 (3rd order) # * + c10 x^4 + c11 x^3 y + c12 x^2 y^2 + c13 x y^3 + c14 y^4 (4th order) # # So, ordered: x^0,y^0 x^1,y^0 x^0,y^1 x^2,y^0 x^1,y^1 x^0,y^2 # SDSS has the terms ordered like, after reshape(): # # x^0,y^0 x^0,y^1 x^0,y^2 # x^1,y^0 x^1,y^1 x^1,y^2 # x^2,y^0 x^2,y^1 x^2,y^2 # # So, it technically goes up to fourth order in LSST-speak. OK, that is the trick. # # Mapping: # cmat[0][0] = c0 x^0y^0 # cmat[1][0] = c2 x^0y^1 # cmat[2][0] = c5 x^0y^2 # cmat[0][1] = c1 x^1y^0 # cmat[1][1] = c4 x^1y^1 # cmat[2][1] = c8 x^1y^2 # cmat[0][2] = c3 x^2y^0 # cmat[1][2] = c7 x^2y^1 # cmat[2][2] = c12 x^2y^2 # # This is quantified in skMatrixPos2TriSeqPosT spaParamsTri = num.zeros(MAX_ORDER_B * MAX_ORDER_B) for k in range(nrow_b * ncol_b): row = k % nrow_b col = k // nrow_b coeff = cmat[row, col] scale = pow(rcscale, row) * pow(rcscale, col) scaledCoeff = coeff * scale # Was originally written like this, but the SDSS code # takes inputs as y,x instead of x,y meaning it was # originally transposed # # idx = row * MAX_ORDER_B + col idx = col * MAX_ORDER_B + row spaParamsTri[skMatrixPos2TriSeqPosT[idx]] = scaledCoeff # print "%d y=%d x=%d %10.3e %2d %2d %10.3e" % \ # (i, row, col, cmat[row,col], idx, skMatrixPos2TriSeqPosT[idx], scaledCoeff) # print spaParamsTri nTerms = (LSST_ORDER + 1) * (LSST_ORDER + 2) // 2 spaParamsTri = spaParamsTri[:nTerms] spaParList[i] = spaParamsTri buff.close() spaFun = afwMath.PolynomialFunction2D(LSST_ORDER) spatialKernel = afwMath.LinearCombinationKernel(kernelList, spaFun) spatialKernel.setSpatialParameters(spaParList) spatialPsf = measAlg.PcaPsf(spatialKernel) return spatialPsf
def setUp(self): config = SingleFrameMeasurementTask.ConfigClass() config.slots.apFlux = 'base_CircularApertureFlux_12_0' self.schema = afwTable.SourceTable.makeMinimalSchema() self.measureSources = SingleFrameMeasurementTask(self.schema, config=config) width, height = 110, 301 self.mi = afwImage.MaskedImageF(geom.ExtentI(width, height)) self.mi.set(0) sd = 3 # standard deviation of image self.mi.getVariance().set(sd * sd) self.mi.getMask().addMaskPlane("DETECTED") self.ksize = 31 # size of desired kernel sigma1 = 1.75 sigma2 = 2 * sigma1 self.exposure = afwImage.makeExposure(self.mi) self.exposure.setPsf( measAlg.DoubleGaussianPsf(self.ksize, self.ksize, 1.5 * sigma1, 1, 0.1)) cdMatrix = np.array([1.0, 0.0, 0.0, 1.0]) cdMatrix.shape = (2, 2) wcs = afwGeom.makeSkyWcs(crpix=geom.PointD(0, 0), crval=geom.SpherePoint( 0.0, 0.0, geom.degrees), cdMatrix=cdMatrix) self.exposure.setWcs(wcs) # # Make a kernel with the exactly correct basis functions. # Useful for debugging # basisKernelList = [] for sigma in (sigma1, sigma2): basisKernel = afwMath.AnalyticKernel( self.ksize, self.ksize, afwMath.GaussianFunction2D(sigma, sigma)) basisImage = afwImage.ImageD(basisKernel.getDimensions()) basisKernel.computeImage(basisImage, True) basisImage /= np.sum(basisImage.getArray()) if sigma == sigma1: basisImage0 = basisImage else: basisImage -= basisImage0 basisKernelList.append(afwMath.FixedKernel(basisImage)) order = 1 # 1 => up to linear spFunc = afwMath.PolynomialFunction2D(order) exactKernel = afwMath.LinearCombinationKernel(basisKernelList, spFunc) exactKernel.setSpatialParameters([[1.0, 0, 0], [0.0, 0.5 * 1e-2, 0.2e-2]]) rand = afwMath.Random() # make these tests repeatable by setting seed addNoise = True if addNoise: im = self.mi.getImage() afwMath.randomGaussianImage(im, rand) # N(0, 1) im *= sd # N(0, sd^2) del im xarr, yarr = [], [] for x, y in [ (20, 20), (60, 20), (30, 35), (50, 50), (20, 90), (70, 160), (25, 265), (75, 275), (85, 30), (50, 120), (70, 80), (60, 210), (20, 210), ]: xarr.append(x) yarr.append(y) for x, y in zip(xarr, yarr): dx = rand.uniform() - 0.5 # random (centered) offsets dy = rand.uniform() - 0.5 k = exactKernel.getSpatialFunction(1)( x, y) # functional variation of Kernel ... b = (k * sigma1**2 / ((1 - k) * sigma2**2) ) # ... converted double Gaussian's "b" # flux = 80000 - 20*x - 10*(y/float(height))**2 flux = 80000 * (1 + 0.1 * (rand.uniform() - 0.5)) I0 = flux * (1 + b) / (2 * np.pi * (sigma1**2 + b * sigma2**2)) for iy in range(y - self.ksize // 2, y + self.ksize // 2 + 1): if iy < 0 or iy >= self.mi.getHeight(): continue for ix in range(x - self.ksize // 2, x + self.ksize // 2 + 1): if ix < 0 or ix >= self.mi.getWidth(): continue II = I0 * psfVal(ix, iy, x + dx, y + dy, sigma1, sigma2, b) Isample = rand.poisson(II) if addNoise else II self.mi.image[ix, iy, afwImage.LOCAL] += Isample self.mi.variance[ix, iy, afwImage.LOCAL] += II bbox = geom.BoxI(geom.PointI(0, 0), geom.ExtentI(width, height)) self.cellSet = afwMath.SpatialCellSet(bbox, 100) self.footprintSet = afwDetection.FootprintSet( self.mi, afwDetection.Threshold(100), "DETECTED") self.catalog = self.measure(self.footprintSet, self.exposure) for source in self.catalog: try: cand = measAlg.makePsfCandidate(source, self.exposure) self.cellSet.insertCandidate(cand) except Exception as e: print(e) continue
def testAutoCorrelation(orderMake, orderFit, inMi=None, display=False): config = ipDiffim.ImagePsfMatchTask.ConfigClass() config.kernel.name = "AL" subconfig = config.kernel.active subconfig.fitForBackground = True stride = 100 if inMi == None: width = 512 height = 2048 inMi = afwImage.MaskedImageF(afwGeom.Extent2I(width, height)) for j in num.arange(stride // 2, height, stride): j = int(j) for i in num.arange(stride // 2, width, stride): i = int(i) inMi.set(i - 1, j - 1, (100., 0x0, 1.)) inMi.set(i - 1, j + 0, (100., 0x0, 1.)) inMi.set(i - 1, j + 1, (100., 0x0, 1.)) inMi.set(i + 0, j - 1, (100., 0x0, 1.)) inMi.set(i + 0, j + 0, (100., 0x0, 1.)) inMi.set(i + 0, j + 1, (100., 0x0, 1.)) inMi.set(i + 1, j - 1, (100., 0x0, 1.)) inMi.set(i + 1, j + 0, (100., 0x0, 1.)) inMi.set(i + 1, j + 1, (100., 0x0, 1.)) addNoise(inMi) kSize = subconfig.kernelSize basicGaussian1 = afwMath.GaussianFunction2D(2., 2., 0.) basicKernel1 = afwMath.AnalyticKernel(kSize, kSize, basicGaussian1) basicGaussian2 = afwMath.GaussianFunction2D(5., 3., 0.5 * num.pi) basicKernel2 = afwMath.AnalyticKernel(kSize, kSize, basicGaussian2) basisList = [] basisList.append(basicKernel1) basisList.append(basicKernel2) spatialKernelFunction = afwMath.PolynomialFunction2D(orderMake) spatialKernel = afwMath.LinearCombinationKernel(basisList, spatialKernelFunction) kCoeffs = [[ 1.0 for x in range(1, spatialKernelFunction.getNParameters() + 1) ], [ 0.01 * x for x in range(1, spatialKernelFunction.getNParameters() + 1) ]] spatialKernel.setSpatialParameters(kCoeffs) cMi = afwImage.MaskedImageF(inMi.getDimensions()) afwMath.convolve(cMi, inMi, spatialKernel, True) if display: ds9.mtv(inMi.getImage(), frame=1) ds9.mtv(inMi.getVariance(), frame=2) ds9.mtv(cMi.getImage(), frame=3) ds9.mtv(cMi.getVariance(), frame=4) subconfig.spatialKernelOrder = orderFit subconfig.sizeCellX = stride subconfig.sizeCellY = stride psfmatch = ipDiffim.ImagePsfMatchTask(config=config) result = psfmatch.run(inMi, cMi, "subtractMaskedImages") differenceMaskedImage = result.subtractedImage spatialKernel = result.psfMatchingKernel spatialBg = result.backgroundModel kernelCellSet = result.kernelCellSet makeAutoCorrelation(kernelCellSet, spatialKernel, makePlot=True)
def testAutoCorrelation(orderMake, orderFit, inMi=None, display=False): config = ipDiffim.ImagePsfMatchTask.ConfigClass() config.kernel.name = "AL" subconfig = config.kernel.active subconfig.fitForBackground = True stride = 100 if inMi is None: width = 512 height = 2048 inMi = afwImage.MaskedImageF(afwGeom.Extent2I(width, height)) for j in num.arange(stride // 2, height, stride): j = int(j) for i in num.arange(stride // 2, width, stride): i = int(i) inMi._set((i - 1, j - 1), (100., 0x0, 1.), afwImage.LOCAL) inMi._set((i - 1, j + 0), (100., 0x0, 1.), afwImage.LOCAL) inMi._set((i - 1, j + 1), (100., 0x0, 1.), afwImage.LOCAL) inMi._set((i + 0, j - 1), (100., 0x0, 1.), afwImage.LOCAL) inMi._set((i + 0, j + 0), (100., 0x0, 1.), afwImage.LOCAL) inMi._set((i + 0, j + 1), (100., 0x0, 1.), afwImage.LOCAL) inMi._set((i + 1, j - 1), (100., 0x0, 1.), afwImage.LOCAL) inMi._set((i + 1, j + 0), (100., 0x0, 1.), afwImage.LOCAL) inMi._set((i + 1, j + 1), (100., 0x0, 1.), afwImage.LOCAL) addNoise(inMi) kSize = subconfig.kernelSize basicGaussian1 = afwMath.GaussianFunction2D(2., 2., 0.) basicKernel1 = afwMath.AnalyticKernel(kSize, kSize, basicGaussian1) basicGaussian2 = afwMath.GaussianFunction2D(5., 3., 0.5 * num.pi) basicKernel2 = afwMath.AnalyticKernel(kSize, kSize, basicGaussian2) basisList = [] basisList.append(basicKernel1) basisList.append(basicKernel2) spatialKernelFunction = afwMath.PolynomialFunction2D(orderMake) spatialKernel = afwMath.LinearCombinationKernel(basisList, spatialKernelFunction) kCoeffs = [[ 1.0 for x in range(1, spatialKernelFunction.getNParameters() + 1) ], [ 0.01 * x for x in range(1, spatialKernelFunction.getNParameters() + 1) ]] spatialKernel.setSpatialParameters(kCoeffs) cMi = afwImage.MaskedImageF(inMi.getDimensions()) convolutionControl = afwMath.ConvolutionControl() convolutionControl.setDoNormalize(True) afwMath.convolve(cMi, inMi, spatialKernel, convolutionControl) if display: afwDisplay.Display(frame=1).mtv(inMi.getImage()) afwDisplay.Display(frame=2).mtv(inMi.getVariance()) afwDisplay.Display(frame=3).mtv(cMi.getImage()) afwDisplay.Display(frame=4).mtv(cMi.getVariance()) subconfig.spatialKernelOrder = orderFit subconfig.sizeCellX = stride subconfig.sizeCellY = stride psfmatch = ipDiffim.ImagePsfMatchTask(config=config) candList = psfmatch.makeCandidateList(afwImage.ExposureF(inMi), afwImage.ExposureF(cMi), kSize) result = psfmatch.subtractMaskedImages(inMi, cMi, candList) spatialKernel = result.psfMatchingKernel kernelCellSet = result.kernelCellSet makeAutoCorrelation(kernelCellSet, spatialKernel, makePlot=True)
def setUp(self): width, height = 110, 301 self.mi = afwImage.MaskedImageF(afwGeom.ExtentI(width, height)) self.mi.set(0) sd = 3 # standard deviation of image self.mi.getVariance().set(sd*sd) self.mi.getMask().addMaskPlane("DETECTED") self.FWHM = 5 self.ksize = 31 # size of desired kernel sigma1 = 1.75 sigma2 = 2*sigma1 self.exposure = afwImage.makeExposure(self.mi) self.exposure.setPsf(measAlg.DoubleGaussianPsf(self.ksize, self.ksize, 1.5*sigma1, 1, 0.1)) crval = afwCoord.makeCoord(afwCoord.ICRS, 0.0*afwGeom.degrees, 0.0*afwGeom.degrees) wcs = afwImage.makeWcs(crval, afwGeom.PointD(0, 0), 1.0, 0, 0, 1.0) self.exposure.setWcs(wcs) ccd = cameraGeom.Ccd(cameraGeom.Id(1)) ccd.addAmp(cameraGeom.Amp(cameraGeom.Id(0), afwGeom.BoxI(afwGeom.PointI(0,0), self.exposure.getDimensions()), afwGeom.BoxI(afwGeom.PointI(0,0), afwGeom.ExtentI(0,0)), afwGeom.BoxI(afwGeom.PointI(0,0), self.exposure.getDimensions()), cameraGeom.ElectronicParams(1.0, 100.0, 65535))) self.exposure.setDetector(ccd) self.exposure.getDetector().setDistortion(None) # # Make a kernel with the exactly correct basis functions. Useful for debugging # basisKernelList = afwMath.KernelList() for sigma in (sigma1, sigma2): basisKernel = afwMath.AnalyticKernel(self.ksize, self.ksize, afwMath.GaussianFunction2D(sigma, sigma)) basisImage = afwImage.ImageD(basisKernel.getDimensions()) basisKernel.computeImage(basisImage, True) basisImage /= np.sum(basisImage.getArray()) if sigma == sigma1: basisImage0 = basisImage else: basisImage -= basisImage0 basisKernelList.append(afwMath.FixedKernel(basisImage)) order = 1 # 1 => up to linear spFunc = afwMath.PolynomialFunction2D(order) exactKernel = afwMath.LinearCombinationKernel(basisKernelList, spFunc) exactKernel.setSpatialParameters([[1.0, 0, 0], [0.0, 0.5*1e-2, 0.2e-2]]) rand = afwMath.Random() # make these tests repeatable by setting seed addNoise = True if addNoise: im = self.mi.getImage() afwMath.randomGaussianImage(im, rand) # N(0, 1) im *= sd # N(0, sd^2) del im xarr, yarr = [], [] for x, y in [(20, 20), (60, 20), (30, 35), (50, 50), (20, 90), (70, 160), (25, 265), (75, 275), (85, 30), (50, 120), (70, 80), (60, 210), (20, 210), ]: xarr.append(x) yarr.append(y) for x, y in zip(xarr, yarr): dx = rand.uniform() - 0.5 # random (centered) offsets dy = rand.uniform() - 0.5 k = exactKernel.getSpatialFunction(1)(x, y) # functional variation of Kernel ... b = (k*sigma1**2/((1 - k)*sigma2**2)) # ... converted double Gaussian's "b" #flux = 80000 - 20*x - 10*(y/float(height))**2 flux = 80000*(1 + 0.1*(rand.uniform() - 0.5)) I0 = flux*(1 + b)/(2*np.pi*(sigma1**2 + b*sigma2**2)) for iy in range(y - self.ksize//2, y + self.ksize//2 + 1): if iy < 0 or iy >= self.mi.getHeight(): continue for ix in range(x - self.ksize//2, x + self.ksize//2 + 1): if ix < 0 or ix >= self.mi.getWidth(): continue I = I0*psfVal(ix, iy, x + dx, y + dy, sigma1, sigma2, b) Isample = rand.poisson(I) if addNoise else I self.mi.getImage().set(ix, iy, self.mi.getImage().get(ix, iy) + Isample) self.mi.getVariance().set(ix, iy, self.mi.getVariance().get(ix, iy) + I) # bbox = afwGeom.BoxI(afwGeom.PointI(0,0), afwGeom.ExtentI(width, height)) self.cellSet = afwMath.SpatialCellSet(bbox, 100) self.footprintSet = afwDetection.FootprintSet(self.mi, afwDetection.Threshold(100), "DETECTED") self.catalog = SpatialModelPsfTestCase.measure(self.footprintSet, self.exposure) for source in self.catalog: try: cand = measAlg.makePsfCandidate(source, self.exposure) self.cellSet.insertCandidate(cand) except Exception, e: print e continue
def testSVLinearCombinationKernelFixed(self): """Test a spatially varying LinearCombinationKernel whose bases are FixedKernels""" kWidth = 3 kHeight = 2 # create image arrays for the basis kernels basisImArrList = [] imArr = np.zeros((kWidth, kHeight), dtype=float) imArr += 0.1 imArr[kWidth//2, :] = 0.9 basisImArrList.append(imArr) imArr = np.zeros((kWidth, kHeight), dtype=float) imArr += 0.2 imArr[:, kHeight//2] = 0.8 basisImArrList.append(imArr) # create a list of basis kernels from the images basisKernelList = [] for basisImArr in basisImArrList: basisImage = afwImage.makeImageFromArray( basisImArr.transpose().copy()) kernel = afwMath.FixedKernel(basisImage) basisKernelList.append(kernel) # create spatially varying linear combination kernel spFunc = afwMath.PolynomialFunction2D(1) # spatial parameters are a list of entries, one per kernel parameter; # each entry is a list of spatial parameters sParams = ( (0.0, 1.0, 0.0), (0.0, 0.0, 1.0), ) kernel = afwMath.LinearCombinationKernel(basisKernelList, spFunc) self.assertFalse(kernel.isDeltaFunctionBasis()) self.basicTests(kernel, 2, nSpatialParams=3) kernel.setSpatialParameters(sParams) kImage = afwImage.ImageD(lsst.geom.Extent2I(kWidth, kHeight)) for colPos, rowPos, coeff0, coeff1 in [ (0.0, 0.0, 0.0, 0.0), (1.0, 0.0, 1.0, 0.0), (0.0, 1.0, 0.0, 1.0), (1.0, 1.0, 1.0, 1.0), (0.5, 0.5, 0.5, 0.5), ]: kernel.computeImage(kImage, False, colPos, rowPos) kImArr = kImage.getArray().transpose() refKImArr = (basisImArrList[0] * coeff0) + \ (basisImArrList[1] * coeff1) if not np.allclose(kImArr, refKImArr): self.fail(f"{kernel.__class__.__name__} = {kImArr} != " f"{refKImArr} at colPos={colPos}, rowPos={rowPos}") sParams = ( (0.1, 1.0, 0.0), (0.1, 0.0, 1.0), ) kernel.setSpatialParameters(sParams) kernelClone = kernel.clone() errStr = self.compareKernels(kernel, kernelClone) if errStr: self.fail(errStr) newSParams = ( (0.1, 0.2, 0.5), (0.1, 0.5, 0.2), ) kernel.setSpatialParameters(newSParams) errStr = self.compareKernels(kernel, kernelClone) if not errStr: self.fail( "Clone was modified by changing original's spatial parameters")
def makeFakeKernelSet(sizeCell=128, nCell=3, deltaFunctionCounts=1.e4, tGaussianWidth=1.0, addNoise=True, bgValue=100., display=False): """Generate test template and science images with sources. Parameters ---------- sizeCell : `int`, optional Size of the square spatial cells in pixels. nCell : `int`, optional Number of adjacent spatial cells in both direction in both images. deltaFunctionCounts : `float`, optional Flux value for the template image sources. tGaussianWidth : `float`, optional Sigma of the generated Gaussian PSF sources in the template image. addNoise : `bool`, optional If `True`, Poisson noise is added to both the generated template and science images. bgValue : `float`, optional Background level to be added to the generated science image. display : `bool`, optional If `True` displays the generated template and science images by `lsst.afw.display.Display`. Notes ----- - The generated images consist of adjacent ``nCell x nCell`` cells, each of pixel size ``sizeCell x sizeCell``. - The sources in the science image are generated by convolving the template by ``sKernel``. ``sKernel`` is a spatial `LinearCombinationKernel` of hard wired kernel bases functions. The linear combination has first order polynomial spatial dependence with polynomial parameters from ``fakeCoeffs()``. - The template image sources are generated in the center of each spatial cell from one pixel, set to `deltaFunctionCounts` counts, then convolved by a 2D Gaussian with sigma of `tGaussianWidth` along each axis. - The sources are also returned in ``kernelCellSet`` each source is "detected" exactly at the center of a cell. Returns ------- tMi : `lsst.afw.image.MaskedImage` Generated template image. sMi : `lsst.afw.image.MaskedImage` Generated science image. sKernel : `lsst.afw.math.LinearCombinationKernel` The spatial kernel used to generate the sources in the science image. kernelCellSet : `lsst.afw.math.SpatialCellSet` Cell grid of `lsst.afw.math.SpatialCell` instances, containing `lsst.ip.diffim.KernelCandidate` instances around all the generated sources in the science image. configFake : `lsst.ip.diffim.ImagePsfMatchConfig` Config instance used in the image generation. """ from . import imagePsfMatch configFake = imagePsfMatch.ImagePsfMatchConfig() configFake.kernel.name = "AL" subconfigFake = configFake.kernel.active subconfigFake.alardNGauss = 1 subconfigFake.alardSigGauss = [ 2.5, ] subconfigFake.alardDegGauss = [ 2, ] subconfigFake.sizeCellX = sizeCell subconfigFake.sizeCellY = sizeCell subconfigFake.spatialKernelOrder = 1 subconfigFake.spatialModelType = "polynomial" subconfigFake.singleKernelClipping = False # variance is a hack subconfigFake.spatialKernelClipping = False # variance is a hack if bgValue > 0.0: subconfigFake.fitForBackground = True psFake = pexConfig.makePropertySet(subconfigFake) basisList = makeKernelBasisList(subconfigFake) kSize = subconfigFake.kernelSize # This sets the final extent of each convolved delta function gaussKernelWidth = sizeCell // 2 # This sets the scale over which pixels are correlated in the # spatial convolution; should be at least as big as the kernel you # are trying to fit for spatialKernelWidth = kSize # Number of bad pixels due to convolutions border = (gaussKernelWidth + spatialKernelWidth) // 2 # Make a fake image with a matrix of delta functions totalSize = nCell * sizeCell + 2 * border tim = afwImage.ImageF(geom.Extent2I(totalSize, totalSize)) for x in range(nCell): for y in range(nCell): tim[x * sizeCell + sizeCell // 2 + border - 1, y * sizeCell + sizeCell // 2 + border - 1, afwImage.LOCAL] = deltaFunctionCounts # Turn this into stars with a narrow width; conserve counts gaussFunction = afwMath.GaussianFunction2D(tGaussianWidth, tGaussianWidth) gaussKernel = afwMath.AnalyticKernel(gaussKernelWidth, gaussKernelWidth, gaussFunction) cim = afwImage.ImageF(tim.getDimensions()) convolutionControl = afwMath.ConvolutionControl() convolutionControl.setDoNormalize(True) afwMath.convolve(cim, tim, gaussKernel, convolutionControl) tim = cim # Trim off border pixels bbox = gaussKernel.shrinkBBox(tim.getBBox(afwImage.LOCAL)) tim = afwImage.ImageF(tim, bbox, afwImage.LOCAL) # Now make a science image which is this convolved with some # spatial function. Use input basis list. polyFunc = afwMath.PolynomialFunction2D(1) kCoeffs = fakeCoeffs() nToUse = min(len(kCoeffs), len(basisList)) # Make the full convolved science image sKernel = afwMath.LinearCombinationKernel(basisList[:nToUse], polyFunc) sKernel.setSpatialParameters(kCoeffs[:nToUse]) sim = afwImage.ImageF(tim.getDimensions()) convolutionControl = afwMath.ConvolutionControl() convolutionControl.setDoNormalize(True) afwMath.convolve(sim, tim, sKernel, convolutionControl) # Get the good subregion bbox = sKernel.shrinkBBox(sim.getBBox(afwImage.LOCAL)) # Add background sim += bgValue # Watch out for negative values tim += 2 * np.abs(np.min(tim.getArray())) # Add noise? if addNoise: sim = makePoissonNoiseImage(sim) tim = makePoissonNoiseImage(tim) # And turn into MaskedImages sim = afwImage.ImageF(sim, bbox, afwImage.LOCAL) svar = afwImage.ImageF(sim, True) smask = afwImage.Mask(sim.getDimensions()) smask.set(0x0) sMi = afwImage.MaskedImageF(sim, smask, svar) tim = afwImage.ImageF(tim, bbox, afwImage.LOCAL) tvar = afwImage.ImageF(tim, True) tmask = afwImage.Mask(tim.getDimensions()) tmask.set(0x0) tMi = afwImage.MaskedImageF(tim, tmask, tvar) if display: import lsst.afw.display as afwDisplay afwDisplay.Display(frame=1).mtv(tMi) afwDisplay.Display(frame=2).mtv(sMi) # Finally, make a kernelSet from these 2 images kernelCellSet = afwMath.SpatialCellSet( geom.Box2I(geom.Point2I(0, 0), geom.Extent2I(sizeCell * nCell, sizeCell * nCell)), sizeCell, sizeCell) stampHalfWidth = 2 * kSize for x in range(nCell): for y in range(nCell): xCoord = x * sizeCell + sizeCell // 2 yCoord = y * sizeCell + sizeCell // 2 p0 = geom.Point2I(xCoord - stampHalfWidth, yCoord - stampHalfWidth) p1 = geom.Point2I(xCoord + stampHalfWidth, yCoord + stampHalfWidth) bbox = geom.Box2I(p0, p1) tsi = afwImage.MaskedImageF(tMi, bbox, origin=afwImage.LOCAL) ssi = afwImage.MaskedImageF(sMi, bbox, origin=afwImage.LOCAL) kc = diffimLib.makeKernelCandidate(xCoord, yCoord, tsi, ssi, psFake) kernelCellSet.insertCandidate(kc) tMi.setXY0(0, 0) sMi.setXY0(0, 0) return tMi, sMi, sKernel, kernelCellSet, configFake