Пример #1
0
def showPsfCandidates(exposure, psfCellSet, psf=None, frame=None, normalize=True, showBadCandidates=True,
                      variance=None, chi=None):
    """Display the PSF candidates.
If psf is provided include PSF model and residuals;  if normalize is true normalize the PSFs (and residuals)
If chi is True, generate a plot of residuals/sqrt(variance), i.e. chi
"""
    if chi is None:
        if variance is not None:        # old name for chi
            chi = variance
    #
    # Show us the ccandidates
    #
    mos = displayUtils.Mosaic()
    #
    candidateCenters = []
    candidateCentersBad = []
    candidateIndex = 0

    for cell in psfCellSet.getCellList():
        for cand in cell.begin(False): # include bad candidates
            cand = algorithmsLib.cast_PsfCandidateF(cand)

            rchi2 = cand.getChi2()
            if rchi2 > 1e100:
                rchi2 = numpy.nan

            if not showBadCandidates and cand.isBad():
                continue

            if psf:
                im_resid = displayUtils.Mosaic(gutter=0, background=-5, mode="x")

                try:
                    im = cand.getMaskedImage() # copy of this object's image
                    xc, yc = cand.getXCenter(), cand.getYCenter()

                    margin = 0 if True else 5
                    w, h = im.getDimensions()
                    bbox = afwGeom.BoxI(afwGeom.PointI(margin, margin), im.getDimensions())

                    if margin > 0:
                        bim = im.Factory(w + 2*margin, h + 2*margin)

                        stdev = numpy.sqrt(afwMath.makeStatistics(im.getVariance(), afwMath.MEAN).getValue())
                        afwMath.randomGaussianImage(bim.getImage(), afwMath.Random())
                        bim *= stdev
                        var = bim.getVariance(); var.set(stdev**2); del var

                        sbim = im.Factory(bim, bbox)
                        sbim <<= im
                        del sbim
                        im = bim
                        xc += margin; yc += margin

                    im = im.Factory(im, True)
                    im.setXY0(cand.getMaskedImage().getXY0())
                except:
                    continue

                if not variance:
                    im_resid.append(im.Factory(im, True))

                # residuals using spatial model
                chi2 = algorithmsLib.subtractPsf(psf, im, xc, yc)
                
                resid = im
                if variance:
                    resid = resid.getImage()
                    var = im.getVariance()
                    var = var.Factory(var, True)
                    numpy.sqrt(var.getArray(), var.getArray()) # inplace sqrt
                    resid /= var
                    
                im_resid.append(resid)

                # Fit the PSF components directly to the data (i.e. ignoring the spatial model)
                im = cand.getMaskedImage()

                im = im.Factory(im, True)
                im.setXY0(cand.getMaskedImage().getXY0())

                noSpatialKernel = afwMath.cast_LinearCombinationKernel(psf.getKernel())
                candCenter = afwGeom.PointD(cand.getXCenter(), cand.getYCenter())
                fit = algorithmsLib.fitKernelParamsToImage(noSpatialKernel, im, candCenter)
                params = fit[0]
                kernels = afwMath.KernelList(fit[1])
                outputKernel = afwMath.LinearCombinationKernel(kernels, params)

                outImage = afwImage.ImageD(outputKernel.getDimensions())
                outputKernel.computeImage(outImage, False)

                im -= outImage.convertF()
                resid = im

                if margin > 0:
                    bim = im.Factory(w + 2*margin, h + 2*margin)
                    afwMath.randomGaussianImage(bim.getImage(), afwMath.Random())
                    bim *= stdev

                    sbim = im.Factory(bim, bbox)
                    sbim <<= resid
                    del sbim
                    resid = bim

                if variance:
                    resid = resid.getImage()
                    resid /= var
                    
                im_resid.append(resid)

                im = im_resid.makeMosaic()
            else:
                im = cand.getMaskedImage()

            if normalize:
                im /= afwMath.makeStatistics(im, afwMath.MAX).getValue()

            objId = splitId(cand.getSource().getId(), True)["objId"]
            if psf:
                lab = "%d chi^2 %.1f" % (objId, rchi2)
                ctype = ds9.RED if cand.isBad() else ds9.GREEN
            else:
                lab = "%d flux %8.3g" % (objId, cand.getSource().getPsfFlux())
                ctype = ds9.GREEN

            mos.append(im, lab, ctype)

            if False and numpy.isnan(rchi2):
                ds9.mtv(cand.getMaskedImage().getImage(), title="candidate", frame=1)
                print "amp",  cand.getAmplitude()

            im = cand.getMaskedImage()
            center = (candidateIndex, xc - im.getX0(), yc - im.getY0())
            candidateIndex += 1
            if cand.isBad():
                candidateCentersBad.append(center)
            else:
                candidateCenters.append(center)

    if variance:
        title = "chi(Psf fit)"
    else:
        title = "Stars & residuals"
    mosaicImage = mos.makeMosaic(frame=frame, title=title)

    with ds9.Buffering():
        for centers, color in ((candidateCenters, ds9.GREEN), (candidateCentersBad, ds9.RED)):
            for cen in centers:
                bbox = mos.getBBox(cen[0])
                ds9.dot("+", cen[1] + bbox.getMinX(), cen[2] + bbox.getMinY(), frame=frame, ctype=color)

    return mosaicImage
Пример #2
0
def showPsfMosaic(exposure, psf=None, nx=7, ny=None,
                  showCenter=True, showEllipticity=False, showFwhm=False,
                  stampSize=0, frame=None, title=None):
    """Show a mosaic of Psf images.  exposure may be an Exposure (optionally with PSF),
    or a tuple (width, height)

    If stampSize is > 0, the psf images will be trimmed to stampSize*stampSize
    """

    scale = 1.0
    if showFwhm:
        showEllipticity = True
        scale = 2*math.log(2)         # convert sigma^2 to HWHM^2 for a Gaussian

    mos = displayUtils.Mosaic()

    try:                                # maybe it's a real Exposure
        width, height = exposure.getWidth(), exposure.getHeight()
        x0, y0 = exposure.getXY0()
        if not psf:
            psf = exposure.getPsf()
    except AttributeError:
        try:                            # OK, maybe a list [width, height]
            width, height = exposure[0], exposure[1]
            x0, y0 = 0, 0
        except TypeError:               # I guess not
            raise RuntimeError("Unable to extract width/height from object of type %s" % type(exposure))

    if not ny:
        ny = int(nx*float(height)/width + 0.5)
        if not ny:
            ny = 1

    centroidName = "base_GaussianCentroid"
    shapeName = "base_SdssShape"

    schema = afwTable.SourceTable.makeMinimalSchema()
    schema.getAliasMap().set("slot_Centroid", centroidName)
    schema.getAliasMap().set("slot_Centroid_flag", centroidName+"_flag")

    control = measBase.GaussianCentroidControl()
    centroider = measBase.GaussianCentroidAlgorithm(control, centroidName, schema)

    sdssShape = measBase.SdssShapeControl()
    shaper = measBase.SdssShapeAlgorithm(sdssShape, shapeName, schema)
    table = afwTable.SourceTable.make(schema)

    table.defineCentroid(centroidName)
    table.defineShape(shapeName)

    bbox = None
    if stampSize > 0:
        w, h = psf.computeImage(afwGeom.PointD(0, 0)).getDimensions()
        if stampSize <= w and stampSize <= h:
            bbox = afwGeom.BoxI(afwGeom.PointI((w - stampSize)//2, (h - stampSize)//2),
                                afwGeom.ExtentI(stampSize, stampSize))

    centers = []
    shapes = []
    for iy in range(ny):
        for ix in range(nx):
            x = int(ix*(width-1)/(nx-1)) + x0
            y = int(iy*(height-1)/(ny-1)) + y0

            im = psf.computeImage(afwGeom.PointD(x, y)).convertF()
            imPeak = psf.computePeak(afwGeom.PointD(x, y))
            im /= imPeak
            if bbox:
                im = im.Factory(im, bbox)
            lab = "PSF(%d,%d)" % (x, y) if False else ""
            mos.append(im, lab)

            exp = afwImage.makeExposure(afwImage.makeMaskedImage(im))
            w, h = im.getWidth(), im.getHeight()
            centerX = im.getX0() + w//2
            centerY = im.getY0() + h//2
            src = table.makeRecord()
            foot = afwDet.Footprint(exp.getBBox())
            foot.addPeak(centerX, centerY, 1)
            src.setFootprint(foot)

            centroider.measure(src, exp)
            centers.append((src.getX() - im.getX0(), src.getY() - im.getY0()))

            shaper.measure(src, exp)
            shapes.append((src.getIxx(), src.getIxy(), src.getIyy()))

    mos.makeMosaic(frame=frame, title=title if title else "Model Psf", mode=nx)

    if centers and frame is not None:
        with ds9.Buffering():
            for i, (cen, shape) in enumerate(zip(centers, shapes)):
                bbox = mos.getBBox(i)
                xc, yc = cen[0] + bbox.getMinX(), cen[1] + bbox.getMinY()
                if showCenter:
                    ds9.dot("+", xc, yc, ctype=ds9.BLUE, frame=frame)

                if showEllipticity:
                    ixx, ixy, iyy = shape
                    ixx *= scale
                    ixy *= scale
                    iyy *= scale
                    ds9.dot("@:%g,%g,%g" % (ixx, ixy, iyy), xc, yc, frame=frame, ctype=ds9.RED)

    return mos
    def getClumps(self, sigma=1.0, display=False):
        if self._num <= 0:
            raise RuntimeError("No candidate PSF sources")

        psfImage = self.getImage()
        #
        # Embed psfImage into a larger image so we can smooth when measuring it
        #
        width, height = psfImage.getWidth(), psfImage.getHeight()
        largeImg = psfImage.Factory(afwGeom.ExtentI(2 * width, 2 * height))
        largeImg.set(0)

        bbox = afwGeom.BoxI(afwGeom.PointI(width, height),
                            afwGeom.ExtentI(width, height))
        largeImg.assign(psfImage, bbox, afwImage.LOCAL)
        #
        # Now measure that image, looking for the highest peak.  Start by building an Exposure
        #
        msk = afwImage.MaskU(largeImg.getDimensions())
        msk.set(0)
        var = afwImage.ImageF(largeImg.getDimensions())
        var.set(1)
        mpsfImage = afwImage.MaskedImageF(largeImg, msk, var)
        mpsfImage.setXY0(afwGeom.PointI(-width, -height))
        del msk
        del var
        exposure = afwImage.makeExposure(mpsfImage)

        #
        # Next run an object detector
        #
        maxVal = afwMath.makeStatistics(psfImage, afwMath.MAX).getValue()
        threshold = maxVal - sigma * math.sqrt(maxVal)
        if threshold <= 0.0:
            threshold = maxVal

        threshold = afwDetection.Threshold(threshold)

        ds = afwDetection.FootprintSet(mpsfImage, threshold, "DETECTED")
        #
        # And measure it.  This policy isn't the one we use to measure
        # Sources, it's only used to characterize this PSF histogram
        #
        schema = SourceTable.makeMinimalSchema()
        psfImageConfig = SingleFrameMeasurementConfig()
        psfImageConfig.slots.centroid = "base_SdssCentroid"
        psfImageConfig.plugins["base_SdssCentroid"].doFootprintCheck = False
        psfImageConfig.slots.psfFlux = None  # "base_PsfFlux"
        psfImageConfig.slots.apFlux = "base_CircularApertureFlux_3_0"
        psfImageConfig.slots.modelFlux = None
        psfImageConfig.slots.instFlux = None
        psfImageConfig.slots.calibFlux = None
        psfImageConfig.slots.shape = "base_SdssShape"
        #   Formerly, this code had centroid.sdss, flux.psf, flux.naive,
        #   flags.pixel, and shape.sdss
        psfImageConfig.algorithms.names = [
            "base_SdssCentroid", "base_CircularApertureFlux", "base_SdssShape"
        ]
        psfImageConfig.algorithms["base_CircularApertureFlux"].radii = [3.0]
        psfImageConfig.validate()
        task = SingleFrameMeasurementTask(schema, config=psfImageConfig)

        sourceCat = SourceCatalog(schema)

        gaussianWidth = 1.5  # Gaussian sigma for detection convolution
        exposure.setPsf(algorithmsLib.DoubleGaussianPsf(11, 11, gaussianWidth))

        ds.makeSources(sourceCat)
        #
        # Show us the Histogram
        #
        if display:
            frame = 1
            dispImage = mpsfImage.Factory(
                mpsfImage,
                afwGeom.BoxI(afwGeom.PointI(width, height),
                             afwGeom.ExtentI(width, height)), afwImage.LOCAL)
            ds9.mtv(dispImage, title="PSF Selection Image", frame=frame)

        clumps = list()  # List of clumps, to return
        e = None  # thrown exception
        IzzMin = 1.0  # Minimum value for second moments
        IzzMax = (
            self._xSize /
            8.0)**2  # Max value ... clump radius should be < clumpImgSize/8
        apFluxes = []
        task.run(
            sourceCat,
            exposure)  # notes that this is backwards for the new framework
        for i, source in enumerate(sourceCat):
            if source.getCentroidFlag():
                continue
            x, y = source.getX(), source.getY()

            apFluxes.append(source.getApFlux())

            val = mpsfImage.getImage().get(int(x) + width, int(y) + height)

            psfClumpIxx = source.getIxx()
            psfClumpIxy = source.getIxy()
            psfClumpIyy = source.getIyy()

            if display:
                if i == 0:
                    ds9.pan(x, y, frame=frame)

                ds9.dot("+", x, y, ctype=ds9.YELLOW, frame=frame)
                ds9.dot("@:%g,%g,%g" % (psfClumpIxx, psfClumpIxy, psfClumpIyy),
                        x,
                        y,
                        ctype=ds9.YELLOW,
                        frame=frame)

            if psfClumpIxx < IzzMin or psfClumpIyy < IzzMin:
                psfClumpIxx = max(psfClumpIxx, IzzMin)
                psfClumpIyy = max(psfClumpIyy, IzzMin)
                if display:
                    ds9.dot("@:%g,%g,%g" %
                            (psfClumpIxx, psfClumpIxy, psfClumpIyy),
                            x,
                            y,
                            ctype=ds9.RED,
                            frame=frame)

            det = psfClumpIxx * psfClumpIyy - psfClumpIxy * psfClumpIxy
            try:
                a, b, c = psfClumpIyy / det, -psfClumpIxy / det, psfClumpIxx / det
            except ZeroDivisionError:
                a, b, c = 1e4, 0, 1e4

            clumps.append(
                Clump(peak=val,
                      x=x,
                      y=y,
                      a=a,
                      b=b,
                      c=c,
                      ixx=psfClumpIxx,
                      ixy=psfClumpIxy,
                      iyy=psfClumpIyy))

        if len(clumps) == 0:
            msg = "Failed to determine center of PSF clump"
            if e:
                msg += ": %s" % e
            raise RuntimeError(msg)

        # if it's all we got return it
        if len(clumps) == 1:
            return clumps

        # which clump is the best?
        # if we've undistorted the moments, stars should only have 1 clump
        # use the apFlux from the clump measurement, and take the highest
        # ... this clump has more psf star candidate neighbours than the others.

        # get rid of any that are huge, and thus poorly defined
        goodClumps = []
        for clump in clumps:
            if clump.ixx < IzzMax and clump.iyy < IzzMax:
                goodClumps.append(clump)

        # if culling > IzzMax cost us all clumps, we'll have to take what we have
        if len(goodClumps) == 0:
            goodClumps = clumps

        # use the 'brightest' clump
        iBestClump = numpy.argsort(apFluxes)[0]
        clumps = [clumps[iBestClump]]
        return clumps
Пример #4
0
    def _makeAmpInfoCatalog(self, ccd):
        """Construct an amplifier info catalog
        """
        # Much of this will need to be filled in when we know it.
        assert len(ccd['amplifiers']) > 0
        amp = list(ccd['amplifiers'].values())[0]

        rawBBox = self._makeBBoxFromList(amp['rawBBox'])  # total in file
        xRawExtent, yRawExtent = rawBBox.getDimensions()

        from lsst.afw.table import LL, LR, UL, UR
        readCorners = dict(LL=LL, LR=LR, UL=UL, UR=UR)

        schema = AmpInfoTable.makeMinimalSchema()

        linThreshKey = schema.addField('linearityThreshold', type=float)
        linMaxKey = schema.addField('linearityMaximum', type=float)
        linUnitsKey = schema.addField('linearityUnits', type=str, size=9)
        hduKey = schema.addField('hdu', type=np.int32)
        # end placeholder
        self.ampInfoDict = {}
        ampCatalog = AmpInfoCatalog(schema)
        for name, amp in sorted(ccd['amplifiers'].items(),
                                key=lambda x: x[1]['hdu']):
            record = ampCatalog.addNew()
            record.setName(name)
            record.set(hduKey, amp['hdu'])

            ix, iy = amp['ixy']
            perAmpData = amp['perAmpData']
            if perAmpData:
                x0, y0 = 0, 0  # origin of data within each amp image
            else:
                x0, y0 = ix * xRawExtent, iy * yRawExtent

            rawDataBBox = self._makeBBoxFromList(
                amp['rawDataBBox'])  # Photosensitive area
            xDataExtent, yDataExtent = rawDataBBox.getDimensions()
            record.setBBox(
                afwGeom.BoxI(
                    afwGeom.PointI(ix * xDataExtent, iy * yDataExtent),
                    rawDataBBox.getDimensions()))

            rawBBox = self._makeBBoxFromList(amp['rawBBox'])
            rawBBox.shift(afwGeom.ExtentI(x0, y0))
            record.setRawBBox(rawBBox)

            rawDataBBox = self._makeBBoxFromList(amp['rawDataBBox'])
            rawDataBBox.shift(afwGeom.ExtentI(x0, y0))
            record.setRawDataBBox(rawDataBBox)

            rawSerialOverscanBBox = self._makeBBoxFromList(
                amp['rawSerialOverscanBBox'])
            rawSerialOverscanBBox.shift(afwGeom.ExtentI(x0, y0))
            record.setRawHorizontalOverscanBBox(rawSerialOverscanBBox)

            rawParallelOverscanBBox = self._makeBBoxFromList(
                amp['rawParallelOverscanBBox'])
            rawParallelOverscanBBox.shift(afwGeom.ExtentI(x0, y0))
            record.setRawVerticalOverscanBBox(rawParallelOverscanBBox)

            rawSerialPrescanBBox = self._makeBBoxFromList(
                amp['rawSerialPrescanBBox'])
            rawSerialPrescanBBox.shift(afwGeom.ExtentI(x0, y0))
            record.setRawPrescanBBox(rawSerialPrescanBBox)

            if perAmpData:
                record.setRawXYOffset(
                    afwGeom.Extent2I(ix * xRawExtent, iy * yRawExtent))
            else:
                record.setRawXYOffset(afwGeom.Extent2I(0, 0))

            record.setReadoutCorner(readCorners[amp['readCorner']])
            record.setGain(amp['gain'])
            record.setReadNoise(amp['readNoise'])
            record.setSaturation(amp['saturation'])
            record.setHasRawInfo(True)
            # flip data when assembling if needs be (e.g. data from the serial at the top of a CCD)
            flipX, flipY = amp.get("flipXY")

            record.setRawFlipX(flipX)
            record.setRawFlipY(flipY)
            # linearity placeholder stuff
            record.setLinearityCoeffs(
                [float(val) for val in amp['linearityCoeffs']])
            record.setLinearityType(amp['linearityType'])
            record.set(linThreshKey, float(amp['linearityThreshold']))
            record.set(linMaxKey, float(amp['linearityMax']))
            record.set(linUnitsKey, "DN")
        return ampCatalog
Пример #5
0
    def makeMosaic(self,
                   images=None,
                   display="deferToFrame",
                   mode=None,
                   background=None,
                   title="",
                   frame=None):
        """Return a mosaic of all the images provided; if none are specified,
        use the list accumulated with Mosaic.append().

        Note that this mosaic is a patchwork of the input images;  if you want to
        make a mosaic of a set images of the sky, you probably want to use the coadd code
        
        If display or frame (deprecated) is specified, display the mosaic
        """

        if not images:
            images = self.images

        self.nImage = len(images)
        if self.nImage == 0:
            raise RuntimeError, "You must provide at least one image"

        self.xsize, self.ysize = 0, 0
        for im in images:
            w, h = im.getWidth(), im.getHeight()
            if w > self.xsize:
                self.xsize = w
            if h > self.ysize:
                self.ysize = h

        if background is None:
            background = self.background
        if mode is None:
            mode = self.mode

        if mode == "square":
            nx, ny = 1, self.nImage
            while nx * im.getWidth() < ny * im.getHeight():
                nx += 1
                ny = self.nImage // nx

                if nx * ny < self.nImage:
                    ny += 1
                if nx * ny < self.nImage:
                    nx += 1

            if nx > self.nImage:
                nx = self.nImage

            assert (nx * ny >= self.nImage)
        elif mode == "x":
            nx, ny = self.nImage, 1
        elif mode == "y":
            nx, ny = 1, self.nImage
        elif isinstance(mode, int):
            nx = mode
            ny = self.nImage // nx
            if nx * ny < self.nImage:
                ny += 1
        else:
            raise RuntimeError, ("Unknown mosaicing mode: %s" % mode)

        self.nx, self.ny = nx, ny

        mosaic = images[0].Factory(
            afwGeom.Extent2I(nx * self.xsize + (nx - 1) * self.gutter,
                             ny * self.ysize + (ny - 1) * self.gutter))
        try:
            mosaic.set(self.background)
        except AttributeError:
            raise RuntimeError(
                "Attempt to mosaic images of type %s which don't support set" %
                type(mosaic))

        for i in range(len(images)):
            smosaic = mosaic.Factory(mosaic, self.getBBox(i % nx, i // nx),
                                     afwImage.LOCAL)
            im = images[i]

            if smosaic.getDimensions() != im.getDimensions(
            ):  # im is smaller than smosaic
                llc = afwGeom.PointI(
                    (smosaic.getWidth() - im.getWidth()) // 2,
                    (smosaic.getHeight() - im.getHeight()) // 2)
                smosaic = smosaic.Factory(
                    smosaic, afwGeom.Box2I(llc, im.getDimensions()),
                    afwImage.LOCAL)

            smosaic <<= im

        display = _getDisplayFromDisplayOrFrame(display, frame)
        if display:
            display.mtv(mosaic, title=title)

            if images == self.images:
                self.drawLabels(display=display)

        return mosaic
Пример #6
0
def addAmp(ampCatalog, i, eparams):
    """ Add an amplifier to an AmpInfoCatalog

    @param ampCatalog: An instance of an AmpInfoCatalog object to fill with amp properties
    @param i which amplifier? (i == 0 ? left : right)
    @param eparams: Electronic parameters.  This is a list of tuples with (i, params),
                    where params is a dictionary of electronic parameters.
    """
    #
    # Layout of active and overclock pixels in the as-readout data  The layout is:
    #     Amp0 || extended | overclock | data || data | overclock | extended || Amp1
    # for each row; all rows are identical in drift-scan data
    #
    height = 1361  # number of rows in a frame
    width = 1024  # number of data pixels read out through one amplifier
    nExtended = 8  # number of pixels in the extended register
    nOverclock = 32  # number of (horizontal) overclock pixels
    #
    # Construct the needed bounding boxes given that geometrical information.
    #
    # Note that all the offsets are relative to the origin of this amp, not to its eventual
    # position in the CCD
    #
    record = ampCatalog.addNew()
    xtot = width + nExtended + nOverclock
    allPixels = afwGeom.BoxI(afwGeom.PointI(0, 0),
                             afwGeom.ExtentI(xtot, height))
    biasSec = afwGeom.BoxI(afwGeom.PointI(nExtended if i == 0 else width, 0),
                           afwGeom.ExtentI(nOverclock, height))
    dataSec = afwGeom.BoxI(
        afwGeom.PointI(nExtended + nOverclock if i == 0 else 0, 0),
        afwGeom.ExtentI(width, height))
    emptyBox = afwGeom.BoxI()
    bbox = afwGeom.BoxI(afwGeom.PointI(0, 0), afwGeom.ExtentI(width, height))
    bbox.shift(afwGeom.Extent2I(width * i, 0))

    shiftp = afwGeom.Extent2I(xtot * i, 0)
    allPixels.shift(shiftp)
    biasSec.shift(shiftp)
    dataSec.shift(shiftp)

    record.setBBox(bbox)
    record.setRawXYOffset(afwGeom.ExtentI(0, 0))
    record.setName('left' if i == 0 else 'right')
    record.setReadoutCorner(afwTable.LL if i == 0 else afwTable.LR)
    record.setGain(eparams['gain'])
    record.setReadNoise(eparams['readNoise'])
    record.setSaturation(eparams['fullWell'])
    record.setSuspectLevel(float("nan"))
    record.setLinearityType(NullLinearityType)
    record.setLinearityCoeffs([
        1.,
    ])
    record.setHasRawInfo(True)
    record.setRawFlipX(False)
    record.setRawFlipY(False)
    record.setRawBBox(allPixels)
    record.setRawDataBBox(dataSec)
    record.setRawHorizontalOverscanBBox(biasSec)
    record.setRawVerticalOverscanBBox(emptyBox)
    record.setRawPrescanBBox(emptyBox)
Пример #7
0
def showPsfResiduals(exposure, sourceSet, magType="psf", scale=10, frame=None):
    mimIn = exposure.getMaskedImage()
    mimIn = mimIn.Factory(mimIn, True)  # make a copy to subtract from

    psf = exposure.getPsf()
    psfWidth, psfHeight = psf.getLocalKernel().getDimensions()
    #
    # Make the image that we'll paste our residuals into.  N.b. they can overlap the edges
    #
    w, h = int(mimIn.getWidth() / scale), int(mimIn.getHeight() / scale)

    im = mimIn.Factory(w + psfWidth, h + psfHeight)

    cenPos = []
    for s in sourceSet:
        x, y = s.getX(), s.getY()

        sx, sy = int(x / scale + 0.5), int(y / scale + 0.5)

        smim = im.Factory(
            im,
            afwGeom.BoxI(afwGeom.PointI(sx, sy),
                         afwGeom.ExtentI(psfWidth, psfHeight)))
        sim = smim.getImage()

        try:
            if magType == "ap":
                flux = s.getApFlux()
            elif magType == "model":
                flux = s.getModelFlux()
            elif magType == "psf":
                flux = s.getPsfFlux()
            else:
                raise RuntimeError("Unknown flux type %s" % magType)

            subtractPsf(psf, mimIn, x, y, flux)
        except Exception as e:
            print(e)

        try:
            expIm = mimIn.getImage().Factory(
                mimIn.getImage(),
                afwGeom.BoxI(
                    afwGeom.PointI(
                        int(x) - psfWidth // 2,
                        int(y) - psfHeight // 2),
                    afwGeom.ExtentI(psfWidth, psfHeight)),
            )
        except pexExcept.Exception:
            continue

        cenPos.append([x - expIm.getX0() + sx, y - expIm.getY0() + sy])

        sim += expIm

    if frame is not None:
        ds9.mtv(im, frame=frame)
        with ds9.Buffering():
            for x, y in cenPos:
                ds9.dot("+", x, y, frame=frame)

    return im
Пример #8
0
    def write(self, dirName=".", fileName=None, metadata=None):
        if not pyfits:
            raise RuntimeError(
                "I failed to import pyfits, so cannot write to disk")

        if fileName is None:
            fileName = self.fileNameFormat % (self.obsDate, self.arm,
                                              self.spectrograph)
        fullFileName = os.path.join(dirName, fileName)
        #
        # We'll pack all the traces into a single masked image, so figure out how large it needs to be
        #
        # Start by unpacking the traces' BBoxes; we need to do this anyway for the fits I/O
        #
        minX = []
        minY = []
        maxX = []
        maxY = []
        width = 0
        for i in range(len(self.traces)):
            bbox = self.traces[i].getBBox()

            minX.append(bbox.getMinX())
            minY.append(bbox.getMinY())
            maxX.append(bbox.getMaxX())
            maxY.append(bbox.getMaxY())

            width += bbox.getWidth()

        height = max(maxY) + 1
        allTracesMI = afwImage.MaskedImageF(width, height)

        # Copy trace's MaskedImages to allTracesMI
        x0 = 0
        origin = afwGeom.PointI(0, 0)
        for i in range(len(self.traces)):
            trace = self.traces[i]

            xy0 = afwGeom.Point2I(x0, minY[i])  # origin in allTracesMI
            allTracesMI[afwGeom.BoxI(xy0, trace.getDimensions())] = \
                        trace.Factory(trace, afwGeom.BoxI(origin, trace.getDimensions()), afwImage.LOCAL)

            x0 += trace.getWidth()
        #
        # Time to actually write the data
        #
        if metadata is None:
            hdr = dafBase.PropertySet()
        else:
            hdr = metadata

        hdr.add('OBSTYPE', 'FIBERTRACE')

        # Write fits file from MaskedImage
        allTracesMI.writeFits(fullFileName, hdr)

        # append the additional HDUs
        hdu = pyfits.BinTableHDU.from_columns([
            pyfits.Column(name='FIBERID',
                          format='J',
                          array=np.array(self.fiberId, dtype=np.int32)),
            pyfits.Column(name='MINX',
                          format='J',
                          array=np.array(minX, dtype=np.int32)),
            pyfits.Column(name='MINY',
                          format='J',
                          array=np.array(minY, dtype=np.int32)),
            pyfits.Column(name='MAXX',
                          format='J',
                          array=np.array(maxX, dtype=np.int32)),
            pyfits.Column(name='MAXY',
                          format='J',
                          array=np.array(maxY, dtype=np.int32)),
        ])

        hdu.name = "ID_BOX"
        hdu.header["INHERIT"] = True

        # clobber=True in writeto prints a message, so use open instead

        with pyfits.open(fullFileName, "update") as fd:
            fd[1].name = "IMAGE"
            fd[2].name = "MASK"
            fd[3].name = "VARIANCE"
            fd.append(hdu)
Пример #9
0
 def _get_bbox(self, tract):
     """returns a afwGeom.BoxI instance given a `tract` and the current options (ra, dec, side_pixel)"""
     xy = afwGeom.PointI(tract.getWcs().skyToPixel(self.radec))
     cutout_size = afwGeom.ExtentI(self.side_pixel, self.side_pixel)
     return afwGeom.BoxI(xy - cutout_size // 2, cutout_size)
Пример #10
0
    def measure(self):
        """Detect and measure sources"""
        mi = self.exposure.getMaskedImage()

        #
        # We do a pretty good job of interpolating, so don't propagagate the convolved CR/INTRP bits
        # (we'll keep them for the original CR/INTRP pixels)
        #
        savedMask = mi.getMask().Factory(mi.getMask(), True)
        saveBits = savedMask.getPlaneBitMask("CR") | \
                   savedMask.getPlaneBitMask("BAD") | \
                   savedMask.getPlaneBitMask("INTRP") # Bits to not convolve
        savedMask &= saveBits

        msk = mi.getMask(); msk &= ~saveBits; del msk # Clear the saved bits
        #
        # Smooth image
        #
        cnvImage = mi.Factory(mi.getBBox(afwImage.PARENT))
        afwMath.convolve(cnvImage, mi, self.psf.getKernel(), afwMath.ConvolutionControl())

        msk = cnvImage.getMask(); msk |= savedMask; del msk # restore the saved bits

        threshold = afwDetection.Threshold(3, afwDetection.Threshold.STDEV)
        #
        # Only search the part of the frame that was PSF-smoothed
        #        
        llc = afwGeom.PointI(self.psf.getKernel().getWidth()/2, self.psf.getKernel().getHeight()/2)
        urc = afwGeom.PointI(cnvImage.getWidth() - 1, cnvImage.getHeight() - 1) - afwGeom.ExtentI(llc[0], llc[1]);
        middle = cnvImage.Factory(cnvImage, afwGeom.BoxI(llc, urc), afwImage.LOCAL)
        ds = afwDetection.FootprintSetF(middle, threshold, "DETECTED")
        del middle
        #
        # ds only searched the middle but it belongs to the entire MaskedImage
        #
        ds.setRegion(mi.getBBox(afwImage.PARENT))
        #
        # We want to grow the detections into the edge by at least one pixel so that it sees the EDGE bit
        #
        grow, isotropic = 1, False
        ds = afwDetection.FootprintSetF(ds, grow, isotropic)
        ds.setMask(mi.getMask(), "DETECTED")
        #
        # Reinstate the saved (e.g. BAD) (and also the DETECTED | EDGE) bits in the unsmoothed image
        #
        savedMask <<= cnvImage.getMask()
        msk = mi.getMask(); msk |= savedMask; del msk
        del savedMask; savedMask = None

        #msk = mi.getMask(); msk &= ~0x10; del msk # XXXX

        if self.display:
            ds9.mtv(mi, frame = 0, lowOrderBits = True)
            ds9.mtv(cnvImage, frame = 1)

        objects = ds.getFootprints()
        #
        # Time to actually measure
        #
        msPolicy = policy.Policy.createPolicy(policy.DefaultPolicyFile("meas_algorithms",
            "examples/measureSources.paf"))
        msPolicy = msPolicy.getPolicy("measureSources")
        measureSources = measAlg.makeMeasureSources(self.exposure, msPolicy)
        
        self.sourceList = afwDetection.SourceSet()
        for i in range(len(objects)):
            source = afwDetection.Source()
            self.sourceList.append(source)

            source.setId(i)
            source.setFlagForDetection(source.getFlagForDetection() | measAlg.Flags.BINNED1);

            try:
                measureSources.apply(source, objects[i])
            except Exception, e:
                try:
                    print e
                except Exception, ee:
                    print ee
Пример #11
0
def makeRaft(raftName):
    dewar = cameraGeom.Raft(cameraGeom.Id("DECam"), 1, 1)
    dewar.addDetector(afwGeom.PointI(0, 0), cameraGeom.FpPoint(0.0, 0.0),
                      cameraGeom.Orientation(0), makeCcd(raftName))
    return dewar
Пример #12
0
    def setBrightObjectMasks(self, exposure, dataId, brightObjectMasks):
        """Set the bright object masks

        exposure:          Exposure under consideration
        dataId:            Data identifier dict for patch
        brightObjectMasks: afwTable of bright objects to mask

        # ---------------------------------------------- #

        copied from AssembleCoaddTask. To be implemented so that it
        can be imported more easily

        see https://jira.lsstcorp.org/browse/DM-15030

        # ---------------------------------------------- #

        """
        #
        # Check the metadata specifying the tract/patch/filter
        #
        if brightObjectMasks is None:
            self.log.warn("Unable to apply bright object mask: none supplied")
            return
        self.log.info("Applying %d bright object masks to %s",
                      len(brightObjectMasks), dataId)
        md = brightObjectMasks.table.getMetadata()
        for k in dataId:
            if not md.exists(k):
                self.log.warn("Expected to see %s in metadata", k)
            else:
                if md.get(k) != dataId[k]:
                    self.log.warn(
                        "Expected to see %s == %s in metadata, saw %s", k,
                        md.get(k), dataId[k])

        mask = exposure.getMaskedImage().getMask()
        wcs = exposure.getWcs()
        plateScale = wcs.getPixelScale().asArcseconds()

        for rec in brightObjectMasks:
            center = afwGeom.PointI(wcs.skyToPixel(rec.getCoord()))
            if rec["type"] == "box":
                assert rec["angle"] == 0.0, ("Angle != 0 for mask object %s" %
                                             rec["id"])
                width = rec["width"].asArcseconds(
                ) / plateScale  # convert to pixels
                height = rec["height"].asArcseconds(
                ) / plateScale  # convert to pixels

                halfSize = afwGeom.ExtentI(0.5 * width, 0.5 * height)
                bbox = afwGeom.Box2I(center - halfSize, center + halfSize)

                bbox = afwGeom.BoxI(
                    afwGeom.PointI(int(center[0] - 0.5 * width),
                                   int(center[1] - 0.5 * height)),
                    afwGeom.PointI(int(center[0] + 0.5 * width),
                                   int(center[1] + 0.5 * height)))
                spans = afwGeom.SpanSet(bbox)
            elif rec["type"] == "circle":
                radius = int(rec["radius"].asArcseconds() /
                             plateScale)  # convert to pixels
                spans = afwGeom.SpanSet.fromShape(radius, offset=center)
            else:
                self.log.warn("Unexpected region type %s at %s" % rec["type"],
                              center)
                continue
            spans.clippedTo(mask.getBBox()).setMask(mask,
                                                    self.brightObjectBitmask)
Пример #13
0
    def readFits(fileName, hdu=0, flags=0):
        """Read a our list of Backgrounds from a file
        @param fileName         FITS file to read
        @param hdu              First Header/Data Unit to attempt to read from
        @param flags            Flags to control details of reading; currently unused,
                                but present for consistency with
                                afw.table.BaseCatalog.readFits.

        See also getImage()
        """
        if not isinstance(fileName,
                          MemFileManager) and not os.path.exists(fileName):
            raise RuntimeError("File not found: %s" % fileName)

        self = BackgroundList()

        while True:
            hdu += 1

            md = dafBase.PropertyList()
            try:
                img = afwImage.ImageF(fileName, hdu, md)
                hdu += 1
            except FitsError:
                break

            msk = afwImage.MaskU(fileName, hdu)
            hdu += 1
            var = afwImage.ImageF(fileName, hdu)

            statsImage = afwImage.makeMaskedImage(img, msk, var)

            x0 = md.get("BKGD_X0")
            y0 = md.get("BKGD_Y0")
            width = md.get("BKGD_WIDTH")
            height = md.get("BKGD_HEIGHT")
            imageBBox = afwGeom.BoxI(afwGeom.PointI(x0, y0),
                                     afwGeom.ExtentI(width, height))

            interpStyle = md.get("INTERPSTYLE")
            undersampleStyle = md.get("UNDERSAMPLESTYLE")

            # Older outputs won't have APPROX* settings.  Provide alternative defaults.
            # Note: Currently X- and Y-orders must be equal due to a limitation in
            #       math::Chebyshev1Function2.  Setting approxOrderY = -1 is equivalent
            #       to saying approxOrderY = approxOrderX.
            approxStyle = md.get("APPROXSTYLE") if "APPROXSTYLE" in md.names() \
                          else afwMath.ApproximateControl.UNKNOWN
            approxOrderX = md.get(
                "APPROXORDERX") if "APPROXORDERX" in md.names() else 1
            approxOrderY = md.get(
                "APPROXORDERY") if "APPROXORDERY" in md.names() else -1
            approxWeighting = md.get(
                "APPROXWEIGHTING") if "APPROXWEIGHTING" in md.names() else True

            bkgd = afwMath.BackgroundMI(imageBBox, statsImage)
            bctrl = bkgd.getBackgroundControl()
            bctrl.setInterpStyle(interpStyle)
            bctrl.setUndersampleStyle(undersampleStyle)
            actrl = afwMath.ApproximateControl(approxStyle, approxOrderX,
                                               approxOrderY, approxWeighting)
            bctrl.setApproximateControl(actrl)
            bgInfo = (bkgd, interpStyle, undersampleStyle, approxStyle,
                      approxOrderX, approxOrderY, approxWeighting)
            self.append(bgInfo)

        return self
Пример #14
0
# From SimonK's tutorial
# 3/31/2017 -- MSSG

import sys
import lsst.afw.image as afwImage
import lsst.afw.geom as afwGeom
from lsst.pex.exceptions import LengthError
import lsst.afw.math as afwMath
import lsst.afw.detection as afwDetect
import lsst.afw.display as afwDisplay

n_objects = 1000

box = afwGeom.BoxI(afwGeom.PointI(300, 500), afwGeom.ExtentI(2000, 2048))

im = afwImage.ImageF(box)

print("im.getXY0() = ", im.getXY0())

subbox = afwGeom.BoxI(afwGeom.PointI(10, 10), afwGeom.ExtentI(100, 100))

try:
    im2 = afwImage.ImageF(im, subbox)
except LengthError:
    im2 = afwImage.ImageF(im, subbox, afwImage.LOCAL)

print("im2.getXY0() = ", im2.getXY0())

rand = afwMath.Random()
buffer_xy = 150  # Don't put objects near the edges
x_positions = [
Пример #15
0
 def makeBbox(x0, y0, x_extent, y_extent):
     return afwGeom.BoxI(afwGeom.PointI(x0, y0),
                         afwGeom.ExtentI(x_extent, y_extent))
Пример #16
0
    def testDetection(self):
        """Test object detection"""
        #
        # Fix defects
        #
        # Mask known bad pixels
        #
        measAlgorithmsDir = lsst.utils.getPackageDir('meas_algorithms')
        badPixels = defects.policyToBadRegionList(
            os.path.join(measAlgorithmsDir, "policy/BadPixels.paf"))
        # did someone lie about the origin of the maskedImage?  If so, adjust bad pixel list
        if self.XY0.getX() != self.mi.getX0() or self.XY0.getY(
        ) != self.mi.getY0():
            dx = self.XY0.getX() - self.mi.getX0()
            dy = self.XY0.getY() - self.mi.getY0()
            for bp in badPixels:
                bp.shift(-dx, -dy)

        algorithms.interpolateOverDefects(self.mi, self.psf, badPixels)
        #
        # Subtract background
        #
        bgGridSize = 64  # was 256 ... but that gives only one region and the spline breaks
        bctrl = afwMath.BackgroundControl(afwMath.Interpolate.NATURAL_SPLINE)
        bctrl.setNxSample(int(self.mi.getWidth() / bgGridSize) + 1)
        bctrl.setNySample(int(self.mi.getHeight() / bgGridSize) + 1)
        backobj = afwMath.makeBackground(self.mi.getImage(), bctrl)

        self.mi.getImage()[:] -= backobj.getImageF()
        #
        # Remove CRs
        #
        crConfig = algorithms.FindCosmicRaysConfig()
        crs = algorithms.findCosmicRays(self.mi, self.psf, 0,
                                        pexConfig.makePolicy(crConfig))
        #
        # We do a pretty good job of interpolating, so don't propagagate the convolved CR/INTRP bits
        # (we'll keep them for the original CR/INTRP pixels)
        #
        savedMask = self.mi.getMask().Factory(self.mi.getMask(), True)
        saveBits = savedMask.getPlaneBitMask("CR") | \
                   savedMask.getPlaneBitMask("BAD") | \
                   savedMask.getPlaneBitMask("INTRP") # Bits to not convolve
        savedMask &= saveBits

        msk = self.mi.getMask()
        msk &= ~saveBits  # Clear the saved bits
        del msk
        #
        # Smooth image
        #
        psf = algorithms.DoubleGaussianPsf(
            15, 15, self.FWHM / (2 * math.sqrt(2 * math.log(2))))

        cnvImage = self.mi.Factory(self.mi.getBBox())
        kernel = psf.getKernel()
        afwMath.convolve(cnvImage, self.mi, kernel,
                         afwMath.ConvolutionControl())

        msk = cnvImage.getMask()
        msk |= savedMask  # restore the saved bits
        del msk

        threshold = afwDetection.Threshold(3, afwDetection.Threshold.STDEV)
        #
        # Only search the part of the frame that was PSF-smoothed
        #
        llc = afwGeom.PointI(psf.getKernel().getWidth() / 2,
                             psf.getKernel().getHeight() / 2)
        urc = afwGeom.PointI(cnvImage.getWidth() - llc[0] - 1,
                             cnvImage.getHeight() - llc[1] - 1)
        middle = cnvImage.Factory(cnvImage, afwGeom.BoxI(llc, urc),
                                  afwImage.LOCAL)
        ds = afwDetection.FootprintSet(middle, threshold, "DETECTED")
        del middle
        #
        # Reinstate the saved (e.g. BAD) (and also the DETECTED | EDGE) bits in the unsmoothed image
        #
        savedMask[:] = cnvImage.getMask()
        msk = self.mi.getMask()
        msk |= savedMask
        del msk
        del savedMask

        if display:
            ds9.mtv(self.mi, frame=0)
            ds9.mtv(cnvImage, frame=1)

        #
        # Time to actually measure
        #
        schema = afwTable.SourceTable.makeMinimalSchema()
        sfm_config = measBase.SingleFrameMeasurementConfig()
        sfm_config.plugins = [
            "base_SdssCentroid", "base_CircularApertureFlux", "base_PsfFlux",
            "base_SdssShape", "base_GaussianFlux",
            "base_ClassificationExtendedness", "base_PixelFlags"
        ]
        sfm_config.slots.centroid = "base_SdssCentroid"
        sfm_config.slots.shape = "base_SdssShape"
        sfm_config.slots.psfFlux = "base_PsfFlux"
        sfm_config.slots.instFlux = None
        sfm_config.slots.apFlux = "base_CircularApertureFlux_3_0"
        sfm_config.slots.modelFlux = "base_GaussianFlux"
        sfm_config.slots.calibFlux = None
        sfm_config.plugins["base_SdssShape"].maxShift = 10.0
        sfm_config.plugins["base_CircularApertureFlux"].radii = [3.0]
        task = measBase.SingleFrameMeasurementTask(schema, config=sfm_config)
        measCat = afwTable.SourceCatalog(schema)
        # detect the sources and run with the measurement task
        ds.makeSources(measCat)
        self.exposure.setPsf(self.psf)
        task.run(measCat, self.exposure)

        for source in measCat:

            if source.get("base_PixelFlags_flag_edge"):
                continue

            if display:
                ds9.dot("+",
                        source.getX() - self.mi.getX0(),
                        source.getY() - self.mi.getY0())
Пример #17
0
    def testEdge(self):
        """Test that we can interpolate to the edge"""
        mi = afwImage.MaskedImageF(80, 30)

        ima = mi.getImage().getArray()
        #
        # Loop over number of bad columns at left or right edge of image
        #
        for nBadCol in range(0, 20):
            mi.set((0, 0x0, 0))

            np.random.seed(666)
            ima[:] = np.random.uniform(-1, 1, ima.shape)

            defects = []

            if nBadCol > 0:
                #
                # Bad left edge
                #
                ima[:, 0:nBadCol] = 10
                defects.append(
                    afwGeom.BoxI(afwGeom.PointI(0, 0),
                                 afwGeom.ExtentI(nBadCol, mi.getHeight())))
                #
                # With another bad set of columns next to bad left edge
                #
                ima[:, -nBadCol:] = 10
                defects.append(
                    afwGeom.BoxI(afwGeom.PointI(mi.getWidth() - nBadCol, 0),
                                 afwGeom.ExtentI(nBadCol, mi.getHeight())))
                #
                # Bad right edge
                #
                ima[0:10, nBadCol + 1:nBadCol + 4] = 100
                defects.append(
                    afwGeom.BoxI(afwGeom.PointI(nBadCol + 1, 0),
                                 afwGeom.ExtentI(3, 10)))
                #
                # With another bad set of columns next to bad right edge
                #
                ima[0:10, -nBadCol - 4:-nBadCol - 1] = 100
                defects.append((afwGeom.BoxI(
                    afwGeom.PointI(mi.getWidth() - nBadCol - 4, 0),
                    afwGeom.ExtentI(3, 10))))
            #
            # Test cases that left and right bad patches nearly (or do) coalesce
            #
            ima[-3:, 0:mi.getWidth() // 2 - 1] = 100
            defects.append(
                afwGeom.BoxI(afwGeom.PointI(0,
                                            mi.getHeight() - 3),
                             afwGeom.ExtentI(mi.getWidth() // 2 - 1, 1)))

            ima[-3:, mi.getWidth() // 2 + 1:] = 100
            defects.append(
                afwGeom.BoxI(
                    afwGeom.PointI(mi.getWidth() // 2 + 1,
                                   mi.getHeight() - 3),
                    afwGeom.ExtentI(mi.getWidth() // 2 - 1, 1)))

            ima[-2:, 0:mi.getWidth() // 2] = 100
            defects.append(
                afwGeom.BoxI(afwGeom.PointI(0,
                                            mi.getHeight() - 2),
                             afwGeom.ExtentI(mi.getWidth() // 2, 1)))

            ima[-2:, mi.getWidth() // 2 + 1:] = 100
            defects.append(
                afwGeom.BoxI(
                    afwGeom.PointI(mi.getWidth() // 2 + 1,
                                   mi.getHeight() - 2),
                    afwGeom.ExtentI(mi.getWidth() // 2 - 1, 1)))

            ima[-1:, :] = 100
            defects.append(
                afwGeom.BoxI(afwGeom.PointI(0,
                                            mi.getHeight() - 1),
                             afwGeom.ExtentI(mi.getWidth(), 1)))

            # Test fix for HSC-978: long defect stops one pixel shy of the edge (when nBadCol == 0)
            ima[13, :-1] = 100
            defects.append(
                afwGeom.BoxI(afwGeom.PointI(0, 13),
                             afwGeom.ExtentI(mi.getWidth() - 1, 1)))
            ima[14, 1:] = 100
            defects.append(
                afwGeom.BoxI(afwGeom.PointI(1, 14),
                             afwGeom.ExtentI(mi.getWidth() - 1, 1)))

            #
            # Build list of defects to interpolate over
            #
            defectList = []

            for bbox in defects:
                defectList.append(algorithms.Defect(bbox))
            #
            # Guess a PSF and do the work
            #
            if display:
                ds9.mtv(mi, frame=0)

            psf = algorithms.DoubleGaussianPsf(
                15, 15, 1. / (2 * math.sqrt(2 * math.log(2))))
            algorithms.interpolateOverDefects(mi, psf, defectList, 0, True)

            if display:
                ds9.mtv(mi, frame=1)

            self.assertGreater(np.min(ima), -2)
            self.assertGreater(2, np.max(ima))
Пример #18
0
 def _makeBBoxFromList(ylist):
     """Given a list [(x0, y0), (xsize, ysize)], probably from a yaml file, return a BoxI
         """
     (x0, y0), (xsize, ysize) = ylist
     return  afwGeom.BoxI(afwGeom.PointI(x0, y0), afwGeom.ExtentI(xsize, ysize))
Пример #19
0
def showCamera(camera,
               imageSource=FakeImageDataSource(),
               imageFactory=afwImage.ImageF,
               detectorNameList=None,
               binSize=10,
               bufferSize=10,
               frame=None,
               overlay=True,
               title="",
               ctype=afwDisplay.GREEN,
               textSize=1.25,
               originAtCenter=True,
               display=None,
               **kwargs):
    """!Show a Camera on display, with the specified display

    The rotation of the sensors is snapped to the nearest multiple of 90 deg.
    Also note that the pixel size is constant over the image array. The lower left corner (LLC) of each
    sensor amp is snapped to the LLC of the pixel containing the LLC of the image.
    if overlay show the IDs and detector boundaries

    @param[in] camera  Camera to show
    @param[in] imageSource  Source to get Ccd images from.  Must have a getCcdImage method.
    @param[in] imageFactory  Type of image to make
    @param[in] detectorNameList  List of names of Detectors to use. If None use all
    @param[in] binSize  bin factor
    @param[in] bufferSize  size of border in binned pixels to make around camera image.
    @param[in] frame  specify image display (@deprecated; new code should use display)
    @param[in] overlay  Overlay Detector IDs and boundaries?
    @param[in] title  Title in display
    @param[in] ctype  Color to use when drawing Detector boundaries
    @param[in] textSize  Size of detector labels
    @param[in] originAtCenter Put origin of the camera WCS at the center of the image? Else it will be LL
    @param[in] display  image display on which to display
    @param[in] **kwargs all remaining keyword arguments are passed to makeImageFromCamera
    @return the mosaic image
    """
    display = _getDisplayFromDisplayOrFrame(display, frame)

    if binSize < 1:
        binSize = 1
    cameraImage = makeImageFromCamera(camera,
                                      detectorNameList=detectorNameList,
                                      bufferSize=bufferSize,
                                      imageSource=imageSource,
                                      imageFactory=imageFactory,
                                      binSize=binSize,
                                      **kwargs)

    if detectorNameList is None:
        ccdList = [camera[name] for name in camera.getNameIter()]
    else:
        ccdList = [camera[name] for name in detectorNameList]

    if detectorNameList is None:
        camBbox = camera.getFpBBox()
    else:
        camBbox = afwGeom.Box2D()
        for detName in detectorNameList:
            for corner in camera[detName].getCorners(FOCAL_PLANE):
                camBbox.include(corner)
    pixelSize = ccdList[0].getPixelSize()
    if originAtCenter:
        #Can't divide SWIGGED extent type things when division is imported
        #from future.  This is DM-83
        ext = cameraImage.getBBox().getDimensions()

        wcsReferencePixel = afwGeom.PointI(ext.getX() // 2, ext.getY() // 2)
    else:
        wcsReferencePixel = afwGeom.Point2I(0, 0)
    wcs = makeFocalPlaneWcs(pixelSize * binSize, wcsReferencePixel)

    if display:
        if title == "":
            title = camera.getName()
        display.mtv(cameraImage, title=title, wcs=wcs)

        if overlay:
            with display.Buffering():
                camBbox = getCameraImageBBox(camBbox, pixelSize,
                                             bufferSize * binSize)
                bboxList = getCcdInCamBBoxList(ccdList, binSize, pixelSize,
                                               camBbox.getMin())
                for bbox, ccd in zip(bboxList, ccdList):
                    nQuarter = ccd.getOrientation().getNQuarter()
                    # borderWidth to 0.5 to align with the outside edge of the pixel
                    displayUtils.drawBBox(bbox,
                                          borderWidth=0.5,
                                          ctype=ctype,
                                          display=display)
                    dims = bbox.getDimensions()
                    display.dot(ccd.getName(),
                                bbox.getMinX() + dims.getX() / 2,
                                bbox.getMinY() + dims.getY() / 2,
                                ctype=ctype,
                                size=textSize,
                                textAngle=nQuarter * 90)

    return cameraImage
Пример #20
0
    jmp = {}
    jmp['x'] = []
    jmp['y'] = []
    jmp['flux'] = []
    for line in file:
        if line.startswith('#'):
            continue
        x = float(line.split()[0])
        y = float(line.split()[1])
        if ccdnum < 18:
            x = imsize.getX() - x + xoff
            y = imsize.getY() - y + yoff
        else:
            x = x - xoff
            y = y - yoff
        pt = afwGeom.PointI(int(x), int(y))
        if bbox.contains(pt):
            jmp['x'].append(x)
            jmp['y'].append(y)
            jmp['flux'].append(float(line.split()[2]))
    jmp['x'] = np.array(jmp['x'], float)
    jmp['y'] = np.array(jmp['y'], float)
    jmp['flux'] = np.array(jmp['flux'], float)
except IOError:
    print 'No JMP file %s' %(jmpfile)
    jmp = {}
    jmp['x'] = []
    jmp['y'] = []
    jmp['flux'] = []

try:
Пример #21
0
    def make_postage_stamp_plot(self,
                                index,
                                stamp_size=100,
                                reverse_colormap=False):
        """
        Gather the data for creating the source postage stamp plot.

        Parameters
        ----------
        index : int
            The location of the source data in the Source table.
        stamp_size : int, optional
            Size of the generated postage stamp in pixels.
        reverse_colormap : bool, optional
            Reverse the colormap. Default is black (low) to white (high).
        """
        ra_target, dec_target = (
            self.src['coord_ra'][self.good_indexes][index],
            self.src['coord_dec'][self.good_indexes][index])  # Radians
        radec = afwGeom.SpherePoint(ra_target, dec_target, afwGeom.radians)
        cutoutSize = afwGeom.ExtentI(stamp_size, stamp_size)
        wcs = self.calexp.getWcs()
        # Note: This call fails in version 15.0. Requires a weekly after that release.
        xy = afwGeom.PointI(wcs.skyToPixel(radec))
        bbox = afwGeom.BoxI(xy - cutoutSize // 2, cutoutSize)
        # Check for bounds that fall off the edges of the image. Need to clip them to the
        # image boundary otherwise the calexp_sub call fails.
        calexp_extent = self.calexp.getDimensions()
        clipped_bbox = afwGeom.BoxI(afwGeom.PointI(0, 0), calexp_extent)
        clipped_bbox.clip(bbox)
        # Postage stamp image only
        cutout_image = self.butler.get('calexp_sub',
                                       bbox=clipped_bbox,
                                       immediate=True,
                                       dataId=self.dataid).getMaskedImage()
        vmin, vmax = self.zscale.get_limits(cutout_image.image.array)
        self.image_src.data = {
            'img': [cutout_image.image.array],
            'x': [0],
            'y': [0],
            'dw': [clipped_bbox.getDimensions().getX()],
            'dh': [clipped_bbox.getDimensions().getY()]
        }
        gc = gray(256)
        if reverse_colormap:
            gc.reverse()
        lcm = LinearColorMapper(palette=gc, low=vmin, high=vmax)
        self.img_plt.image('img',
                           'x',
                           'y',
                           'dw',
                           'dh',
                           color_mapper=lcm,
                           source=self.image_src)
        # Color bar doesn't come up properly. Need to work on this later.
        colorbar = ColorBar(color_mapper=lcm,
                            ticker=BasicTicker(),
                            border_line_color=None,
                            label_standoff=5,
                            location=(0, 0))
        # self.img_plt.add_layout(colorbar, 'right')
        # Does the cutout_image have a wcs? It does not appear to...
        self.img_plt.circle(xy.getX() - cutout_image.getX0(),
                            xy.getY() - cutout_image.getY0(),
                            fill_color=None,
                            line_color='red',
                            radius=int(0.05 * stamp_size))
def addAmp(ampCatalog, amp, eparams):
    """ Add an amplifier to an AmpInfoCatalog
    
    @param ampCatalog: An instance of an AmpInfoCatalog object to fill with amp properties
    @param amp: Dictionary of amp geometric properties
    @param eparams: Dictionary of amp electronic properties for this amp
    """
    record = ampCatalog.addNew()
 
    xtot = amp['ewidth']
    ytot = amp['eheight']

    allPixels = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(xtot, ytot))
    biassl = amp['biassec']
    biasSec = afwGeom.Box2I(afwGeom.Point2I(biassl[0], biassl[1]), afwGeom.Point2I(biassl[2], biassl[3]))
    datasl = amp['datasec']
    dataSec = afwGeom.Box2I(afwGeom.Point2I(datasl[0], datasl[1]), afwGeom.Point2I(datasl[2], datasl[3]))

    extended = dataSec.getMin().getX()
    voverscan = ytot - dataSec.getMaxY()
    pscan = dataSec.getMin().getY()

    if not voverscan:
        voscanSec = afwGeom.Box2I(afwGeom.Point2I(extended, dataSec.getMax().getY()),
                                  afwGeom.Extent2I(dataSec.getDimensions().getX(), 0))
    else:
        voscanSec = afwGeom.Box2I(afwGeom.Point2I(extended, dataSec.getMax().getY()+1),
                                  afwGeom.Extent2I(dataSec.getDimensions().getX(), voverscan))
    pscanSec = afwGeom.Box2I(afwGeom.Point2I(extended, 0),
                             afwGeom.Extent2I(dataSec.getDimensions().getX(), pscan))

    if amp['flipX']:
        #No need to flip bbox or allPixels since they
        #are at the origin and span the full pixel grid
        biasSec.flipLR(xtot)
        dataSec.flipLR(xtot)
        voscanSec.flipLR(xtot)
        pscanSec.flipLR(xtot) 

    bbox = afwGeom.BoxI(afwGeom.PointI(0, 0), dataSec.getDimensions())
    bbox.shift(afwGeom.Extent2I(dataSec.getDimensions().getX()*eparams['index'][0], 0))

    shiftp = afwGeom.Extent2I(xtot*eparams['index'][0], 0)
    allPixels.shift(shiftp)
    biasSec.shift(shiftp)
    dataSec.shift(shiftp)
    voscanSec.shift(shiftp)
    pscanSec.shift(shiftp)

    record.setBBox(bbox)
    record.setRawXYOffset(afwGeom.ExtentI(0,0))
    #Set amplifier names according to the CFHT convention (A, B)
    if eparams['index'][0] == 0 and eparams['index'][1] == 0 :
        record.setName("A")
    elif eparams['index'][0] == 1 and eparams['index'][1] == 0 :
        record.setName("B")
    else :
        raise ValueError("Unexpected index parameter %i, %i"%(eparams['index'][0], eparams['index'][1]))
    record.setReadoutCorner(afwTable.LR if amp['flipX'] else afwTable.LL)    
    record.setGain(eparams['gain'])
    record.setReadNoise(eparams['readNoise'])
    record.setSaturation(int(eparams['saturation']))
    #The files do not have any linearity information
    record.setLinearityType('Proportional')
    record.setLinearityCoeffs([1.,])
    record.setHasRawInfo(True)
    record.setRawFlipX(False)
    record.setRawFlipY(False)
    record.setRawBBox(allPixels)
    record.setRawDataBBox(dataSec)
    record.setRawHorizontalOverscanBBox(biasSec)
    record.setRawVerticalOverscanBBox(voscanSec)
    record.setRawPrescanBBox(pscanSec)
Пример #23
0
def fitPatches(exp,
               nx=4,
               ny=8,
               bin=None,
               frame=None,
               returnResidualImage=False,
               r=None,
               lnGrad=None,
               theta=None):
    """Fit planes to a set of patches of an image im

If r, theta, and lnGrad are provided they should be lists (more accurately, support .append), and they have the
values of r, theta, and dlnI/dr from this image appended.
    """

    width, height = exp.getDimensions()

    if bin is not None:
        nx, ny = width // bin, height // bin

    xsize = width // nx
    ysize = height // ny

    if frame is not None:
        frame0 = frame
        ds9.mtv(exp, title="im", frame=frame) if True else None
        frame += 1

    if hasattr(exp, "getMaskedImage"):
        mi = exp.getMaskedImage()
        ccd = exp.getDetector()
    else:
        mi = exp
        ccd = None

    try:
        mi = mi.convertF()
    except AttributeError:
        pass

    if r is not None or lnGrad is not None:
        assert ccd is not None, "I need a CCD to set r and the logarithmic gradient"
        assert r is not None and lnGrad is not None, "Please provide both r and lnGrad"

    z = afwImage.ImageF(nx, ny)
    za = z.getArray()
    dlnzdx = afwImage.ImageF(nx, ny)
    dlnzdxa = dlnzdx.getArray()
    dlnzdy = afwImage.ImageF(nx, ny)
    dlnzdya = dlnzdy.getArray()
    dlnzdr = afwImage.ImageF(nx, ny)
    dlnzdra = dlnzdr.getArray()
    if returnResidualImage:
        residualImage = mi.clone()
        try:
            residualImage = residualImage.convertF()
        except AttributeError:
            pass
    else:
        residualImage = None

    with ds9.Buffering():
        for iy in range(ny):
            for ix in range(nx):
                bbox = afwGeom.BoxI(afwGeom.PointI(ix * xsize, iy * ysize),
                                    afwGeom.ExtentI(xsize, ysize))
                if False and frame is not None:
                    ds9Utils.drawBBox(bbox, frame=frame0)

                b, res = fitPlane(mi[bbox].getImage(),
                                  returnResidualImage=returnResidualImage,
                                  niter=5)

                b[1:] /= b[0]
                za[iy, ix], dlnzdxa[iy, ix], dlnzdya[iy, ix] = b

                if returnResidualImage:
                    residualImage[bbox][:] = res

                if ccd:
                    cen = afwGeom.PointD(bbox.getBegin() +
                                         bbox.getDimensions() / 2)
                    x, y = ccd.getPositionFromPixel(
                        cen).getMm()  # I really want pixels here
                    t = np.arctan2(y, x)
                    dlnzdra[iy, ix] = np.cos(t) * dlnzdxa[iy, ix] + np.sin(
                        t) * dlnzdya[iy, ix]

                    if r is not None:
                        if not (ix in (0, xsize - 1) or iy in (0, ysize - 1)):
                            r.append(np.hypot(x, y))
                            lnGrad.append(dlnzdra[iy, ix])
                            if theta is not None:
                                theta.append(t)

    if frame is not None:
        if False:
            ds9.mtv(z, title="z", frame=frame)
            frame += 1
            ds9.mtv(dlnzdx, title="dlnz/dx", frame=frame)
            frame += 1
            ds9.mtv(dlnzdy, title="dlnz/dy", frame=frame)
            frame += 1
        ds9.mtv(residualImage, title="res", frame=frame)
        frame += 1
        ds9.mtv(dlnzdr,
                title="dlnz/dr %s" % (ccd.getId().getSerial() if ccd else ""),
                frame=frame)
        frame += 1

    return dlnzdx, dlnzdy, dlnzdr, residualImage
Пример #24
0
    def setUp(self):
        width, height = 100, 300
        self.mi = afwImage.MaskedImageF(afwGeom.ExtentI(width, height))
        self.mi.set(0)
        self.mi.getVariance().set(10)
        self.mi.getMask().addMaskPlane("DETECTED")

        self.FWHM = 5
        self.ksize = 25  # size of desired kernel

        self.exposure = afwImage.makeExposure(self.mi)

        psf = roundTripPsf(
            2,
            algorithms.DoubleGaussianPsf(self.ksize, self.ksize,
                                         self.FWHM / (2 * sqrt(2 * log(2))), 1,
                                         0.1))
        self.exposure.setPsf(psf)

        for x, y in [
            (20, 20),
                #(30, 35), (50, 50),
            (60, 20),
            (60, 210),
            (20, 210)
        ]:

            flux = 10000 - 0 * x - 10 * y

            sigma = 3 + 0.01 * (y - self.mi.getHeight() / 2)
            psf = roundTripPsf(
                3,
                algorithms.DoubleGaussianPsf(self.ksize, self.ksize, sigma, 1,
                                             0.1))
            im = psf.computeImage().convertF()
            im *= flux
            smi = self.mi.getImage().Factory(
                self.mi.getImage(),
                afwGeom.BoxI(
                    afwGeom.PointI(x - self.ksize / 2, y - self.ksize / 2),
                    afwGeom.ExtentI(self.ksize)), afwImage.LOCAL)

            if False:  # Test subtraction with non-centered psfs
                im = afwMath.offsetImage(im, 0.5, 0.5)

            smi += im
            del psf
            del im
            del smi

        psf = roundTripPsf(
            4,
            algorithms.DoubleGaussianPsf(self.ksize, self.ksize,
                                         self.FWHM / (2 * sqrt(2 * log(2))), 1,
                                         0.1))

        self.cellSet = afwMath.SpatialCellSet(
            afwGeom.BoxI(afwGeom.PointI(0, 0), afwGeom.ExtentI(width, height)),
            100)
        ds = afwDetection.FootprintSet(self.mi, afwDetection.Threshold(10),
                                       "DETECTED")
        #
        # Prepare to measure
        #
        msConfig = algorithms.SourceMeasurementConfig()
        msConfig.load("tests/config/MeasureSources.py")
        schema = afwTable.SourceTable.makeMinimalSchema()
        measureSources = msConfig.makeMeasureSources(schema)
        catalog = afwTable.SourceCatalog(schema)
        msConfig.slots.calibFlux = None
        msConfig.slots.setupTable(catalog.table)
        ds.makeSources(catalog)
        for i, source in enumerate(catalog):
            measureSources.applyWithPeak(source, self.exposure)
            self.cellSet.insertCandidate(
                algorithms.makePsfCandidate(source, self.exposure))
Пример #25
0
def showPsfCandidates(exposure, psfCellSet, psf=None, frame=None, normalize=True, showBadCandidates=True,
                      fitBasisComponents=False, variance=None, chi=None):
    """Display the PSF candidates.

    If psf is provided include PSF model and residuals;  if normalize is true normalize the PSFs
    (and residuals)

    If chi is True, generate a plot of residuals/sqrt(variance), i.e. chi

    If fitBasisComponents is true, also find the best linear combination of the PSF's components
    (if they exist)
    """
    if chi is None:
        if variance is not None:        # old name for chi
            chi = variance
    #
    # Show us the ccandidates
    #
    mos = displayUtils.Mosaic()
    #
    candidateCenters = []
    candidateCentersBad = []
    candidateIndex = 0

    for cell in psfCellSet.getCellList():
        for cand in cell.begin(False): # include bad candidates
            rchi2 = cand.getChi2()
            if rchi2 > 1e100:
                rchi2 = numpy.nan

            if not showBadCandidates and cand.isBad():
                continue

            if psf:
                im_resid = displayUtils.Mosaic(gutter=0, background=-5, mode="x")

                try:
                    im = cand.getMaskedImage() # copy of this object's image
                    xc, yc = cand.getXCenter(), cand.getYCenter()

                    margin = 0 if True else 5
                    w, h = im.getDimensions()
                    bbox = afwGeom.BoxI(afwGeom.PointI(margin, margin), im.getDimensions())

                    if margin > 0:
                        bim = im.Factory(w + 2*margin, h + 2*margin)

                        stdev = numpy.sqrt(afwMath.makeStatistics(im.getVariance(), afwMath.MEAN).getValue())
                        afwMath.randomGaussianImage(bim.getImage(), afwMath.Random())
                        bim.getVariance().set(stdev**2)

                        bim.assign(im, bbox)
                        im = bim
                        xc += margin
                        yc += margin

                    im = im.Factory(im, True)
                    im.setXY0(cand.getMaskedImage().getXY0())
                except:
                    continue

                if not variance:
                    im_resid.append(im.Factory(im, True))

                if True:                # tweak up centroids
                    mi = im
                    psfIm = mi.getImage()
                    config = measBase.SingleFrameMeasurementTask.ConfigClass()
                    config.slots.centroid = "base_SdssCentroid"

                    schema = afwTable.SourceTable.makeMinimalSchema()
                    measureSources = measBase.SingleFrameMeasurementTask(schema, config=config)
                    catalog = afwTable.SourceCatalog(schema)

                    extra = 10          # enough margin to run the sdss centroider
                    miBig = mi.Factory(im.getWidth() + 2*extra, im.getHeight() + 2*extra)
                    miBig[extra:-extra, extra:-extra] = mi
                    miBig.setXY0(mi.getX0() - extra, mi.getY0() - extra)
                    mi = miBig
                    del miBig

                    exp = afwImage.makeExposure(mi)
                    exp.setPsf(psf)

                    footprintSet = afwDet.FootprintSet(mi,
                                                       afwDet.Threshold(0.5*numpy.max(psfIm.getArray())),
                                                       "DETECTED")
                    footprintSet.makeSources(catalog)

                    if len(catalog) == 0:
                        raise RuntimeError("Failed to detect any objects")

                    measureSources.run(catalog, exp)
                    if len(catalog) == 1:
                        source = catalog[0]
                    else:               # more than one source; find the once closest to (xc, yc)
                        dmin = None # an invalid value to catch logic errors
                        for i, s in enumerate(catalog):
                            d = numpy.hypot(xc - s.getX(), yc - s.getY())
                            if i == 0 or d < dmin:
                                source, dmin = s, d
                    xc, yc = source.getCentroid()

                # residuals using spatial model
                try:
                    subtractPsf(psf, im, xc, yc)
                except:
                    continue

                resid = im
                if variance:
                    resid = resid.getImage()
                    var = im.getVariance()
                    var = var.Factory(var, True)
                    numpy.sqrt(var.getArray(), var.getArray()) # inplace sqrt
                    resid /= var

                im_resid.append(resid)

                # Fit the PSF components directly to the data (i.e. ignoring the spatial model)
                if fitBasisComponents:
                    im = cand.getMaskedImage()

                    im = im.Factory(im, True)
                    im.setXY0(cand.getMaskedImage().getXY0())

                    try:
                        noSpatialKernel = psf.getKernel()
                    except:
                        noSpatialKernel = None

                    if noSpatialKernel:
                        candCenter = afwGeom.PointD(cand.getXCenter(), cand.getYCenter())
                        fit = fitKernelParamsToImage(noSpatialKernel, im, candCenter)
                        params = fit[0]
                        kernels = afwMath.KernelList(fit[1])
                        outputKernel = afwMath.LinearCombinationKernel(kernels, params)

                        outImage = afwImage.ImageD(outputKernel.getDimensions())
                        outputKernel.computeImage(outImage, False)

                        im -= outImage.convertF()
                        resid = im

                        if margin > 0:
                            bim = im.Factory(w + 2*margin, h + 2*margin)
                            afwMath.randomGaussianImage(bim.getImage(), afwMath.Random())
                            bim *= stdev

                            bim.assign(resid, bbox)
                            resid = bim

                        if variance:
                            resid = resid.getImage()
                            resid /= var

                        im_resid.append(resid)

                im = im_resid.makeMosaic()
            else:
                im = cand.getMaskedImage()

            if normalize:
                im /= afwMath.makeStatistics(im, afwMath.MAX).getValue()

            objId = splitId(cand.getSource().getId(), True)["objId"]
            if psf:
                lab = "%d chi^2 %.1f" % (objId, rchi2)
                ctype = ds9.RED if cand.isBad() else ds9.GREEN
            else:
                lab = "%d flux %8.3g" % (objId, cand.getSource().getPsfFlux())
                ctype = ds9.GREEN

            mos.append(im, lab, ctype)

            if False and numpy.isnan(rchi2):
                ds9.mtv(cand.getMaskedImage().getImage(), title="candidate", frame=1)
                print("amp", cand.getAmplitude())

            im = cand.getMaskedImage()
            center = (candidateIndex, xc - im.getX0(), yc - im.getY0())
            candidateIndex += 1
            if cand.isBad():
                candidateCentersBad.append(center)
            else:
                candidateCenters.append(center)

    if variance:
        title = "chi(Psf fit)"
    else:
        title = "Stars & residuals"
    mosaicImage = mos.makeMosaic(frame=frame, title=title)

    with ds9.Buffering():
        for centers, color in ((candidateCenters, ds9.GREEN), (candidateCentersBad, ds9.RED)):
            for cen in centers:
                bbox = mos.getBBox(cen[0])
                ds9.dot("+", cen[1] + bbox.getMinX(), cen[2] + bbox.getMinY(), frame=frame, ctype=color)

    return mosaicImage
Пример #26
0
 def testDetectorTime(self):
     """Test that we can ask a calib for the MidTime at a point in a detector (ticket #1337)"""
     p = afwGeom.PointI(3, 4)
     self.calib.getMidTime(self.detector, p)
Пример #27
0
    def setUp(self):
        width, height = 100, 300
        self.mi = afwImage.MaskedImageF(afwGeom.ExtentI(width, height))
        self.mi.set(0)
        self.mi.getVariance().set(10)
        self.mi.getMask().addMaskPlane("DETECTED")

        self.FWHM = 5
        self.ksize = 25  # size of desired kernel

        self.exposure = afwImage.makeExposure(self.mi)

        psf = roundTripPsf(
            2,
            algorithms.DoubleGaussianPsf(
                self.ksize, self.ksize,
                self.FWHM / (2 * math.sqrt(2 * math.log(2))), 1, 0.1))
        self.exposure.setPsf(psf)

        for x, y in [
            (20, 20),
                #(30, 35), (50, 50),
            (60, 20),
            (60, 210),
            (20, 210)
        ]:

            flux = 10000 - 0 * x - 10 * y

            sigma = 3 + 0.01 * (y - self.mi.getHeight() / 2)
            psf = roundTripPsf(
                3,
                algorithms.DoubleGaussianPsf(self.ksize, self.ksize, sigma, 1,
                                             0.1))
            im = psf.computeImage().convertF()
            im *= flux
            x0y0 = afwGeom.PointI(x - self.ksize // 2, y - self.ksize // 2)
            smi = self.mi.getImage().Factory(
                self.mi.getImage(),
                afwGeom.BoxI(x0y0, afwGeom.ExtentI(self.ksize)),
                afwImage.LOCAL)

            if False:  # Test subtraction with non-centered psfs
                im = afwMath.offsetImage(im, 0.5, 0.5)

            smi += im
            del psf
            del im
            del smi

        roundTripPsf(
            4,
            algorithms.DoubleGaussianPsf(
                self.ksize, self.ksize,
                self.FWHM / (2 * math.sqrt(2 * math.log(2))), 1, 0.1))

        self.cellSet = afwMath.SpatialCellSet(
            afwGeom.BoxI(afwGeom.PointI(0, 0), afwGeom.ExtentI(width, height)),
            100)
        ds = afwDetection.FootprintSet(self.mi, afwDetection.Threshold(10),
                                       "DETECTED")
        #
        # Prepare to measure
        #
        schema = afwTable.SourceTable.makeMinimalSchema()
        sfm_config = measBase.SingleFrameMeasurementConfig()
        sfm_config.plugins = [
            "base_SdssCentroid", "base_CircularApertureFlux", "base_PsfFlux",
            "base_SdssShape", "base_GaussianFlux", "base_PixelFlags"
        ]
        sfm_config.slots.centroid = "base_SdssCentroid"
        sfm_config.slots.shape = "base_SdssShape"
        sfm_config.slots.psfFlux = "base_PsfFlux"
        sfm_config.slots.instFlux = None
        sfm_config.slots.apFlux = "base_CircularApertureFlux_3_0"
        sfm_config.slots.modelFlux = "base_GaussianFlux"
        sfm_config.slots.calibFlux = None
        sfm_config.plugins["base_SdssShape"].maxShift = 10.0
        sfm_config.plugins["base_CircularApertureFlux"].radii = [3.0]
        task = measBase.SingleFrameMeasurementTask(schema, config=sfm_config)
        measCat = afwTable.SourceCatalog(schema)
        # detect the sources and run with the measurement task
        ds.makeSources(measCat)
        task.run(measCat, self.exposure)
        for source in measCat:
            self.cellSet.insertCandidate(
                algorithms.makePsfCandidate(source, self.exposure))
Пример #28
0
    def _fillVisitCatalog(self, butler, visitCat, srcVisits, srcCcds):
        """
        Fill the visit catalog with visit metadata

        Parameters
        ----------
        butler: `lsst.daf.persistence.Butler`
        visitCat: `afw.table.BaseCatalog`
           Catalog with schema from _createFgcmVisitSchema()
        srcVisits: `list'
           List of source visits
        srcCcds: `list`
           List of source CCDs
        """

        bbox = afwGeom.BoxI(afwGeom.PointI(0, 0), afwGeom.PointI(1, 1))

        # now loop over visits and get the information
        for i, srcVisit in enumerate(srcVisits):
            # We don't use the bypasses since we need the psf info which does
            # not have a bypass
            # TODO: When DM-15500 is implemented in the Gen3 Butler, this
            # can be fixed

            dataId = {
                self.config.visitDataRefName: srcVisit,
                self.config.ccdDataRefName: srcCcds[i]
            }

            exp = butler.get('calexp_sub',
                             dataId=dataId,
                             bbox=bbox,
                             flags=afwTable.SOURCE_IO_NO_FOOTPRINTS)
            visitInfo = exp.getInfo().getVisitInfo()
            f = exp.getFilter()
            psf = exp.getPsf()

            rec = visitCat.addNew()
            rec['visit'] = srcVisit
            rec['filtername'] = f.getName()
            radec = visitInfo.getBoresightRaDec()
            rec['telra'] = radec.getRa().asDegrees()
            rec['teldec'] = radec.getDec().asDegrees()
            rec['telha'] = visitInfo.getBoresightHourAngle().asDegrees()
            rec['mjd'] = visitInfo.getDate().get(system=DateTime.MJD)
            rec['exptime'] = visitInfo.getExposureTime()
            # convert from Pa to millibar
            # Note that I don't know if this unit will need to be per-camera config
            rec['pmb'] = visitInfo.getWeather().getAirPressure() / 100
            # Flag to signify if this is a "deep" field.  Not currently used
            rec['deepFlag'] = 0
            # Relative flat scaling (1.0 means no relative scaling)
            rec['scaling'][:] = 1.0
            # Median delta aperture, to be measured from stars
            rec['deltaAper'] = 0.0

            rec['psfSigma'] = psf.computeShape().getDeterminantRadius()

            if butler.datasetExists('calexpBackground', dataId=dataId):
                # Get background for reference CCD
                # This approximation is good enough for now
                bgStats = (
                    bg[0].getStatsImage().getImage().array
                    for bg in butler.get('calexpBackground', dataId=dataId))
                rec['skyBackground'] = sum(
                    np.median(bg[np.isfinite(bg)]) for bg in bgStats)
            else:
                rec['skyBackground'] = -1.0
    def setUp(self):
        config = SingleFrameMeasurementTask.ConfigClass()
        config.slots.apFlux = 'base_CircularApertureFlux_12_0'
        self.schema = afwTable.SourceTable.makeMinimalSchema()

        self.measureSources = SingleFrameMeasurementTask(self.schema,
                                                         config=config)

        width, height = 110, 301

        self.mi = afwImage.MaskedImageF(afwGeom.ExtentI(width, height))
        self.mi.set(0)
        sd = 3  # standard deviation of image
        self.mi.getVariance().set(sd * sd)
        self.mi.getMask().addMaskPlane("DETECTED")

        self.ksize = 31  # size of desired kernel

        sigma1 = 1.75
        sigma2 = 2 * sigma1

        self.exposure = afwImage.makeExposure(self.mi)
        self.exposure.setPsf(
            measAlg.DoubleGaussianPsf(self.ksize, self.ksize, 1.5 * sigma1, 1,
                                      0.1))
        cdMatrix = np.array([1.0, 0.0, 0.0, 1.0])
        cdMatrix.shape = (2, 2)
        wcs = afwGeom.makeSkyWcs(crpix=afwGeom.PointD(0, 0),
                                 crval=afwGeom.SpherePoint(
                                     0.0, 0.0, afwGeom.degrees),
                                 cdMatrix=cdMatrix)
        self.exposure.setWcs(wcs)

        #
        # Make a kernel with the exactly correct basis functions.  Useful for debugging
        #
        basisKernelList = []
        for sigma in (sigma1, sigma2):
            basisKernel = afwMath.AnalyticKernel(
                self.ksize, self.ksize,
                afwMath.GaussianFunction2D(sigma, sigma))
            basisImage = afwImage.ImageD(basisKernel.getDimensions())
            basisKernel.computeImage(basisImage, True)
            basisImage /= np.sum(basisImage.getArray())

            if sigma == sigma1:
                basisImage0 = basisImage
            else:
                basisImage -= basisImage0

            basisKernelList.append(afwMath.FixedKernel(basisImage))

        order = 1  # 1 => up to linear
        spFunc = afwMath.PolynomialFunction2D(order)

        exactKernel = afwMath.LinearCombinationKernel(basisKernelList, spFunc)
        exactKernel.setSpatialParameters([[1.0, 0, 0],
                                          [0.0, 0.5 * 1e-2, 0.2e-2]])

        rand = afwMath.Random()  # make these tests repeatable by setting seed

        addNoise = True

        if addNoise:
            im = self.mi.getImage()
            afwMath.randomGaussianImage(im, rand)  # N(0, 1)
            im *= sd  # N(0, sd^2)
            del im

        xarr, yarr = [], []

        for x, y in [
            (20, 20),
            (60, 20),
            (30, 35),
            (50, 50),
            (20, 90),
            (70, 160),
            (25, 265),
            (75, 275),
            (85, 30),
            (50, 120),
            (70, 80),
            (60, 210),
            (20, 210),
        ]:
            xarr.append(x)
            yarr.append(y)

        for x, y in zip(xarr, yarr):
            dx = rand.uniform() - 0.5  # random (centered) offsets
            dy = rand.uniform() - 0.5

            k = exactKernel.getSpatialFunction(1)(
                x, y)  # functional variation of Kernel ...
            b = (k * sigma1**2 / ((1 - k) * sigma2**2)
                 )  # ... converted double Gaussian's "b"

            #flux = 80000 - 20*x - 10*(y/float(height))**2
            flux = 80000 * (1 + 0.1 * (rand.uniform() - 0.5))
            I0 = flux * (1 + b) / (2 * np.pi * (sigma1**2 + b * sigma2**2))
            for iy in range(y - self.ksize // 2, y + self.ksize // 2 + 1):
                if iy < 0 or iy >= self.mi.getHeight():
                    continue

                for ix in range(x - self.ksize // 2, x + self.ksize // 2 + 1):
                    if ix < 0 or ix >= self.mi.getWidth():
                        continue

                    I = I0 * psfVal(ix, iy, x + dx, y + dy, sigma1, sigma2, b)
                    Isample = rand.poisson(I) if addNoise else I
                    self.mi.getImage().set(
                        ix, iy,
                        self.mi.getImage().get(ix, iy) + Isample)
                    self.mi.getVariance().set(
                        ix, iy,
                        self.mi.getVariance().get(ix, iy) + I)

        bbox = afwGeom.BoxI(afwGeom.PointI(0, 0),
                            afwGeom.ExtentI(width, height))
        self.cellSet = afwMath.SpatialCellSet(bbox, 100)

        self.footprintSet = afwDetection.FootprintSet(
            self.mi, afwDetection.Threshold(100), "DETECTED")

        self.catalog = self.measure(self.footprintSet, self.exposure)

        for source in self.catalog:
            try:
                cand = measAlg.makePsfCandidate(source, self.exposure)
                self.cellSet.insertCandidate(cand)

            except Exception as e:
                print(e)
                continue
Пример #30
0
    def runDataRef(self, expRefList, butler):
        """Make summary plots of full focalplane images.
        """
        if len(expRefList) == 0:
            return pipeBase.Struct(exitStatus=1)

        lsst.afw.fits.setAllowImageCompression(
            self.config.allowFitsCompression)

        dstype = expRefList[0].butlerSubset.datasetType

        if dstype == "raw":

            def callback(im, ccd, imageSource):
                return cgu.rawCallback(im,
                                       ccd,
                                       imageSource,
                                       correctGain=True,
                                       subtractBias=True)
        elif dstype == "eimage":
            callback = eimageCallback
        elif self.config.doApplySkyCorr:
            callback = skyCorrCallback
        else:
            callback = None

        for visit in set([er.dataId["visit"] for er in expRefList]):
            self.log.info("Processing visit %d", visit)
            expRefListForVisit = [
                er for er in expRefList if er.dataId["visit"] == visit
            ]

            dataId = expRefListForVisit[0].dataId
            bi = cgu.ButlerImage(butler,
                                 dstype,
                                 visit=visit,
                                 callback=callback,
                                 verbose=True)

            if self.config.doSensorImages:
                for dataId in (er.dataId for er in expRefListForVisit):
                    ccd = butler.get('calexp_detector', **dataId)
                    try:
                        md = butler.get('calexp_md', **dataId)
                    except RuntimeError:
                        md = None
                    if md:
                        afwGeom.makeSkyWcs(
                            md, strip=True
                        )  # strip WCS cards; they're invalidated by binning
                    try:
                        binned_im = bi.getCcdImage(
                            ccd,
                            binSize=self.config.sensorBinSize,
                            asMaskedImage=True)[0]
                        binned_im = rotateImageBy90(
                            binned_im,
                            ccd.getOrientation().getNQuarter())
                        if self.config.putFullSensors:
                            binned_exp = afwImage.ExposureF(binned_im)
                            binned_exp.setMetadata(md)
                            butler.put(binned_exp,
                                       'binned_sensor_fits',
                                       **dataId,
                                       dstype=dstype)
                    except (TypeError, RuntimeError) as e:
                        # butler couldn't put the image or there was no image to put
                        self.log.warn("Unable to make binned image: %s", e)
                        continue

                    (x, y) = binned_im.getDimensions()
                    boxes = {
                        'A':
                        afwGeom.Box2I(afwGeom.PointI(0, y / 2),
                                      afwGeom.ExtentI(x, y / 2)),
                        'B':
                        afwGeom.Box2I(afwGeom.PointI(0, 0),
                                      afwGeom.ExtentI(x, y / 2))
                    }
                    for half in ('A', 'B'):
                        box = boxes[half]
                        binned_exp = afwImage.ExposureF(binned_im[box])
                        binned_exp.setMetadata(md)
                        butler.put(binned_exp,
                                   'binned_sensor_fits_halves',
                                   half=half,
                                   **dataId,
                                   dstype=dstype)

            im = cgu.showCamera(butler.get('camera'),
                                imageSource=bi,
                                binSize=self.config.binSize)

            dstypeName = "%s-%s" % (
                dstype, self.config.fpId) if self.config.fpId else dstype

            butler.put(im, 'focal_plane_fits', visit=visit, dstype=dstypeName)

            # Compute the zscale stretch for just the CCDs that have data.
            detectorNameList = [
                "%s_%s" % (er.dataId["raftName"], er.dataId["detectorName"])
                for er in expRefListForVisit
            ]
            im_scaling = cgu.showCamera(butler.get('camera'),
                                        imageSource=bi,
                                        binSize=self.config.binSize,
                                        detectorNameList=detectorNameList)
            zmap = ZScaleMapping(im_scaling, contrast=self.config.contrast)

            im = flipImage(im, False, True)
            rgb = zmap.makeRgbImage(im, im, im)
            file_name = butler.get('focal_plane_png_filename',
                                   visit=visit,
                                   dstype=dstypeName)
            writeRGB(file_name[0], rgb)

        return pipeBase.Struct(exitStatus=0)