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 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 checkEdge(self, footprint): """Check that Footprint::findEdgePixels() works""" bbox = footprint.getBBox() bbox.grow(3) def makeImage(area): """Make an ImageF with 1 in the footprint, and 0 elsewhere""" ones = afwImage.ImageI(bbox) ones.set(1) image = afwImage.ImageI(bbox) image.set(0) if isinstance(area, afwDetect.Footprint): area.spans.copyImage(ones, image) if isinstance(area, afwGeom.SpanSet): area.copyImage(ones, image) return image edges = self.foot.spans.findEdgePixels() edgeImage = makeImage(edges) # Find edges with an edge-detection kernel image = makeImage(self.foot) kernel = afwImage.ImageD(3, 3) kernel[1, 1, afwImage.LOCAL] = 4 for x, y in [(1, 2), (0, 1), (1, 0), (2, 1)]: kernel[x, y, afwImage.LOCAL] = -1 kernel.setXY0(1, 1) result = afwImage.ImageI(bbox) result.set(0) afwMath.convolve(result, image, afwMath.FixedKernel(kernel), afwMath.ConvolutionControl(False)) result.getArray().__imul__(image.getArray()) trueEdges = np.where(result.getArray() > 0, 1, 0) self.assertTrue(np.all(trueEdges == edgeImage.getArray()))
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 makeExposure(imgArray, psfArray, imgVariance): """! Convert an image numpy.array and corresponding PSF numpy.array into an exposure. Add the (constant) variance plane equal to `imgVariance`. @param imgArray 2-d numpy.array containing the image @param psfArray 2-d numpy.array containing the PSF image @param imgVariance variance of input image @return a new exposure containing the image, PSF and desired variance plane """ # All this code to convert the template image array/psf array into an exposure. bbox = geom.Box2I( geom.Point2I(0, 0), geom.Point2I(imgArray.shape[1] - 1, imgArray.shape[0] - 1)) im1ex = afwImage.ExposureD(bbox) im1ex.getMaskedImage().getImage().getArray()[:, :] = imgArray im1ex.getMaskedImage().getVariance().getArray()[:, :] = imgVariance psfBox = geom.Box2I(geom.Point2I(-12, -12), geom.Point2I(12, 12)) # a 25x25 pixel psf psf = afwImage.ImageD(psfBox) psfBox.shift(geom.Extent2I(size[0] // 2, size[1] // 2)) im1_psf_sub = psfArray[psfBox.getMinX():psfBox.getMaxX() + 1, psfBox.getMinY():psfBox.getMaxY() + 1] psf.getArray()[:, :] = im1_psf_sub psfK = afwMath.FixedKernel(psf) psfNew = measAlg.KernelPsf(psfK) im1ex.setPsf(psfNew) wcs = makeWcs() im1ex.setWcs(wcs) return im1ex
def makeExposure(imgArray, psfArray, imgVariance): """Convert an image and corresponding PSF into an exposure. Set the (constant) variance plane equal to ``imgVariance``. Parameters ---------- imgArray : `numpy.ndarray` 2D array containing the image. psfArray : `numpy.ndarray` 2D array containing the PSF image. imgVariance : `float` or `numpy.ndarray` Set the variance plane to this value. If an array, must be broadcastable to ``imgArray.shape``. Returns ------- im1ex : `lsst.afw.image.Exposure` The new exposure. """ # All this code to convert the template image array/psf array into an exposure. bbox = geom.Box2I(geom.Point2I(0, 0), geom.Point2I(imgArray.shape[1] - 1, imgArray.shape[0] - 1)) im1ex = afwImage.ExposureD(bbox) im1ex.image.array[:, :] = imgArray im1ex.variance.array[:, :] = imgVariance psfBox = geom.Box2I(geom.Point2I(-12, -12), geom.Point2I(12, 12)) # a 25x25 pixel psf psf = afwImage.ImageD(psfBox) psfBox.shift(geom.Extent2I(-(-size[0]//2), -(-size[1]//2))) # -N//2 != -(N//2) for odd numbers im1_psf_sub = psfArray[psfBox.getMinY():psfBox.getMaxY() + 1, psfBox.getMinX():psfBox.getMaxX() + 1] psf.getArray()[:, :] = im1_psf_sub psfK = afwMath.FixedKernel(psf) psfNew = measAlg.KernelPsf(psfK) im1ex.setPsf(psfNew) wcs = makeWcs() im1ex.setWcs(wcs) return im1ex
def _doConvolve(exposure, kernel): """Convolve an Exposure with a decorrelation convolution kernel. Parameters ---------- exposure : `lsst.afw.image.Exposure` Input exposure to be convolved. kernel : `numpy.array` Input 2-d numpy.array to convolve the image with Returns ------- out : `lsst.afw.image.Exposure` a new Exposure with the convolved pixels and the (possibly re-centered) kernel. Notes ----- We re-center the kernel if necessary and return the possibly re-centered kernel """ kernelImg = afwImage.ImageD(kernel.shape[0], kernel.shape[1]) kernelImg.getArray()[:, :] = kernel kern = afwMath.FixedKernel(kernelImg) maxloc = np.unravel_index(np.argmax(kernel), kernel.shape) kern.setCtrX(maxloc[0]) kern.setCtrY(maxloc[1]) outExp = exposure.clone() # Do this to keep WCS, PSF, masks, etc. convCntrl = afwMath.ConvolutionControl(False, True, 0) afwMath.convolve(outExp.getMaskedImage(), exposure.getMaskedImage(), kern, convCntrl) return outExp, kern
def _makeAndTestUncorrectedDiffim(self): """Create the (un-decorrelated) diffim, and verify that its variance is too low. """ # Create the matching kernel. We used Gaussian PSFs for im1 and im2, so we can compute the "expected" # matching kernel sigma. psf1_sig = self.im1ex.getPsf().computeShape().getDeterminantRadius() psf2_sig = self.im2ex.getPsf().computeShape().getDeterminantRadius() sig_match = np.sqrt((psf1_sig**2. - psf2_sig**2.)) # Sanity check - make sure PSFs are correct. self.assertFloatsAlmostEqual(sig_match, np.sqrt((self.psf1_sigma**2. - self.psf2_sigma**2.)), rtol=2e-5) # mKernel = measAlg.SingleGaussianPsf(31, 31, sig_match) x0 = np.arange(-16, 16, 1) y0 = x0.copy() x0im, y0im = np.meshgrid(x0, y0) matchingKernel = singleGaussian2d(x0im, y0im, -1., -1., sigma_x=sig_match, sigma_y=sig_match) kernelImg = afwImage.ImageD(matchingKernel.shape[0], matchingKernel.shape[1]) kernelImg.getArray()[:, :] = matchingKernel mKernel = afwMath.FixedKernel(kernelImg) # Create the matched template by convolving the template with the matchingKernel matched_im2ex = self.im2ex.clone() convCntrl = afwMath.ConvolutionControl(False, True, 0) afwMath.convolve(matched_im2ex.getMaskedImage(), self.im2ex.getMaskedImage(), mKernel, convCntrl) # Expected (ideal) variance of difference image expected_var = self.svar + self.tvar if verbose: print('EXPECTED VARIANCE:', expected_var) # Create the diffim (uncorrected) # Uncorrected diffim exposure - variance plane is wrong (too low) tmp_diffExp = self.im1ex.getMaskedImage().clone() tmp_diffExp -= matched_im2ex.getMaskedImage() var = self._computeVarianceMean(tmp_diffExp) self.assertLess(var, expected_var) # Uncorrected diffim exposure - variance is wrong (too low) - same as above but on pixels diffExp = self.im1ex.clone() tmp = diffExp.getMaskedImage() tmp -= matched_im2ex.getMaskedImage() var = self._computePixelVariance(diffExp.getMaskedImage()) self.assertLess(var, expected_var) # Uncorrected diffim exposure - variance plane is wrong (too low) mn = self._computeVarianceMean(diffExp.getMaskedImage()) self.assertLess(mn, expected_var) if verbose: print('UNCORRECTED VARIANCE:', var, mn) return diffExp, mKernel, expected_var
def checkEdge(self, footprint): """Check that Footprint::findEdgePixels() works""" bbox = footprint.getBBox() bbox.grow(3) def makeImage(footprint): """Make an ImageF with 1 in the footprint, and 0 elsewhere""" ones = afwImage.ImageI(bbox) ones.set(1) image = afwImage.ImageI(bbox) image.set(0) afwDetect.copyWithinFootprintImage(footprint, ones, image) return image edges = self.foot.findEdgePixels() edgeImage = makeImage(edges) # Find edges with an edge-detection kernel image = makeImage(self.foot) kernel = afwImage.ImageD(3, 3) kernel.set(1, 1, 4) for x, y in [(1, 2), (0, 1), (1, 0), (2, 1)]: kernel.set(x, y, -1) kernel.setXY0(1, 1) result = afwImage.ImageI(bbox) result.set(0) afwMath.convolve(result, image, afwMath.FixedKernel(kernel), afwMath.ConvolutionControl(False)) result.getArray().__imul__(image.getArray()) trueEdges = numpy.where(result.getArray() > 0, 1, 0) self.assertTrue(numpy.all(trueEdges == edgeImage.getArray()))
def performALZCExposureCorrection(templateExposure, exposure, subtractedExposure, psfMatchingKernel, log): kimg = alPsfMatchingKernelToArray(psfMatchingKernel, subtractedExposure) # Compute the images' sigmas (sqrt of variance) sig1 = templateExposure.getMaskedImage().getVariance().getArray() sig2 = exposure.getMaskedImage().getVariance().getArray() sig1squared, _, _, _ = computeClippedImageStats(sig1) sig2squared, _, _, _ = computeClippedImageStats(sig2) corrKernel = computeDecorrelationKernel(kimg, sig1squared, sig2squared) # Eventually, use afwMath.convolve(), but for now just use scipy. log.info("ALZC: Convolving.") pci, _ = doConvolve( subtractedExposure.getMaskedImage().getImage().getArray(), corrKernel) subtractedExposure.getMaskedImage().getImage().getArray()[:, :] = pci log.info("ALZC: Finished with convolution.") # Compute the subtracted exposure's updated psf psf = afwPsfToArray(subtractedExposure.getPsf(), subtractedExposure) # .computeImage().getArray() psfc = computeCorrectedDiffimPsf(corrKernel, psf, svar=sig1squared, tvar=sig2squared) psfcI = afwImage.ImageD( subtractedExposure.getPsf().computeKernelImage().getBBox()) psfcI.getArray()[:, :] = psfc psfcK = afwMath.FixedKernel(psfcI) psfNew = measAlg.KernelPsf(psfcK) subtractedExposure.setPsf(psfNew) return subtractedExposure, corrKernel
def makeHSCExposure(self, galData, psfData, pixScale, variance): ny, nx = galData.shape exposure = afwImg.ExposureF(nx, ny) exposure.getMaskedImage().getImage().getArray()[:, :] = galData exposure.getMaskedImage().getVariance().getArray()[:, :] = variance #Set the PSF ngridPsf = psfData.shape[0] psfLsst = afwImg.ImageF(ngridPsf, ngridPsf) psfLsst.getArray()[:, :] = psfData psfLsst = psfLsst.convertD() kernel = afwMath.FixedKernel(psfLsst) kernelPSF = meaAlg.KernelPsf(kernel) exposure.setPsf(kernelPSF) #prepare the wcs #Rotation cdelt = (pixScale * afwGeom.arcseconds) CD = afwGeom.makeCdMatrix(cdelt, afwGeom.Angle(0.)) #no rotation #wcs crval = afwGeom.SpherePoint(afwGeom.Angle(0., afwGeom.degrees), afwGeom.Angle(0., afwGeom.degrees)) #crval = afwCoord.IcrsCoord(0.*afwGeom.degrees, 0.*afwGeom.degrees) # hscpipe6 crpix = afwGeom.Point2D(0.0, 0.0) dataWcs = afwGeom.makeSkyWcs(crpix, crval, CD) exposure.setWcs(dataWcs) #prepare the frc dataCalib = afwImg.makePhotoCalibFromCalibZeroPoint(63095734448.0194) exposure.setPhotoCalib(dataCalib) return exposure
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 arrayToAfwKernel(array): kernelImg = afwImage.ImageD(array.shape[1], array.shape[0]) kernelImg.getArray()[:, :] = array kern = afwMath.FixedKernel(kernelImg) maxloc = np.unravel_index(np.argmax(array), array.shape) kern.setCtrX(maxloc[0]) kern.setCtrY(maxloc[1]) return kern
def doALdecorrelation(alTaskResult, sig1squared=None, sig2squared=None, preConvKernel=None): kimg = alPsfMatchingKernelToArray(alTaskResult.psfMatchingKernel, alTaskResult.subtractedExposure) if preConvKernel is not None and kimg.shape[0] < preConvKernel.shape[0]: # This is likely brittle and may only work if both kernels are odd-shaped. #kimg[np.abs(kimg) < 1e-4] = np.sign(kimg)[np.abs(kimg) < 1e-4] * 1e-8 #kimg -= kimg[0, 0] padSize0 = preConvKernel.shape[0] // 2 - kimg.shape[0] // 2 padSize1 = preConvKernel.shape[1] // 2 - kimg.shape[1] // 2 kimg = np.pad(kimg, ((padSize0, padSize0), (padSize1, padSize1)), mode='constant', constant_values=0) #kimg /= kimg.sum() #preConvKernel = preConvKernel[padSize0:-padSize0, padSize1:-padSize1] if sig1squared is None: sig1squared = computeVarianceMean(im1) if sig2squared is None: sig2squared = computeVarianceMean(im2) pck = computeDecorrelationKernel(kimg, sig1squared, sig2squared, preConvKernel=preConvKernel, delta=0.) #return kimg, preConvKernel, pck diffim, _ = doConvolve(alTaskResult.subtractedExposure, pck, use_scipy=False) # For some reason, border areas of img and variance planes can become infinite. Fix it. img = diffim.getMaskedImage().getImage().getArray() img[~np.isfinite(img)] = np.nan img = diffim.getMaskedImage().getVariance().getArray() img[~np.isfinite(img)] = np.nan # TBD: also need to update the mask as it is not (apparently) set correctly. psf = afwPsfToArray(alTaskResult.subtractedExposure.getPsf(), img=alTaskResult.subtractedExposure) # NOTE! Need to compute the updated PSF including preConvKernel !!! This doesn't do it: psfc = computeCorrectedDiffimPsf(kimg, psf, tvar=sig1squared, svar=sig2squared) psfcI = afwImage.ImageD(psfc.shape[0], psfc.shape[1]) psfcI.getArray()[:, :] = psfc psfcK = afwMath.FixedKernel(psfcI) psfNew = measAlg.KernelPsf(psfcK) diffim.setPsf(psfNew) alTaskResult.decorrelatedDiffim = diffim alTaskResult.preConvKernel = preConvKernel alTaskResult.decorrelationKernel = pck alTaskResult.kappaImg = kimg return alTaskResult
def testSVAnalyticKernel(self): """Test spatially varying AnalyticKernel using a Gaussian function Just tests cloning. """ kWidth = 5 kHeight = 8 # spatial model spFunc = 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, 1.0, 0.0), (1.0, 0.0, 1.0), (0.5, 0.5, 0.5), ) gaussFunc = afwMath.GaussianFunction2D(1.0, 1.0, 0.0) kernel = afwMath.AnalyticKernel(kWidth, kHeight, gaussFunc, spFunc) 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), (0.2, 0.3, 0.3), ) kernel.setSpatialParameters(newSParams) errStr = self.compareKernels(kernel, kernelClone) if not errStr: self.fail( "Clone was modified by changing original's spatial parameters") # # check that we can construct a FixedKernel from a LinearCombinationKernel # x, y = 100, 200 kernel2 = afwMath.FixedKernel(kernel, lsst.geom.PointD(x, y)) self.assertTrue(re.search("AnalyticKernel", kernel.toString())) self.assertFalse(kernel2.isSpatiallyVarying()) self.assertTrue(re.search("FixedKernel", kernel2.toString())) self.assertTrue(kernel.isSpatiallyVarying()) kim = afwImage.ImageD(kernel.getDimensions()) kernel.computeImage(kim, True, x, y) kim2 = afwImage.ImageD(kernel2.getDimensions()) kernel2.computeImage(kim2, True) assert_allclose(kim.getArray(), kim2.getArray())
def doConvolve(exposure, kernel, use_scipy=False): """! Convolve an Exposure with a decorrelation convolution kernel. @param exposure Input afw.image.Exposure to be convolved. @param kernel Input 2-d numpy.array to convolve the image with @param use_scipy Use scipy to do convolution instead of afwMath @return a new Exposure with the convolved pixels and the (possibly re-centered) kernel. @note We use afwMath.convolve() but keep scipy.convolve for debugging. @note We re-center the kernel if necessary and return the possibly re-centered kernel """ def _fixEvenKernel(kernel): """! Take a kernel with even dimensions and make them odd, centered correctly. @param kernel a numpy.array @return a fixed kernel numpy.array """ # Make sure the peak (close to a delta-function) is in the center! maxloc = np.unravel_index(np.argmax(kernel), kernel.shape) out = np.roll(kernel, kernel.shape[0] // 2 - maxloc[0], axis=0) out = np.roll(out, out.shape[1] // 2 - maxloc[1], axis=1) # Make sure it is odd-dimensioned by trimming it. if (out.shape[0] % 2) == 0: maxloc = np.unravel_index(np.argmax(out), out.shape) if out.shape[0] - maxloc[0] > maxloc[0]: out = out[:-1, :] else: out = out[1:, :] if out.shape[1] - maxloc[1] > maxloc[1]: out = out[:, :-1] else: out = out[:, 1:] return out outExp = kern = None fkernel = _fixEvenKernel(kernel) if use_scipy: from scipy.ndimage.filters import convolve pci = convolve(exposure.getMaskedImage().getImage().getArray(), fkernel, mode='constant', cval=np.nan) outExp = exposure.clone() outExp.getMaskedImage().getImage().getArray()[:, :] = pci kern = fkernel else: kernelImg = afwImage.ImageD(fkernel.shape[0], fkernel.shape[1]) kernelImg.getArray()[:, :] = fkernel kern = afwMath.FixedKernel(kernelImg) maxloc = np.unravel_index(np.argmax(fkernel), fkernel.shape) kern.setCtrX(maxloc[0]) kern.setCtrY(maxloc[1]) outExp = exposure.clone() # Do this to keep WCS, PSF, masks, etc. convCntrl = afwMath.ConvolutionControl(False, True, 0) afwMath.convolve(outExp.getMaskedImage(), exposure.getMaskedImage(), kern, convCntrl) return outExp, kern
def assess(self, cand, kFn1, bgFn1, kFn2, bgFn2, frame0): tmi = cand.getTemplateMaskedImage() smi = cand.getScienceMaskedImage() im1 = afwImage.ImageD(kFn1.getDimensions()) kFn1.computeImage(im1, False, afwImage.indexToPosition(int(cand.getXCenter())), afwImage.indexToPosition(int(cand.getYCenter()))) fk1 = afwMath.FixedKernel(im1) bg1 = bgFn1(afwImage.indexToPosition(int(cand.getXCenter())), afwImage.indexToPosition(int(cand.getYCenter()))) d1 = ipDiffim.convolveAndSubtract(tmi, smi, fk1, bg1) #### im2 = afwImage.ImageD(kFn2.getDimensions()) kFn2.computeImage(im2, False, afwImage.indexToPosition(int(cand.getXCenter())), afwImage.indexToPosition(int(cand.getYCenter()))) fk2 = afwMath.FixedKernel(im2) bg2 = bgFn2(afwImage.indexToPosition(int(cand.getXCenter())), afwImage.indexToPosition(int(cand.getYCenter()))) d2 = ipDiffim.convolveAndSubtract(tmi, smi, fk2, bg2) if display: disp = afwDisplay.Display(frame=frame0) disp.mtv(tmi, title="Template Masked Image") disp.dot("Cand %d" % (cand.getId()), 0, 0) afwDisplay.Display(frame=frame0 + 1).mtv( smi, title="Science Masked Image") afwDisplay.Display(frame=frame0 + 2).mtv(im1, title="Masked Image: 1") afwDisplay.Display(frame=frame0 + 3).mtv( d1, title="Difference Image: 1") afwDisplay.Display(frame=frame0 + 4).mtv(im2, title="Masked Image: 2") afwDisplay.Display(frame=frame0 + 5).mtv( d2, title="Difference Image: 2") logger.debug("Full Spatial Model") self.stats(cand.getId(), d1) logger.debug("N-1 Spatial Model") self.stats(cand.getId(), d2)
def _setNewPsf(self, exposure, psfArr): """Utility method to set an exposure's PSF when provided as a 2-d numpy.array """ psfI = afwImage.ImageD(psfArr.shape[0], psfArr.shape[1]) psfI.getArray()[:, :] = psfArr psfK = afwMath.FixedKernel(psfI) psfNew = measAlg.KernelPsf(psfK) exposure.setPsf(psfNew) return exposure
def makeRatingVector(kernelCellSet, spatialKernel, spatialBg): imstats = diffimLib.ImageStatisticsF() #sdqaVector = sdqa.SdqaRatingSet() width, height = spatialKernel.getDimensions() kImage = afwImage.ImageD(width, height) # find the kernel sum and its Rms by looking at the 4 corners of the image kSums = afwMath.vectorD() for x in (0, width): for y in (0, height): kSum = spatialKernel.computeImage(kImage, False, x, y) kSums.push_back(kSum) #afwStat = afwMath.makeStatistics(kSums, afwMath.MEAN | afwMath.STDEV) #kSumRating = sdqa.SdqaRating("lsst.ip.diffim.kernel_sum", # afwStat.getValue(afwMath.MEAN), # afwStat.getValue(afwMath.STDEV), # scope) #sdqaVector.append(kSumRating) nGood = 0 nBad = 0 for cell in kernelCellSet.getCellList(): for cand in cell.begin(False): # False = include bad candidates cand = diffimLib.cast_KernelCandidateF(cand) if cand.getStatus() == afwMath.SpatialCellCandidate.GOOD: # this has been used for processing nGood += 1 xCand = int(cand.getXCenter()) yCand = int(cand.getYCenter()) # evaluate kernel and background at position of candidate kSum = spatialKernel.computeImage(kImage, False, xCand, yCand) kernel = afwMath.FixedKernel(kImage) background = spatialBg(xCand, yCand) diffIm = cand.getDifferenceImage(kernel, background) imstats.apply(diffIm) #candMean = imstats.getMean() #candRms = imstats.getRms() #candRating = sdqa.SdqaRating("lsst.ip.diffim.residuals_%d_%d" % (xCand, yCand), # candMean, candRms, scope) #sdqaVector.append(candRating) elif cand.getStatus() == afwMath.SpatialCellCandidate.BAD: nBad += 1 #nGoodRating = sdqa.SdqaRating("lsst.ip.diffim.nCandGood", nGood, 0, scope) #sdqaVector.append(nGoodRating) #nBadRating = sdqa.SdqaRating("lsst.ip.diffim.nCandBad", nBad, 0, scope) #sdqaVector.append(nBadRating) nKernelTerms = spatialKernel.getNSpatialParameters() if nKernelTerms == 0: # order 0 nKernelTerms = 1
def runMeasurement(self, algorithmName, imageid, x, y, v): """Run the measurement algorithm on an image""" # load the test image imgFile = os.path.join(self.dataDir, "image.%d.fits" % imageid) img = afwImage.ImageF(imgFile) img -= self.bkgd nx, ny = img.getWidth(), img.getHeight() msk = afwImage.Mask(geom.Extent2I(nx, ny), 0x0) var = afwImage.ImageF(geom.Extent2I(nx, ny), v) mimg = afwImage.MaskedImageF(img, msk, var) msk.getArray()[:] = np.where(np.fabs(img.getArray()) < 1.0e-8, msk.getPlaneBitMask("BAD"), 0) # Put it in a bigger image, in case it matters big = afwImage.MaskedImageF(self.offset + mimg.getDimensions()) big.getImage().set(0) big.getMask().set(0) big.getVariance().set(v) subBig = afwImage.MaskedImageF(big, geom.Box2I(big.getXY0() + self.offset, mimg.getDimensions())) subBig <<= mimg mimg = big mimg.setXY0(self.xy0) exposure = afwImage.makeExposure(mimg) cdMatrix = np.array([1.0/(2.53*3600.0), 0.0, 0.0, 1.0/(2.53*3600.0)]) cdMatrix.shape = (2, 2) exposure.setWcs(afwGeom.makeSkyWcs(crpix=geom.Point2D(1.0, 1.0), crval=geom.SpherePoint(0, 0, geom.degrees), cdMatrix=cdMatrix)) # load the corresponding test psf psfFile = os.path.join(self.dataDir, "psf.%d.fits" % imageid) psfImg = afwImage.ImageD(psfFile) psfImg -= self.bkgd kernel = afwMath.FixedKernel(psfImg) kernelPsf = algorithms.KernelPsf(kernel) exposure.setPsf(kernelPsf) # perform the shape measurement msConfig = base.SingleFrameMeasurementConfig() alg = base.SingleFramePlugin.registry[algorithmName].PluginClass.AlgClass control = base.SingleFramePlugin.registry[algorithmName].PluginClass.ConfigClass().makeControl() msConfig.algorithms.names = [algorithmName] # Note: It is essential to remove the floating point part of the position for the # Algorithm._apply. Otherwise, when the PSF is realised it will have been warped # to account for the sub-pixel offset and we won't get *exactly* this PSF. plugin, table = makePluginAndCat(alg, algorithmName, control, centroid="centroid") center = geom.Point2D(int(x), int(y)) + geom.Extent2D(self.offset + geom.Extent2I(self.xy0)) source = table.makeRecord() source.set("centroid_x", center.getX()) source.set("centroid_y", center.getY()) source.setFootprint(afwDetection.Footprint(afwGeom.SpanSet(exposure.getBBox(afwImage.PARENT)))) plugin.measure(source, exposure) return source
def assess(self, cand, kFn1, bgFn1, kFn2, bgFn2, frame0): tmi = cand.getTemplateMaskedImage() smi = cand.getScienceMaskedImage() im1 = afwImage.ImageD(kFn1.getDimensions()) kFn1.computeImage(im1, False, afwImage.indexToPosition(int(cand.getXCenter())), afwImage.indexToPosition(int(cand.getYCenter()))) fk1 = afwMath.FixedKernel(im1) bg1 = bgFn1(afwImage.indexToPosition(int(cand.getXCenter())), afwImage.indexToPosition(int(cand.getYCenter()))) d1 = ipDiffim.convolveAndSubtract(tmi, smi, fk1, bg1) #### im2 = afwImage.ImageD(kFn2.getDimensions()) kFn2.computeImage(im2, False, afwImage.indexToPosition(int(cand.getXCenter())), afwImage.indexToPosition(int(cand.getYCenter()))) fk2 = afwMath.FixedKernel(im2) bg2 = bgFn2(afwImage.indexToPosition(int(cand.getXCenter())), afwImage.indexToPosition(int(cand.getYCenter()))) d2 = ipDiffim.convolveAndSubtract(tmi, smi, fk2, bg2) if display: ds9.mtv(tmi, frame=frame0+0) ds9.dot("Cand %d" % (cand.getId()), 0, 0, frame=frame0+0) ds9.mtv(smi, frame=frame0+1) ds9.mtv(im1, frame=frame0+2) ds9.mtv(d1, frame=frame0+3) ds9.mtv(im2, frame=frame0+4) ds9.mtv(d2, frame=frame0+5) pexLog.Trace("lsst.ip.diffim.JackknifeResampleKernel", 1, "Full Spatial Model") self.stats(cand.getId(), d1) pexLog.Trace("lsst.ip.diffim.JackknifeResampleKernel", 1, "N-1 Spatial Model") self.stats(cand.getId(), d2)
def testFixedKernelConvolve(self): """Test convolve with a fixed kernel """ kWidth = 6 kHeight = 7 kFunc = afwMath.GaussianFunction2D(2.5, 1.5, 0.5) analyticKernel = afwMath.AnalyticKernel(kWidth, kHeight, kFunc) kernelImage = afwImage.ImageD(afwGeom.Extent2I(kWidth, kHeight)) analyticKernel.computeImage(kernelImage, False) fixedKernel = afwMath.FixedKernel(kernelImage) self.runStdTest(fixedKernel, kernelDescr="Gaussian FixedKernel")
def testFixedKernel(self): """Test FixedKernel using a ramp function """ kWidth = 5 kHeight = 6 inArr = np.arange(kWidth * kHeight, dtype=float) inArr.shape = [kWidth, kHeight] inImage = afwImage.ImageD(afwGeom.Extent2I(kWidth, kHeight)) for row in range(inImage.getHeight()): for col in range(inImage.getWidth()): inImage.set(col, row, inArr[col, row]) k = afwMath.FixedKernel(inImage) pol = pexPolicy.Policy() additionalData = dafBase.PropertySet() loc = dafPersist.LogicalLocation( os.path.join(testPath, "data", "kernel1.boost")) persistence = dafPersist.Persistence.getPersistence(pol) 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("FixedKernel", storageList2, additionalData) k2 = afwMath.FixedKernel.swigConvert(x) self.kernelCheck(k, k2) outImage = afwImage.ImageD(k2.getDimensions()) k2.computeImage(outImage, False) outArr = outImage.getArray().transpose() if not np.allclose(inArr, outArr): self.fail("%s = %s != %s (not normalized)" % (k2.__class__.__name__, inArr, outArr)) normInArr = inArr / inArr.sum() normOutImage = afwImage.ImageD(k2.getDimensions()) k2.computeImage(normOutImage, True) normOutArr = normOutImage.getArray().transpose() if not np.allclose(normOutArr, normInArr): self.fail("%s = %s != %s (normalized)" % (k2.__class__.__name__, normInArr, normOutArr))
def _growPsf(exp, extraPix=(2, 3)): bbox = exp.getBBox() center = ((bbox.getBeginX() + bbox.getEndX()) // 2., (bbox.getBeginY() + bbox.getEndY()) // 2.) center = geom.Point2D(center[0], center[1]) kern = exp.getPsf().computeKernelImage(center).convertF() kernSize = kern.getDimensions() paddedKern = afwImage.ImageF(kernSize[0] + extraPix[0], kernSize[1] + extraPix[1]) bboxToPlace = geom.Box2I(geom.Point2I((kernSize[0] + extraPix[0] - kern.getWidth()) // 2, (kernSize[1] + extraPix[1] - kern.getHeight()) // 2), kern.getDimensions()) paddedKern.assign(kern, bboxToPlace) fixedKern = afwMath.FixedKernel(paddedKern.convertD()) psfNew = measAlg.KernelPsf(fixedKern, center) exp.setPsf(psfNew) return exp
def makeKernelPsfFromArray(A): """Create a non spatially varying PSF from a `numpy.ndarray`. Parameters ---------- A : `numpy.ndarray` 2D array to use as the new psf image. The pixels are copied. Returns ------- psfNew : `lsst.meas.algorithms.KernelPsf` The constructed PSF. """ psfImg = afwImage.ImageD(A.astype(np.float64, copy=True), deep=False) psfNew = measAlg.KernelPsf(afwMath.FixedKernel(psfImg)) return psfNew
def writeKernelCellSet(kernelCellSet, psfMatchingKernel, backgroundModel, outdir): """TODO: DM-17458 Parameters ---------- kernelCellSet : TODO: DM-17458 TODO: DM-17458 psfMatchingKernel : TODO: DM-17458 TODO: DM-17458 backgroundModel : TODO: DM-17458 TODO: DM-17458 outdir : TODO: DM-17458 TODO: DM-17458 """ if not os.path.isdir(outdir): os.makedirs(outdir) for cell in kernelCellSet.getCellList(): for cand in cell.begin(False): # False = include bad candidates if cand.getStatus() == afwMath.SpatialCellCandidate.GOOD: xCand = int(cand.getXCenter()) yCand = int(cand.getYCenter()) idCand = cand.getId() diffIm = cand.getDifferenceImage( diffimLib.KernelCandidateF.ORIG) kernel = cand.getKernelImage(diffimLib.KernelCandidateF.ORIG) diffIm.writeFits( os.path.join( outdir, 'diffim_c%d_x%d_y%d.fits' % (idCand, xCand, yCand))) kernel.writeFits( os.path.join( outdir, 'kernel_c%d_x%d_y%d.fits' % (idCand, xCand, yCand))) # Diffim from spatial model ski = afwImage.ImageD(kernel.getDimensions()) psfMatchingKernel.computeImage(ski, False, xCand, yCand) sk = afwMath.FixedKernel(ski) sbg = backgroundModel(xCand, yCand) sdmi = cand.getDifferenceImage(sk, sbg) sdmi.writeFits( os.path.join( outdir, 'sdiffim_c%d_x%d_y%d.fits' % (idCand, xCand, yCand)))
def getCoaddPsf(self, exposure): import lsst.afw.table as afwTable import lsst.afw.image as afwImage import lsst.afw.math as afwMath import lsst.afw.geom as afwGeom import lsst.meas.algorithms as measAlg schema = afwTable.ExposureTable.makeMinimalSchema() schema.addField("weight", type="D", doc="Coadd weight") mycatalog = afwTable.ExposureCatalog(schema) wcsref = exposure.getWcs() extentX = int(exposure.getWidth() * 0.05) extentY = int(exposure.getHeight() * 0.05) ind = 0 for x in np.linspace(extentX, exposure.getWidth() - extentX, 10): for y in np.linspace(extentY, exposure.getHeight() - extentY, 10): x = int(x) y = int(y) image = self.getImage(x, y) psf = afwImage.ImageD(image.shape[0], image.shape[1]) psf.getArray()[:, :] = image psfK = afwMath.FixedKernel(psf) psf = measAlg.KernelPsf(psfK) record = mycatalog.getTable().makeRecord() record.setPsf(psf) record.setWcs(wcsref) bbox = afwGeom.Box2I( afwGeom.Point2I( int(np.floor(x - extentX)) - 5, int(np.floor(y - extentY)) - 5), afwGeom.Point2I( int(np.floor(x + extentX)) + 5, int(np.floor(y + extentY)) + 5)) record.setBBox(bbox) record['weight'] = 1.0 record['id'] = ind ind += 1 mycatalog.append(record) # create the coaddpsf psf = measAlg.CoaddPsf(mycatalog, wcsref, 'weight') return psf
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 makeLsstExposure(galData, psfData, pixScale, variance): """ make an LSST exposure object Parameters: galData (ndarray): array of galaxy image psfData (ndarray): array of PSF image pixScale (float): pixel scale variance (float): noise variance Returns: exposure: LSST exposure object """ if not with_lsst: raise ImportError('Do not have lsstpipe!') ny, nx = galData.shape exposure = afwImg.ExposureF(nx, ny) exposure.getMaskedImage().getImage().getArray()[:, :] = galData exposure.getMaskedImage().getVariance().getArray()[:, :] = variance #Set the PSF ngridPsf = psfData.shape[0] psfLsst = afwImg.ImageF(ngridPsf, ngridPsf) psfLsst.getArray()[:, :] = psfData psfLsst = psfLsst.convertD() kernel = afwMath.FixedKernel(psfLsst) kernelPSF = meaAlg.KernelPsf(kernel) exposure.setPsf(kernelPSF) #prepare the wcs #Rotation cdelt = (pixScale * afwGeom.arcseconds) CD = afwGeom.makeCdMatrix(cdelt, afwGeom.Angle(0.)) #no rotation #wcs crval = afwGeom.SpherePoint(afwGeom.Angle(0., afwGeom.degrees), afwGeom.Angle(0., afwGeom.degrees)) #crval = afwCoord.IcrsCoord(0.*afwGeom.degrees, 0.*afwGeom.degrees) # hscpipe6 crpix = afwGeom.Point2D(0.0, 0.0) dataWcs = afwGeom.makeSkyWcs(crpix, crval, CD) exposure.setWcs(dataWcs) #prepare the frc dataCalib = afwImg.makePhotoCalibFromCalibZeroPoint(63095734448.0194) exposure.setPhotoCalib(dataCalib) return exposure
def testFixedKernel(self): """Test FixedKernel using a ramp function """ kWidth = 5 kHeight = 6 inArr = np.arange(kWidth * kHeight, dtype=float) inArr.shape = [kWidth, kHeight] inImage = afwImage.ImageD(afwGeom.Extent2I(kWidth, kHeight)) for row in range(inImage.getHeight()): for col in range(inImage.getWidth()): inImage.set(col, row, inArr[col, row]) kernel = afwMath.FixedKernel(inImage) self.basicTests(kernel, 0) kernelResized = self.verifyResized(kernel, oddPadRaises=True) self.basicTests(kernelResized, 0) outImage = afwImage.ImageD(kernel.getDimensions()) kernel.computeImage(outImage, False) outArr = outImage.getArray().transpose() if not np.allclose(inArr, outArr): self.fail("%s = %s != %s (not normalized)" % (kernel.__class__.__name__, inArr, outArr)) normInArr = inArr / inArr.sum() normOutImage = afwImage.ImageD(kernel.getDimensions()) kernel.computeImage(normOutImage, True) normOutArr = normOutImage.getArray().transpose() if not np.allclose(normOutArr, normInArr): self.fail("%s = %s != %s (normalized)" % (kernel.__class__.__name__, normInArr, normOutArr)) errStr = self.compareKernels(kernel, kernel.clone()) if errStr: self.fail(errStr) self.verifyCache(kernel, hasCache=False)