Exemplo n.º 1
0
 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)
Exemplo n.º 2
0
    def testResized(self):
        for pad in [0, -10, 10]:
            newLen = self.kernelSize - pad
            resizedPsf = self.psf.resized(newLen, newLen)
            newBBox = resizedPsf.computeBBox(resizedPsf.getAveragePosition())
            self.assertEqual(newBBox.getWidth(), newLen)
            self.assertEqual(newBBox.getHeight(), newLen)
            self.assertEqual(resizedPsf.getSigma(), self.psf.getSigma())

            image = resizedPsf.computeKernelImage(resizedPsf.getAveragePosition())
            check = makeGaussianImage(newBBox, self.psf.getSigma())
            self.assertFloatsAlmostEqual(image.getArray(), check.getArray())
            # tolerance same as in self.testKernelImage
            self.assertFloatsAlmostEqual(image.getArray().sum(), 1.0, atol=1E-14)
 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)
Exemplo n.º 4
0
 def testAddToImage(self):
     bbox = geom.Box2I(geom.Point2I(5, 6), geom.Extent2I(20, 30))
     image = lsst.afw.image.ImageD(bbox)
     x = numpy.arange(bbox.getBeginX(), bbox.getEndX(), dtype=float)
     y = numpy.arange(bbox.getBeginY(), bbox.getEndY(), dtype=float)
     array = numpy.zeros((bbox.getHeight(), bbox.getWidth()), dtype=float)
     for f in self.functions:
         image.getArray()[:] = 0.0
         array[:] = 0.0
         ev = f.evaluate()
         ev.addToImage(image)
         ev.addToImage(array, bbox.getMin())
         check = self.makeImage(f, x, y)
         self.assertClose(image.getArray(), check)
         self.assertClose(array, check)
Exemplo n.º 5
0
 def testAddToImage(self):
     bbox = geom.Box2I(geom.Point2I(5, 6), geom.Extent2I(20, 30))
     image = lsst.afw.image.ImageD(bbox)
     x = numpy.arange(bbox.getBeginX(), bbox.getEndX(), dtype=float)
     y = numpy.arange(bbox.getBeginY(), bbox.getEndY(), dtype=float)
     array = numpy.zeros((bbox.getHeight(), bbox.getWidth()), dtype=float)
     for f in self.functions:
         image.getArray()[:] = 0.0
         array[:] = 0.0
         ev = f.evaluate()
         ev.addToImage(image)
         ev.addToImage(array, bbox.getMin())
         check = self.makeImage(f, x, y)
         self.assertClose(image.getArray(), check)
         self.assertClose(array, check)
 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
Exemplo n.º 7
0
    def testImage(self):
        """Test Polygon.createImage"""
        if display:
            import lsst.afw.display as afwDisplay

        for i, num in enumerate(range(3, 30)):
            # We need to test at different centers, because the
            # boost::intersection algorithm depends sensitively on
            # input floating-point values, and you will get different
            # aliasing depending on the central pixel value when
            # generating the polygon from numpy values.
            for cent in [-75, -50, -25, 0, 25, 50, 75]:
                poly = self.polygon(num, 25, cent, cent)
                box = lsst.geom.Box2I(lsst.geom.Point2I(cent - 60, cent - 60),
                                      lsst.geom.Extent2I(115, 115))
                image = poly.createImage(box)
                if display:
                    disp = afwDisplay.Display(frame=i + 1)
                    disp.mtv(image, title=f"Polygon nside={num}")
                    for p1, p2 in poly.getEdges():
                        disp.line((p1, p2))
                # Some computations of the image area have such large aliasing
                # in boost::intersection that the precision required here is 0.025.
                self.assertFloatsAlmostEqual(image.getArray().sum(),
                                             poly.calculateArea(),
                                             rtol=0.025)
Exemplo n.º 8
0
 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
Exemplo n.º 9
0
    def addSource(self, flux, centroid, shape=None):
        """!
        Add a source to the simulation

        @param[in]  flux      Total flux of the source to be added.
        @param[in]  centroid  Position of the source to be added (lsst.afw.geom.Point2D).
        @param[in]  shape     2nd moments of the source before PSF convolution
                              (lsst.afw.geom.ellipses.Quadrupole).  Note that the truth catalog
                              records post-convolution moments).  If None, a point source
                              will be added.

        @return a truth catalog record and single-source image corresponding to the new source.
        """
        # Create and set the truth catalog fields
        record = self.catalog.addNew()
        record.set(self.keys["flux"], flux)
        record.set(self.keys["centroid"], centroid)
        if shape is None:
            record.set(self.keys["isStar"], True)
            fullShape = self.psfShape
        else:
            record.set(self.keys["isStar"], False)
            fullShape = shape.convolve(self.psfShape)
        record.set(self.keys["shape"], fullShape)
        # Create an image containing just this source
        image = self.drawGaussian(self.exposure.getBBox(), flux,
                                  lsst.afw.geom.ellipses.Ellipse(fullShape, centroid))
        # Generate a footprint for this source
        self._installFootprint(record, image)
        # Actually add the source to the full exposure
        self.exposure.getMaskedImage().getImage().getArray()[:,:] += image.getArray()
        return record, image
 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 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)
Exemplo n.º 12
0
    def drawGaussian(bbox, instFlux, ellipse):
        """Create an image of an elliptical Gaussian.

        Parameters
        ----------
        bbox : `lsst.geom.Box2I` or `lsst.geom.Box2D`
            Bounding box of image to create.
        instFlux : `float`
            Total instrumental flux of the Gaussian (normalized analytically,
            not using pixel values).
        ellipse : `lsst.afw.geom.Ellipse`
            Defines the centroid and shape.

        Returns
        -------
        image : `lsst.afw.image.ImageF`
            An image of the Gaussian.
        """
        x, y = np.meshgrid(np.arange(bbox.getBeginX(), bbox.getEndX()),
                           np.arange(bbox.getBeginY(), bbox.getEndY()))
        t = ellipse.getGridTransform()
        xt = t[t.XX] * x + t[t.XY] * y + t[t.X]
        yt = t[t.YX] * x + t[t.YY] * y + t[t.Y]
        image = lsst.afw.image.ImageF(bbox)
        image.getArray()[:, :] = np.exp(
            -0.5 *
            (xt**2 + yt**2)) * instFlux / (2.0 * ellipse.getCore().getArea())
        return image
Exemplo n.º 13
0
def makeGaussianImage(bbox, sigma, xc=0.0, yc=0.0):
    image = lsst.afw.image.ImageD(bbox)
    array = image.getArray()
    for yi, yv in enumerate(range(bbox.getBeginY(), bbox.getEndY())):
        for xi, xv in enumerate(range(bbox.getBeginX(), bbox.getEndX())):
            array[yi, xi] = np.exp(-0.5*((xv - xc)**2 + (yv - yc)**2)/sigma**2)
    array /= array.sum()
    return image
Exemplo n.º 14
0
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
Exemplo n.º 15
0
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
Exemplo n.º 16
0
 def testObjective(self):
     """Test that model evaluation agrees with derivative evaluation in the objective object.
     """
     image = self.psf.computeKernelImage()
     msf = self.Algorithm.initializeResult(self.ctrl)
     self.Algorithm.fitMoments(msf, self.ctrl, image)
     moments = msf.evaluate().computeMoments()
     r0 = moments.getCore().getDeterminantRadius()
     objective = self.Algorithm.makeObjective(moments, self.ctrl, image)
     image, model = self.makeImages(msf)
     parameters = numpy.zeros(4, dtype=float)
     parameters[0] = msf.getComponents()[0].getCoefficients()[0]
     parameters[1] = msf.getComponents()[1].getCoefficients()[0]
     parameters[2] = msf.getComponents()[0].getEllipse().getCore(
     ).getDeterminantRadius() / r0
     parameters[3] = msf.getComponents()[1].getEllipse().getCore(
     ).getDeterminantRadius() / r0
     residuals = numpy.zeros(image.getArray().size, dtype=float)
     objective.computeResiduals(parameters, residuals)
     return msf
     self.assertFloatsAlmostEqual(
         residuals.reshape(image.getHeight(), image.getWidth()),
         image.getArray() - model.getArray())
     step = 1E-6
     derivatives = numpy.zeros((parameters.size, residuals.size),
                               dtype=float).transpose()
     objective.differentiateResiduals(parameters, derivatives)
     for i in range(parameters.size):
         original = parameters[i]
         r1 = numpy.zeros(residuals.size, dtype=float)
         r2 = numpy.zeros(residuals.size, dtype=float)
         parameters[i] = original + step
         objective.computeResiduals(parameters, r1)
         parameters[i] = original - step
         objective.computeResiduals(parameters, r2)
         parameters[i] = original
         d = (r1 - r2) / (2.0 * step)
         self.assertFloatsAlmostEqual(d.reshape(image.getHeight(),
                                                image.getWidth()),
                                      derivatives[:, i].reshape(
                                          image.getHeight(),
                                          image.getWidth()),
                                      atol=1E-11)
Exemplo n.º 17
0
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)
Exemplo n.º 18
0
    def makeImage(self, ImageClass):
        """Create an image

        Parameters
        ----------
        ImageClass : `type`, an `lsst.afw.image.Image` class
            Class of image to create.

        Returns
        -------
        image : `ImageClass`
            The created image.
        """
        image = ImageClass(self.bbox)
        rng = np.random.RandomState(12345)
        dtype = image.getArray().dtype
        noise = rng.normal(0.0, self.noise,
                           image.getArray().shape).astype(dtype)
        image.getArray()[:] = np.array(self.background, dtype=dtype) + noise
        return image
Exemplo n.º 19
0
 def computeVariance(self, image):
     array = image.getArray()
     n = array.shape[0] / 100
     assert n * 100 == array.shape[0]
     mask = numpy.zeros(array.shape, dtype=bool)
     for i in range(self.config.varianceBorderWidth):
         mask[i::n,:] = True
         mask[:,i::n] = True
         mask[n-i::n,:] = True
         mask[:,n-i::n] = True
     borderPixels = array[mask]
     return numpy.std(borderPixels, dtype=numpy.float64)**2
Exemplo n.º 20
0
    def checkSubtracted(self, exposure):
        """Check that the subtracted image is as expected

        Parameters
        ----------
        exposure : `lsst.afw.image.Exposure`
            Crosstalk-subtracted exposure.
        """
        image = exposure.getMaskedImage().getImage()
        mask = exposure.getMaskedImage().getMask()
        self.assertFloatsAlmostEqual(image.getArray(), self.corrected.getArray(), atol=2.0e-2)
        self.assertIn(self.crosstalkStr, mask.getMaskPlaneDict())
        self.assertGreater((mask.getArray() & mask.getPlaneBitMask(self.crosstalkStr) > 0).sum(), 0)
 def testObjective(self):
     """Test that model evaluation agrees with derivative evaluation in the objective object.
     """
     image = self.psf.computeKernelImage()
     msf = self.Algorithm.initializeResult(self.ctrl)
     self.Algorithm.fitMoments(msf, self.ctrl, image)
     moments = msf.evaluate().computeMoments()
     r0 = moments.getCore().getDeterminantRadius()
     objective = self.Algorithm.makeObjective(moments, self.ctrl, image)
     image, model = self.makeImages(msf)
     parameters = numpy.zeros(4, dtype=float)
     parameters[0] = msf.getComponents()[0].getCoefficients()[0]
     parameters[1] = msf.getComponents()[1].getCoefficients()[0]
     parameters[2] = msf.getComponents()[0].getEllipse().getCore().getDeterminantRadius() / r0
     parameters[3] = msf.getComponents()[1].getEllipse().getCore().getDeterminantRadius() / r0
     residuals = numpy.zeros(image.getArray().size, dtype=float)
     objective.computeResiduals(parameters, residuals)
     self.assertFloatsAlmostEqual(
         residuals.reshape(image.getHeight(), image.getWidth()),
         image.getArray() - model.getArray()
     )
     step = 1E-6
     derivatives = numpy.zeros((parameters.size, residuals.size), dtype=float).transpose()
     objective.differentiateResiduals(parameters, derivatives)
     for i in range(parameters.size):
         original = parameters[i]
         r1 = numpy.zeros(residuals.size, dtype=float)
         r2 = numpy.zeros(residuals.size, dtype=float)
         parameters[i] = original + step
         objective.computeResiduals(parameters, r1)
         parameters[i] = original - step
         objective.computeResiduals(parameters, r2)
         parameters[i] = original
         d = (r1 - r2)/(2.0*step)
         self.assertFloatsAlmostEqual(
             d.reshape(image.getHeight(), image.getWidth()),
             derivatives[:, i].reshape(image.getHeight(), image.getWidth()),
             atol=1E-11
         )
Exemplo n.º 22
0
    def checkSubtracted(self, exposure):
        """Check that the subtracted image is as expected

        Parameters
        ----------
        exposure : `lsst.afw.image.Exposure`
            Crosstalk-subtracted exposure.
        """
        image = exposure.getMaskedImage().getImage()
        mask = exposure.getMaskedImage().getMask()
        self.assertFloatsAlmostEqual(image.getArray(), self.corrected.getArray(), atol=2.0e-2)
        self.assertIn(self.crosstalkStr, mask.getMaskPlaneDict())
        self.assertGreater((mask.getArray() & mask.getPlaneBitMask(self.crosstalkStr) > 0).sum(), 0)
Exemplo n.º 23
0
def checkAstropy(image, filename, hduNum=0):
    """Check that astropy can read our file

    We don't insist on equality for low BITPIX (8, 16) when the original
    type is double-precision: astropy will (quite reasonably) read that
    into a single-precision image and apply bscale,bzero to that so it's
    going to be subject to roundoff.

    Parameters
    ----------
    image : `lsst.afw.image.Image`
        Image read by our own code.
    filename : `str`
        Filename of FITS file to read with astropy.
    hduNum : `int`
        HDU number of interest.
    """
    print("Astropy currently doesn't read our compressed images perfectly.")
    return

    def parseVersion(version):
        return tuple(int(vv) for vv in np.array(version.split(".")))

    if parseVersion(astropy.__version__) <= parseVersion("2.0.1"):
        # astropy 2.0.1 and earlier have problems:
        # * Doesn't support GZIP_2: https://github.com/astropy/astropy/pull/6486
        # * Uses the wrong array type: https://github.com/astropy/astropy/pull/6492
        print(
            f"Refusing to check with astropy version {astropy.__version__} due to astropy bugs"
        )
        return
    hdu = astropy.io.fits.open(filename)[hduNum]
    if hdu.header["BITPIX"] in (8, 16) and isinstance(image,
                                                      lsst.afw.image.ImageD):
        return
    dtype = image.getArray().dtype
    theirs = hdu.data.astype(dtype)
    # Allow for minor differences due to arithmetic: +/- 1 in the last place
    np.testing.assert_array_max_ulp(theirs, image.getArray())
Exemplo n.º 24
0
 def construct(imageList):
     image = lsst.afw.image.ImageF(2*width, 2*height)
     image.getArray()[:height, :width] = imageList[0].getArray()
     image.getArray()[:height, width:] = imageList[1].getArray()[:, ::-1]  # flip in x
     image.getArray()[height:, :width] = imageList[2].getArray()[::-1, :]  # flip in y
     image.getArray()[height:, width:] = imageList[3].getArray()[::-1, ::-1]  # flip in x and y
     image.getArray()[:] += self.noise
     return image
Exemplo n.º 25
0
 def construct(imageList):
     image = lsst.afw.image.ImageF(2*width, 2*height)
     image.getArray()[:height, :width] = imageList[0].getArray()
     image.getArray()[:height, width:] = imageList[1].getArray()[:, ::-1]  # flip in x
     image.getArray()[height:, :width] = imageList[2].getArray()[::-1, :]  # flip in y
     image.getArray()[height:, width:] = imageList[3].getArray()[::-1, ::-1]  # flip in x and y
     image.getArray()[:] += self.noise
     return image
Exemplo n.º 26
0
 def testImage(self):
     """Test Polygon.createImage"""
     for i, num in enumerate(range(3, 30)):
         poly = self.polygon(num, 25, 75, 75)
         box = lsst.geom.Box2I(lsst.geom.Point2I(15, 15),
                               lsst.geom.Extent2I(115, 115))
         image = poly.createImage(box)
         if DEBUG:
             import lsst.afw.display.ds9 as ds9
             ds9.mtv(image, frame=i+1, title="Polygon nside=%d" % num)
             for p1, p2 in poly.getEdges():
                 ds9.line((p1, p2), frame=i+1)
         self.assertAlmostEqual(
             image.getArray().sum()/poly.calculateArea(), 1.0, 6)
Exemplo n.º 27
0
    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
Exemplo n.º 28
0
    def __exit__(self, type_, value, tb):
        # We're not using the context manager for any kind of exception safety
        # or guarantees; we just want the nice "with" statement syntax.

        if type_ is not None:
            # exception was raised; just skip all this and let it propagate
            return

        # On exit, compute and set the truth values for the parent object.
        self.parentRecord.set(self.owner.keys["nChild"], len(self.children))
        # Compute instFlux from sum of component fluxes
        instFlux = 0.0
        for record, image in self.children:
            instFlux += record.get(self.owner.keys["instFlux"])
        self.parentRecord.set(self.owner.keys["instFlux"], instFlux)
        # Compute centroid from instFlux-weighted mean of component centroids
        x = 0.0
        y = 0.0
        for record, image in self.children:
            w = record.get(self.owner.keys["instFlux"]) / instFlux
            x += record.get(self.owner.keys["centroid"].getX()) * w
            y += record.get(self.owner.keys["centroid"].getY()) * w
        self.parentRecord.set(self.owner.keys["centroid"],
                              lsst.geom.Point2D(x, y))
        # Compute shape from instFlux-weighted mean of offset component shapes
        xx = 0.0
        yy = 0.0
        xy = 0.0
        for record, image in self.children:
            w = record.get(self.owner.keys["instFlux"]) / instFlux
            dx = record.get(self.owner.keys["centroid"].getX()) - x
            dy = record.get(self.owner.keys["centroid"].getY()) - y
            xx += (record.get(self.owner.keys["shape"].getIxx()) + dx**2) * w
            yy += (record.get(self.owner.keys["shape"].getIyy()) + dy**2) * w
            xy += (record.get(self.owner.keys["shape"].getIxy()) + dx * dy) * w
        self.parentRecord.set(self.owner.keys["shape"],
                              lsst.afw.geom.Quadrupole(xx, yy, xy))
        # Run detection on the parent image to get the parent Footprint.
        self.owner._installFootprint(self.parentRecord, self.parentImage)
        # Create perfect HeavyFootprints for all children; these will need to
        # be modified later to account for the noise we'll add to the image.
        deblend = lsst.afw.image.MaskedImageF(
            self.owner.exposure.getMaskedImage(), True)
        for record, image in self.children:
            deblend.getImage().getArray()[:, :] = image.getArray()
            heavyFootprint = lsst.afw.detection.HeavyFootprintF(
                self.parentRecord.getFootprint(), deblend)
            record.setFootprint(heavyFootprint)
Exemplo n.º 29
0
 def testImage(self):
     """Test Polygon.createImage"""
     if display:
         import lsst.afw.display as afwDisplay
     for i, num in enumerate(range(3, 30)):
         poly = self.polygon(num, 25, 75, 75)
         box = lsst.geom.Box2I(lsst.geom.Point2I(15, 15),
                               lsst.geom.Extent2I(115, 115))
         image = poly.createImage(box)
         if display:
             disp = afwDisplay.Display(frame=i + 1)
             disp.mtv(image, title="Polygon nside=%d" % num)
             for p1, p2 in poly.getEdges():
                 disp.line((p1, p2))
         self.assertAlmostEqual(
             image.getArray().sum()/poly.calculateArea(), 1.0, 6)
Exemplo n.º 30
0
 def testImage(self):
     """Test Polygon.createImage"""
     if display:
         import lsst.afw.display as afwDisplay
     for i, num in enumerate(range(3, 30)):
         poly = self.polygon(num, 25, 75, 75)
         box = lsst.geom.Box2I(lsst.geom.Point2I(15, 15),
                               lsst.geom.Extent2I(115, 115))
         image = poly.createImage(box)
         if display:
             disp = afwDisplay.Display(frame=i + 1)
             disp.mtv(image, title=f"Polygon nside={num}")
             for p1, p2 in poly.getEdges():
                 disp.line((p1, p2))
         self.assertAlmostEqual(
             image.getArray().sum() / poly.calculateArea(), 1.0, 6)
Exemplo n.º 31
0
    def drawGaussian(bbox, flux, ellipse):
        """!
        Create an image of an elliptical Gaussian.

        @param[in,out] bbox        Bounding box of image to create.
        @param[in]     flux        Total flux of the Gaussian (normalized analytically, not using pixel
                                   values)
        @param[in]     ellipse     lsst.afw.geom.ellipses.Ellipse holding the centroid and shape.
        """
        x, y = numpy.meshgrid(numpy.arange(bbox.getBeginX(), bbox.getEndX()),
                              numpy.arange(bbox.getBeginY(), bbox.getEndY()))
        t = ellipse.getGridTransform()
        xt = t[t.XX] * x + t[t.XY] * y + t[t.X]
        yt = t[t.YX] * x + t[t.YY] * y + t[t.Y]
        image = lsst.afw.image.ImageF(bbox)
        image.getArray()[:,:] = numpy.exp(-0.5*(xt**2 + yt**2))*flux/(2.0*ellipse.getCore().getArea())
        return image
Exemplo n.º 32
0
    def addSource(self, instFlux, centroid, shape=None):
        """Add a source to the simulation.

        Parameters
        ----------
        instFlux : `float`
            Total instFlux of the source to be added.
        centroid : `lsst.geom.Point2D`
            Position of the source to be added.
        shape : `lsst.afw.geom.Quadrupole`
            Second moments of the source before PSF convolution. Note that the
            truth catalog records post-convolution moments. If `None`, a point
            source will be added.

        Returns
        -------
        record : `lsst.afw.table.SourceRecord`
            A truth catalog record.
        image : `lsst.afw.image.ImageF`
            Single-source image corresponding to the new source.
        """
        # Create and set the truth catalog fields
        record = self.catalog.addNew()
        record.set(self.keys["instFlux"], instFlux)
        record.set(self.keys["centroid"], centroid)
        covariance = np.random.normal(0, 0.1, 4).reshape(2, 2)
        covariance[0, 1] = covariance[
            1, 0]  # CovarianceMatrixKey assumes symmetric x_y_Cov
        record.set(self.keys["centroid_sigma"], covariance.astype(np.float32))
        if shape is None:
            record.set(self.keys["isStar"], True)
            fullShape = self.psfShape
        else:
            record.set(self.keys["isStar"], False)
            fullShape = shape.convolve(self.psfShape)
        record.set(self.keys["shape"], fullShape)
        # Create an image containing just this source
        image = self.drawGaussian(self.exposure.getBBox(), instFlux,
                                  lsst.afw.geom.Ellipse(fullShape, centroid))
        # Generate a footprint for this source
        self._installFootprint(record, image)
        # Actually add the source to the full exposure
        self.exposure.getMaskedImage().getImage().getArray(
        )[:, :] += image.getArray()
        return record, image
 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
Exemplo n.º 34
0
 def __exit__(self, type_, value, tb):
     # We're not using the context manager for any kind of exception safety or guarantees;
     # we just want the nice "with" statement syntax.
     if type_ is not None:  # exception was raised; just skip all this and let it propagate
         return
     # On exit, we need to compute and set the truth values for the parent object.
     self.parentRecord.set(self.owner.keys["nChild"], len(self.children))
     # Compute flux from sum of component fluxes
     flux = 0.0
     for record, image in self.children:
         flux += record.get(self.owner.keys["flux"])
     self.parentRecord.set(self.owner.keys["flux"], flux)
     # Compute centroid from flux-weighted mean of component centroids
     x = 0.0
     y = 0.0
     for record, image in self.children:
         w = record.get(self.owner.keys["flux"])/flux
         x += record.get(self.owner.keys["centroid"].getX())*w
         y += record.get(self.owner.keys["centroid"].getY())*w
     self.parentRecord.set(self.owner.keys["centroid"], lsst.afw.geom.Point2D(x, y))
     # Compute shape from flux-weighted mean of offset component shapes
     xx = 0.0
     yy = 0.0
     xy = 0.0
     for record, image in self.children:
         w = record.get(self.owner.keys["flux"])/flux
         dx = record.get(self.owner.keys["centroid"].getX()) - x
         dy = record.get(self.owner.keys["centroid"].getY()) - y
         xx += (record.get(self.owner.keys["shape"].getIxx()) + dx**2)*w
         yy += (record.get(self.owner.keys["shape"].getIyy()) + dy**2)*w
         xy += (record.get(self.owner.keys["shape"].getIxy()) + dx*dy)*w
     self.parentRecord.set(self.owner.keys["shape"], lsst.afw.geom.ellipses.Quadrupole(xx, yy, xy))
     # Run detection on the parent image to get the parent Footprint.
     self.owner._installFootprint(self.parentRecord, self.parentImage)
     # Create perfect HeavyFootprints for all children; these will need to be modified later to account
     # for the noise we'll add to the image.
     deblend = lsst.afw.image.MaskedImageF(self.owner.exposure.getMaskedImage(), True)
     for record, image in self.children:
         deblend.getImage().getArray()[:,:] = image.getArray()
         heavyFootprint = lsst.afw.detection.HeavyFootprintF(self.parentRecord.getFootprint(), deblend)
         record.setFootprint(heavyFootprint)
Exemplo n.º 35
0
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
Exemplo n.º 36
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)
Exemplo n.º 37
0
    def setUp(self):
        width, height = 250, 500
        self.numAmps = 4
        numPixelsPerAmp = 1000
        # crosstalk[i][j] is the fraction of the j-th amp present on the i-th
        # amp.
        self.crosstalk = [[0.0, 1e-4, 2e-4, 3e-4], [3e-4, 0.0, 2e-4, 1e-4],
                          [4e-4, 5e-4, 0.0, 6e-4], [7e-4, 8e-4, 9e-4, 0.0]]
        self.value = 12345
        self.crosstalkStr = "XTLK"

        # A bit of noise is important, because otherwise the pixel
        # distributions are razor-thin and then rejection doesn't work.
        rng = np.random.RandomState(12345)
        self.noise = rng.normal(0.0, 0.1, (2 * height, 2 * width))

        # Create amp images
        withoutCrosstalk = [
            lsst.afw.image.ImageF(width, height) for _ in range(self.numAmps)
        ]
        for image in withoutCrosstalk:
            image.set(0)
            xx = rng.randint(0, width, numPixelsPerAmp)
            yy = rng.randint(0, height, numPixelsPerAmp)
            image.getArray()[yy, xx] = self.value

        # Add in crosstalk
        withCrosstalk = [
            image.Factory(image, True) for image in withoutCrosstalk
        ]
        for ii, iImage in enumerate(withCrosstalk):
            for jj, jImage in enumerate(withoutCrosstalk):
                value = self.crosstalk[ii][jj]
                iImage.scaledPlus(value, jImage)

        # Put amp images together
        def construct(imageList):
            image = lsst.afw.image.ImageF(2 * width, 2 * height)
            image.getArray()[:height, :width] = imageList[0].getArray()
            image.getArray()[:height,
                             width:] = imageList[1].getArray()[:, ::
                                                               -1]  # flip in x
            image.getArray()[height:, :width] = imageList[2].getArray(
            )[::-1, :]  # flip in y
            image.getArray()[height:, width:] = imageList[3].getArray(
            )[::-1, ::-1]  # flip in x and y
            image.getArray()[:] += self.noise
            return image

        # Construct detector
        detName = 'detector 1'
        detId = 1
        detSerial = 'serial 1'
        orientation = cameraGeom.Orientation()
        pixelSize = lsst.geom.Extent2D(1, 1)
        bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0),
                               lsst.geom.Extent2I(2 * width, 2 * height))
        crosstalk = np.array(self.crosstalk, dtype=np.float32)

        camBuilder = cameraGeom.Camera.Builder("fakeCam")
        detBuilder = camBuilder.add(detName, detId)
        detBuilder.setSerial(detSerial)
        detBuilder.setBBox(bbox)
        detBuilder.setOrientation(orientation)
        detBuilder.setPixelSize(pixelSize)
        detBuilder.setCrosstalk(crosstalk)

        # Construct second detector in this fake camera
        detName = 'detector 2'
        detId = 2
        detSerial = 'serial 2'
        orientation = cameraGeom.Orientation()
        pixelSize = lsst.geom.Extent2D(1, 1)
        bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0),
                               lsst.geom.Extent2I(2 * width, 2 * height))
        crosstalk = np.array(self.crosstalk, dtype=np.float32)

        detBuilder2 = camBuilder.add(detName, detId)
        detBuilder2.setSerial(detSerial)
        detBuilder2.setBBox(bbox)
        detBuilder2.setOrientation(orientation)
        detBuilder2.setPixelSize(pixelSize)
        detBuilder2.setCrosstalk(crosstalk)

        # Create amp info
        for ii, (xx, yy, corner) in enumerate([
            (0, 0, lsst.afw.cameraGeom.ReadoutCorner.LL),
            (width, 0, lsst.afw.cameraGeom.ReadoutCorner.LR),
            (0, height, lsst.afw.cameraGeom.ReadoutCorner.UL),
            (width, height, lsst.afw.cameraGeom.ReadoutCorner.UR)
        ]):

            amp = cameraGeom.Amplifier.Builder()
            amp.setName("amp %d" % ii)
            amp.setBBox(
                lsst.geom.Box2I(lsst.geom.Point2I(xx, yy),
                                lsst.geom.Extent2I(width, height)))
            amp.setRawDataBBox(
                lsst.geom.Box2I(lsst.geom.Point2I(xx, yy),
                                lsst.geom.Extent2I(width, height)))
            amp.setReadoutCorner(corner)
            detBuilder.append(amp)
            detBuilder2.append(amp)

        cam = camBuilder.finish()
        ccd1 = cam.get('detector 1')
        ccd2 = cam.get('detector 2')

        self.exposure = lsst.afw.image.makeExposure(
            lsst.afw.image.makeMaskedImage(construct(withCrosstalk)))
        self.exposure.setDetector(ccd1)

        # Create a single ctSource that will be used for interChip CT
        # correction.
        self.ctSource = lsst.afw.image.makeExposure(
            lsst.afw.image.makeMaskedImage(construct(withCrosstalk)))
        self.ctSource.setDetector(ccd2)

        self.corrected = construct(withoutCrosstalk)

        if display:
            disp = lsst.afw.display.Display(frame=1)
            disp.mtv(self.exposure, title="exposure")
            disp = lsst.afw.display.Display(frame=0)
            disp.mtv(self.corrected, title="corrected exposure")
Exemplo n.º 38
0
 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)
Exemplo n.º 39
0
    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
Exemplo n.º 40
0
 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)
Exemplo n.º 41
0
    def setUp(self):
        width, height = 250, 500
        self.numAmps = 4
        numPixelsPerAmp = 1000
        # crosstalk[i][j] is the fraction of the j-th amp present on the i-th amp.
        self.crosstalk = [[0.0, 1e-4, 2e-4, 3e-4], [3e-4, 0.0, 2e-4, 1e-4],
                          [4e-4, 5e-4, 0.0, 6e-4], [7e-4, 8e-4, 9e-4, 0.0]]
        self.value = 12345
        self.crosstalkStr = "XTLK"

        # A bit of noise is important, because otherwise the pixel distributions are razor-thin
        # and then rejection doesn't work
        rng = np.random.RandomState(12345)
        self.noise = rng.normal(0.0, 0.1, (2 * height, 2 * width))

        # Create amp images
        withoutCrosstalk = [
            lsst.afw.image.ImageF(width, height) for _ in range(self.numAmps)
        ]
        for image in withoutCrosstalk:
            image.set(0)
            xx = rng.randint(0, width, numPixelsPerAmp)
            yy = rng.randint(0, height, numPixelsPerAmp)
            image.getArray()[yy, xx] = self.value

        # Add in crosstalk
        withCrosstalk = [
            image.Factory(image, True) for image in withoutCrosstalk
        ]
        for ii, iImage in enumerate(withCrosstalk):
            for jj, jImage in enumerate(withoutCrosstalk):
                value = self.crosstalk[ii][jj]
                iImage.scaledPlus(value, jImage)

        # Put amp images together
        def construct(imageList):
            image = lsst.afw.image.ImageF(2 * width, 2 * height)
            image.getArray()[:height, :width] = imageList[0].getArray()
            image.getArray()[:height,
                             width:] = imageList[1].getArray()[:, ::
                                                               -1]  # flip in x
            image.getArray()[height:, :width] = imageList[2].getArray(
            )[::-1, :]  # flip in y
            image.getArray()[height:, width:] = imageList[3].getArray(
            )[::-1, ::-1]  # flip in x and y
            image.getArray()[:] += self.noise
            return image

        # Create amp info
        schema = lsst.afw.table.AmpInfoTable.makeMinimalSchema()
        amplifiers = lsst.afw.table.AmpInfoCatalog(schema)
        for ii, (xx, yy, corner) in enumerate([(0, 0, LL), (width, 0, LR),
                                               (0, height, UL),
                                               (width, height, UR)]):
            amp = amplifiers.addNew()
            amp.setName("amp %d" % ii)
            amp.setBBox(
                lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(xx, yy),
                                    lsst.afw.geom.Extent2I(width, height)))
            amp.setRawDataBBox(
                lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(xx, yy),
                                    lsst.afw.geom.Extent2I(width, height)))
            amp.setReadoutCorner(corner)

        # Put everything together
        ccd = lsst.afw.cameraGeom.Detector(
            "detector", 123, lsst.afw.cameraGeom.SCIENCE, "serial",
            lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(0, 0),
                                lsst.afw.geom.Extent2I(2 * width, 2 * height)),
            amplifiers, lsst.afw.cameraGeom.Orientation(),
            lsst.afw.geom.Extent2D(1, 1), {},
            np.array(self.crosstalk, dtype=np.float32))

        self.exposure = lsst.afw.image.makeExposure(
            lsst.afw.image.makeMaskedImage(construct(withCrosstalk)))
        self.exposure.setDetector(ccd)

        self.corrected = construct(withoutCrosstalk)

        if display:
            disp = lsst.afw.display.Display(frame=1)
            disp.mtv(self.exposure, title="exposure")
            disp = lsst.afw.display.Display(frame=0)
            disp.mtv(self.corrected, title="corrected exposure")
Exemplo n.º 42
0
    def setUp(self):
        width, height = 250, 500
        self.numAmps = 4
        numPixelsPerAmp = 1000
        # crosstalk[i][j] is the fraction of the j-th amp present on the i-th amp.
        self.crosstalk = [[0.0, 1e-4, 2e-4, 3e-4],
                          [3e-4, 0.0, 2e-4, 1e-4],
                          [4e-4, 5e-4, 0.0, 6e-4],
                          [7e-4, 8e-4, 9e-4, 0.0]]
        self.value = 12345
        self.crosstalkStr = "XTLK"

        # A bit of noise is important, because otherwise the pixel distributions are razor-thin
        # and then rejection doesn't work
        rng = np.random.RandomState(12345)
        self.noise = rng.normal(0.0, 0.1, (2*height, 2*width))

        # Create amp images
        withoutCrosstalk = [lsst.afw.image.ImageF(width, height) for _ in range(self.numAmps)]
        for image in withoutCrosstalk:
            image.set(0)
            xx = rng.randint(0, width, numPixelsPerAmp)
            yy = rng.randint(0, height, numPixelsPerAmp)
            image.getArray()[yy, xx] = self.value

        # Add in crosstalk
        withCrosstalk = [image.Factory(image, True) for image in withoutCrosstalk]
        for ii, iImage in enumerate(withCrosstalk):
            for jj, jImage in enumerate(withoutCrosstalk):
                value = self.crosstalk[ii][jj]
                iImage.scaledPlus(value, jImage)

        # Put amp images together
        def construct(imageList):
            image = lsst.afw.image.ImageF(2*width, 2*height)
            image.getArray()[:height, :width] = imageList[0].getArray()
            image.getArray()[:height, width:] = imageList[1].getArray()[:, ::-1]  # flip in x
            image.getArray()[height:, :width] = imageList[2].getArray()[::-1, :]  # flip in y
            image.getArray()[height:, width:] = imageList[3].getArray()[::-1, ::-1]  # flip in x and y
            image.getArray()[:] += self.noise
            return image

        # Create amp info
        schema = lsst.afw.table.AmpInfoTable.makeMinimalSchema()
        amplifiers = lsst.afw.table.AmpInfoCatalog(schema)
        for ii, (xx, yy, corner) in enumerate([(0, 0, LL),
                                               (width, 0, LR),
                                               (0, height, UL),
                                               (width, height, UR)]):
            amp = amplifiers.addNew()
            amp.setName("amp %d" % ii)
            amp.setBBox(lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(xx, yy),
                                            lsst.afw.geom.Extent2I(width, height)))
            amp.setRawDataBBox(lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(xx, yy),
                                                   lsst.afw.geom.Extent2I(width, height)))
            amp.setReadoutCorner(corner)

        # Put everything together
        ccd = lsst.afw.cameraGeom.Detector("detector", 123, lsst.afw.cameraGeom.SCIENCE, "serial",
                                           lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(0, 0),
                                                               lsst.afw.geom.Extent2I(2*width, 2*height)),
                                           amplifiers, lsst.afw.cameraGeom.Orientation(),
                                           lsst.afw.geom.Extent2D(1, 1), {},
                                           np.array(self.crosstalk, dtype=np.float32))

        self.exposure = lsst.afw.image.makeExposure(lsst.afw.image.makeMaskedImage(construct(withCrosstalk)))
        self.exposure.setDetector(ccd)

        self.corrected = construct(withoutCrosstalk)

        if display:
            disp = lsst.afw.display.Display(frame=1)
            disp.mtv(self.exposure, title="exposure")
            disp = lsst.afw.display.Display(frame=0)
            disp.mtv(self.corrected, title="corrected exposure")