def testObjective(self): eps = 1E-6 ctrl = ms.FitPsfControl() image = lsst.afw.image.ImageD(5, 5) nParameters = 3 nData = image.getBBox().getArea() nTests = 10 center = geom.Point2D(2.0, 2.0) xGrid, yGrid = numpy.meshgrid(numpy.arange(-2, 3), numpy.arange(-2, 3)) image.getArray()[:, :] = 1.0 * numpy.exp(-0.5 * (xGrid**2 + yGrid**2)) image.getArray()[:, :] += numpy.random.randn(5, 5) * 0.1 inputs = ms.ModelInputHandler(image, center, image.getBBox(lsst.afw.image.PARENT)) obj = ms.FitPsfAlgorithm.makeObjective(ctrl, inputs) parameters = numpy.random.rand(nTests, nParameters) * 0.5 for i in range(nTests): f0 = numpy.zeros(nData, dtype=float) obj.computeFunction(parameters[i, :], f0) f1 = obj.getModel() * obj.getAmplitude() - inputs.getData() model = ms.FitPsfModel(ctrl, obj.getAmplitude(), parameters[i, :]) self.assertClose( model.outer[0], ctrl.peakRatio * model.inner[0] * ctrl.radiusRatio**2) self.assertEqual(model.radiusRatio, ctrl.radiusRatio) image2 = lsst.afw.image.ImageD(5, 5) multiShapeletFunc = model.asMultiShapelet(center) multiShapeletFunc.evaluate().addToImage(image2) f2 = (image2.getArray().ravel() - inputs.getData()) multiGaussian = model.getMultiGaussian() builder1 = ms.GaussianModelBuilder(inputs.getX(), inputs.getY(), multiGaussian[0].flux, multiGaussian[0].radius) builder2 = ms.GaussianModelBuilder(inputs.getX(), inputs.getY(), multiGaussian[1].flux, multiGaussian[1].radius) builder1.update(model.ellipse) builder2.update(model.ellipse) f3 = builder1.getModel() + builder2.getModel() - inputs.getData() self.assertClose(f0, f1) self.assertClose(f0, f2) self.assertClose(f0, f3) d0 = numpy.zeros((nParameters, nData), dtype=float).transpose() d1 = numpy.zeros((nParameters, nData), dtype=float).transpose() obj.computeDerivative(parameters[i, :], f0, d0) for j in range(nParameters): parameters[i, j] += eps f1a = numpy.zeros(nData, dtype=float) obj.computeFunction(parameters[i, :], f1a) parameters[i, j] -= 2.0 * eps f1b = numpy.zeros(nData, dtype=float) obj.computeFunction(parameters[i, :], f1b) d1[:, j] = (f1a - f1b) / (2.0 * eps) parameters[i, j] += eps self.assertClose(d0, d1, rtol=1E-10, atol=1E-8)
def testObjective(self): eps = 1E-6 ctrl = ms.FitPsfControl() image = lsst.afw.image.ImageD(5, 5) nParameters = 3 nData = image.getBBox().getArea() nTests = 10 center = geom.Point2D(2.0, 2.0) xGrid, yGrid = numpy.meshgrid(numpy.arange(-2, 3), numpy.arange(-2, 3)) image.getArray()[:,:] = 1.0 * numpy.exp(-0.5*(xGrid**2 + yGrid**2)) image.getArray()[:,:] += numpy.random.randn(5, 5) * 0.1 inputs = ms.ModelInputHandler(image, center, image.getBBox()) obj = ms.FitPsfAlgorithm.makeObjective(ctrl, inputs) parameters = numpy.random.rand(nTests, nParameters) * 0.5 for i in range(nTests): f0 = numpy.zeros(nData, dtype=float) obj.computeFunction(parameters[i,:], f0) f1 = obj.getModel() * obj.getAmplitude() - inputs.getData() model = ms.FitPsfModel(ctrl, obj.getAmplitude(), parameters[i,:]) self.assertClose(model.outer[0], ctrl.peakRatio * model.inner[0] * ctrl.radiusRatio**2) self.assertEqual(model.radiusRatio, ctrl.radiusRatio) image2 = lsst.afw.image.ImageD(5, 5) multiShapeletFunc = model.asMultiShapelet(center) multiShapeletFunc.evaluate().addToImage(image2) f2 = (image2.getArray().ravel() - inputs.getData()) multiGaussian = model.getMultiGaussian() builder1 = ms.GaussianModelBuilder(inputs.getX(), inputs.getY(), multiGaussian[0].flux, multiGaussian[0].radius) builder2 = ms.GaussianModelBuilder(inputs.getX(), inputs.getY(), multiGaussian[1].flux, multiGaussian[1].radius) builder1.update(model.ellipse) builder2.update(model.ellipse) f3 = builder1.getModel() + builder2.getModel() - inputs.getData() self.assertClose(f0, f1) self.assertClose(f0, f2) self.assertClose(f0, f3) d0 = numpy.zeros((nParameters, nData), dtype=float).transpose() d1 = numpy.zeros((nParameters, nData), dtype=float).transpose() obj.computeDerivative(parameters[i,:], f0, d0) for j in range(nParameters): parameters[i,j] += eps f1a = numpy.zeros(nData, dtype=float) obj.computeFunction(parameters[i,:], f1a) parameters[i,j] -= 2.0*eps f1b = numpy.zeros(nData, dtype=float) obj.computeFunction(parameters[i,:], f1b) d1[:,j] = (f1a - f1b) / (2.0 * eps) parameters[i,j] += eps self.assertClose(d0, d1, rtol=1E-10, atol=1E-8)
def buildExposure(self, dataRef): image = dataRef.get("image", immediate=True) exposure = lsst.afw.image.ExposureF(image.getBBox(lsst.afw.image.PARENT)) exposure.getMaskedImage().getImage().getArray()[:,:] = image.getArray() exposure.getMaskedImage().getVariance().set(self.computeVariance(image)) exposure.setPsf(self.psf.run(dataRef)) return exposure
def testFitMoments(self): """Test that fitMoments() preserves peakRatio and radiusRatio while setting moments correctly. """ MOMENTS_RTOL = 1E-13 image = self.psf.computeKernelImage() array = image.getArray() bbox = image.getBBox() x, y = numpy.meshgrid( numpy.arange(bbox.getBeginX(), bbox.getEndX()), numpy.arange(bbox.getBeginY(), bbox.getEndY()) ) msf = self.Algorithm.initializeResult(self.ctrl) self.Algorithm.fitMoments(msf, self.ctrl, image) self.assertFloatsAlmostEqual(msf.evaluate().integrate(), array.sum(), rtol=MOMENTS_RTOL) moments = msf.evaluate().computeMoments() q = lsst.afw.geom.ellipses.Quadrupole(moments.getCore()) cx = (x*array).sum()/array.sum() cy = (y*array).sum()/array.sum() self.assertFloatsAlmostEqual(moments.getCenter().getX(), cx, rtol=MOMENTS_RTOL) self.assertFloatsAlmostEqual(moments.getCenter().getY(), cy, rtol=MOMENTS_RTOL) self.assertFloatsAlmostEqual(q.getIxx(), ((x - cx)**2 * array).sum()/array.sum(), rtol=MOMENTS_RTOL) self.assertFloatsAlmostEqual(q.getIyy(), ((y - cy)**2 * array).sum()/array.sum(), rtol=MOMENTS_RTOL) self.assertFloatsAlmostEqual(q.getIxy(), ((x - cx)*(y - cy)*array).sum()/array.sum(), rtol=MOMENTS_RTOL) self.assertEqual(len(msf.getComponents()), 2) self.checkRatios(msf) self.checkBounds(msf)
def _plotImage(image, title=None, ellipses=(), vmin=None, vmax=None): bbox = image.getBBox() array = image.getArray() if vmin is None or vmax is None: valid = array[numpy.isfinite(array)] if vmin is None: vmin = valid.min() - 0.1 * (valid.max() - valid.min()) if vmax is None: vmax = valid.max() + 0.1 * (valid.max() - valid.min()) pyplot.imshow(array, interpolation='nearest', origin='lower', vmin=vmin, vmax=vmax, extent=(bbox.getMinX() - 0.5, bbox.getMaxX() + 0.5, bbox.getMinY() - 0.5, bbox.getMaxY() + 0.5)) if title is not None: pyplot.title(title) for ellipse in ellipses: ellipse.plot(fill=False, rescale=False) pyplot.plot([ellipse.getCenter().getX()], [ellipse.getCenter().getY()], 'kx', scalex=False, scaley=False) return vmin, vmax
def multiply(image, field): """Return the product of image and field() at each point in image.""" box = image.getBBox() outImage = lsst.afw.image.ImageF(box) for i in range(box.getMinX(), box.getMaxX() + 1): for j in range(box.getMinY(), box.getMaxY() + 1): outImage[i, j] = image[i, j] * field.evaluate(i, j) return outImage
def multiply(image, field): """Return the product of image and field() at each point in image. """ box = image.getBBox() outImage = lsst.afw.image.ImageF(box) for i in range(box.getMinX(), box.getMaxX() + 1): for j in range(box.getMinY(), box.getMaxY() + 1): outImage[i, j] = image[i, j]*field.evaluate(i, j) return outImage
def asSamples(image): bbox = image.getBBox(lsst.afw.image.PARENT) x, y = numpy.meshgrid(numpy.arange(bbox.getBeginX(), bbox.getEndX()), numpy.arange(bbox.getBeginY(), bbox.getEndY())) w = image.getArray().flatten() s = numpy.zeros((w.size, 2), dtype=float) s[:,0] = x.flatten() s[:,1] = y.flatten() return s, w
def computeNaiveApertureFlux(image, radius, xc=0.0, yc=0.0): bbox = image.getBBox() array = image.getArray() s = 0.0 for yi, yv in enumerate(range(bbox.getBeginY(), bbox.getEndY())): for xi, xv in enumerate(range(bbox.getBeginX(), bbox.getEndX())): if (xv - xc)**2 + (yv - yc)**2 < radius**2: s += array[yi, xi] return s
def fitFull(image, orders, radii=None, p0=None, penalty=0.01): bbox = image.getBBox(lsst.afw.image.PARENT) x, y = numpy.meshgrid(numpy.arange(bbox.getBeginX(), bbox.getEndX(), dtype=float), numpy.arange(bbox.getBeginY(), bbox.getEndY(), dtype=float)) basisOffsets = numpy.cumsum([0] + [lsst.shapelet.computeSize(order) for order in orders]) matrix = numpy.zeros((basisOffsets[-1], bbox.getArea()), dtype=float).transpose() builder = lsst.shapelet.ModelBuilderD(x.flatten(), y.flatten()) data = image.getArray().flatten() if penalty is not None: penalty = numpy.identity(basisOffsets[-1], dtype=float) * penalty**2 for i, order in enumerate(orders): penalty[basisOffsets[i], basisOffsets[i]] = 0.0 if p0 is None: nRadii = len(radii) unitcircle = lsst.afw.geom.ellipses.Ellipse( lsst.afw.geom.ellipses.SeparableConformalShearLogTraceRadius(), lsst.afw.geom.Point2D() ) p0 = numpy.zeros(nRadii*5, dtype=float) for i, radius in enumerate(radii): ellipse = lsst.afw.geom.ellipses.Ellipse(unitcircle) ellipse.scale(radius) p0[i*5:(i+1)*5] = ellipse.getParameterVector() def solve(p, *args): matrix[:] = 0.0 for i, order in enumerate(orders): ellipse.setParameterVector(p[i*5:(i+1)*5]) builder.update(ellipse) builder.addModelMatrix(order, matrix[:,basisOffsets[i]:basisOffsets[i+1]]) f = numpy.dot(matrix.transpose(), matrix) g = numpy.dot(matrix.transpose(), data) if penalty is not None: f += penalty c, _, _, _ = numpy.linalg.lstsq(f, g) return c def func(p, *args): c = solve(p) r = numpy.dot(matrix, c) r -= data return r p1, flags = scipy.optimize.leastsq(func, p0, maxfev=10000) c1 = solve(p1) msf = lsst.shapelet.MultiShapeletFunction() for i, order in enumerate(orders): ellipse.setParameterVector(p1[i*5:(i+1)*5]) sf = lsst.shapelet.ShapeletFunction(order, lsst.shapelet.HERMITE, ellipse, c1[basisOffsets[i]:basisOffsets[i+1]]) msf.getElements().append(sf) return msf, func(p0)
def checkCompressedImage(self, ImageClass, image, compression, scaling=None, atol=0.0): """Check that compression works on an image Parameters ---------- ImageClass : `type`, an `lsst.afw.image.Image` class Class of image. image : `lsst.afw.image.Image` Image to compress. compression : `lsst.afw.fits.ImageCompressionOptions` Compression parameters. scaling : `lsst.afw.fits.ImageScalingOptions` or `None` Scaling parameters for lossy compression (optional). atol : `float` Absolute tolerance for comparing unpersisted image. Returns ------- unpersisted : `ImageClass` The unpersisted image. """ with lsst.utils.tests.getTempFilePath(self.extension) as filename: if scaling: options = lsst.afw.fits.ImageWriteOptions(compression, scaling) else: options = lsst.afw.fits.ImageWriteOptions(compression) unpersisted = self.readWriteImage(ImageClass, image, filename, options) fileSize = os.stat(filename).st_size fitsBlockSize = 2880 # All sizes in FITS are a multiple of this numBlocks = 1 + np.ceil( self.bbox.getArea() * image.getArray().dtype.itemsize / fitsBlockSize) uncompressedSize = fitsBlockSize * numBlocks print(ImageClass, compression.algorithm, fileSize, uncompressedSize, fileSize / uncompressedSize) self.assertEqual(image.getBBox(), unpersisted.getBBox()) self.assertImagesAlmostEqual(unpersisted, image, atol=atol) checkAstropy(unpersisted, filename, 1) return unpersisted
def _plotImage(image, title=None, ellipses=(), vmin=None, vmax=None): bbox = image.getBBox() array = image.getArray() if vmin is None or vmax is None: valid = array[numpy.isfinite(array)] if vmin is None: vmin = valid.min() - 0.1 * (valid.max() - valid.min()) if vmax is None: vmax = valid.max() + 0.1 * (valid.max() - valid.min()) pyplot.imshow(array, interpolation='nearest', origin='lower', vmin=vmin, vmax=vmax, extent=(bbox.getMinX()-0.5, bbox.getMaxX()+0.5, bbox.getMinY()-0.5, bbox.getMaxY()+0.5) ) if title is not None: pyplot.title(title) for ellipse in ellipses: ellipse.plot(fill=False, rescale=False) pyplot.plot([ellipse.getCenter().getX()], [ellipse.getCenter().getY()], 'kx', scalex=False, scaley=False) return vmin, vmax
def checkCompressedMaskedImage(self, image, imageOptions, maskOptions, varianceOptions, atol=0.0): """Check that compression works on a MaskedImage Parameters ---------- image : `lsst.afw.image.MaskedImage` or `lsst.afw.image.Exposure` MaskedImage or exposure to compress. imageOptions, maskOptions, varianceOptions : `lsst.afw.fits.ImageWriteOptions` Parameters for writing (compression and scaling) the image, mask and variance planes. atol : `float` Absolute tolerance for comparing unpersisted image. """ with lsst.utils.tests.getTempFilePath(self.extension) as filename: self.readWriteMaskedImage(image, filename, imageOptions, maskOptions, varianceOptions) unpersisted = type(image)(filename) if hasattr(image, "getMaskedImage"): image = image.getMaskedImage() unpersisted = unpersisted.getMaskedImage() self.assertEqual(image.getBBox(), unpersisted.getBBox()) self.assertImagesAlmostEqual(unpersisted.getImage(), image.getImage(), atol=atol) self.assertImagesAlmostEqual(unpersisted.getMask(), image.getMask(), atol=atol) self.assertImagesAlmostEqual(unpersisted.getVariance(), image.getVariance(), atol=atol) for mp in image.getMask().getMaskPlaneDict(): self.assertIn(mp, unpersisted.getMask().getMaskPlaneDict()) unpersisted.getMask().getPlaneBitMask(mp)
def fitShapelets(image, msf): bbox = image.getBBox(lsst.afw.image.PARENT) x, y = numpy.meshgrid(numpy.arange(bbox.getBeginX(), bbox.getEndX(), dtype=float), numpy.arange(bbox.getBeginY(), bbox.getEndY(), dtype=float)) matrix = numpy.zeros((sum(lsst.shapelet.computeSize(element.getOrder()) for element in msf.getElements()), bbox.getArea()), dtype=float).transpose() offset = 0 for element in msf.getElements(): builder = lsst.shapelet.ModelBuilderD(x.flatten(), y.flatten()) size = lsst.shapelet.computeSize(element.getOrder()) builder.addModelMatrix(element.getOrder(), matrix[:,offset:offset+size]) offset += size data = image.getArray().flatten() coefficients, _, _, _ = numpy.linalg.lstsq(matrix, data) offset = 0 for element in msf.getElements(): size = lsst.shapelet.computeSize(element.getOrder()) element.getCoefficients()[:] = coefficients[offset:offset+size] offset += size
def testConstructImage(self): """Test construction of image from the spectrum Reverse process of extraction. """ spectrum = drpStella.Spectrum(self.fullDims.getY(), self.fiberId) spectrum.spectrum[self.xy0.getY():self.xy0.getY() + self.height] = 1.0 image = self.fiberTrace.constructImage(spectrum, self.bbox) self.assertEqual(image.getBBox(), self.bbox) self.assertImagesEqual(image[self.bbox, lsst.afw.image.PARENT], self.subimage.image) image[self.bbox, lsst.afw.image.PARENT].set(0.0) self.assertFloatsEqual(image.array, 0.0) # Modify provided image image.set(0.0) self.fiberTrace.constructImage(image, spectrum) self.assertImagesEqual(image[self.bbox, lsst.afw.image.PARENT], self.subimage.image) # Check that we're actually adding, not simply setting self.fiberTrace.constructImage(image, spectrum) self.image += self.image self.assertImagesEqual(image[self.bbox, lsst.afw.image.PARENT], self.subimage.image) image[self.bbox, lsst.afw.image.PARENT].set(0.0) self.assertFloatsEqual(image.array, 0.0)
def load(cls, sourceID, dataRef=None, catalog="deepCoadd_meas", exposure="deepCoadd", config="measureCoaddSources_config"): if not isinstance(catalog, lsst.afw.table.SourceCatalog): catalog = dataRef.get(catalog, immediate=True) record = catalog.find(sourceID) if not isinstance(exposure, lsst.afw.image.ExposureF): exposure = dataRef.get(exposure, immediate=True) if not isinstance(config, lsst.pex.config.Config): config = dataRef.get(config, immediate=True) if not isinstance(config, lsst.meas.algorithms.SourceMeasurementConfig): config = config.measurement image = lsst.afw.image.ImageF(os.path.join(config.algorithms["cmodel"].diagnostics.root, "%s.fits" % sourceID)) exposure = lsst.afw.image.ExposureF(exposure, image.getBBox(lsst.afw.image.PARENT), lsst.afw.image.PARENT, True) exposure.getMaskedImage().getImage().getArray()[:,:] = image.getArray() psfModel = lsst.meas.extensions.multiShapelet.FitPsfModel( config.algorithms["multishapelet.psf"].makeControl(), record ) psf = psfModel.asMultiShapelet() return cls(config.algorithms["cmodel"], exposure, record.getFootprint(), psf, record.getCentroid(), record.getShape(), record.getPsfFlux(), record=record)
def makeImage(self, ImageClass, scaling, addNoise=True): """Make an image for testing We create an image, persist and unpersist it, returning some data to the caller. Parameters ---------- ImageClass : `type`, an `lsst.afw.image.Image` class Class of image to create. scaling : `lsst.afw.fits.ImageScalingOptions` Scaling to apply during persistence. addNoise : `bool` Add noise to image? Returns ------- image : `lsst.afw.image.Image` (ImageClass) Created image. unpersisted : `lsst.afw.image.Image` (ImageClass) Unpersisted image. bscale, bzero : `float` FITS scale factor and zero used. minValue, maxValue : `float` Minimum and maximum value given the nominated scaling. """ image = ImageClass(self.bbox) mask = lsst.afw.image.Mask(self.bbox) mask.addMaskPlane(self.badMask) bad = mask.getPlaneBitMask(self.badMask) image.set(self.base) image[self.highPixel, LOCAL] = self.highValue image[self.lowPixel, LOCAL] = self.lowValue image[self.maskedPixel, LOCAL] = self.maskedValue mask[self.maskedPixel, LOCAL] = bad rng = np.random.RandomState(12345) dtype = image.getArray().dtype if addNoise: image.getArray()[:] += rng.normal( 0.0, self.stdev, image.getArray().shape).astype(dtype) with lsst.utils.tests.getTempFilePath(".fits") as filename: with lsst.afw.fits.Fits(filename, "w") as fits: options = lsst.afw.fits.ImageWriteOptions(scaling) header = lsst.daf.base.PropertyList() image.writeFits(fits, options, header, mask) unpersisted = ImageClass(filename) self.assertEqual(image.getBBox(), unpersisted.getBBox()) header = lsst.afw.fits.readMetadata(filename) bscale = header.getScalar("BSCALE") bzero = header.getScalar("BZERO") if scaling.algorithm != ImageScalingOptions.NONE: self.assertEqual(header.getScalar("BITPIX"), scaling.bitpix) if scaling.bitpix == 8: # unsigned, says FITS maxValue = bscale * (2**scaling.bitpix - 1) + bzero minValue = bzero else: maxValue = bscale * (2**(scaling.bitpix - 1) - 1) + bzero if scaling.bitpix == 32: # cfitsio pads 10 values, and so do we minValue = -bscale * (2**(scaling.bitpix - 1) - 10) + bzero else: minValue = -bscale * (2**(scaling.bitpix - 1)) + bzero # Convert scalars to the appropriate type maxValue = np.array(maxValue, dtype=image.getArray().dtype) minValue = np.array(minValue, dtype=image.getArray().dtype) checkAstropy(unpersisted, filename) return image, unpersisted, bscale, bzero, minValue, maxValue
def testKernelImage(self): image = self.psf.computeKernelImage(self.psf.getAveragePosition()) check = makeGaussianImage(image.getBBox(), self.psf.getSigma()) self.assertFloatsAlmostEqual(image.getArray(), check.getArray()) self.assertFloatsAlmostEqual(image.getArray().sum(), 1.0, atol=1E-14)
def testOffsetImage(self): image = self.psf.computeImage(lsst.geom.Point2D(0.25, 0.25)) check = makeGaussianImage( image.getBBox(), self.psf.getSigma(), 0.25, 0.25) self.assertFloatsAlmostEqual(image.getArray(), check.getArray(), atol=1E-4, rtol=1E-4, plotOnFailure=True)