Beispiel #1
0
 def testAssemble(self):
     """Test the assembly of E2V and ITL sensors
     """
     task = AssembleCcdTask()
     # exclude LATISS for this test since we don't have an expected output
     for root, did, expected in zip(self.roots, self.ids, self.expecteds):
         butler = Butler(root)
         raw = butler.get("raw", dataId=did)
         assembled = task.assembleCcd(raw)
         count = numpy.sum(expected['expected'].read().array -
                           assembled.getImage().array)
         self.assertEqual(count, 0)
Beispiel #2
0
def assemble_raw(dataId, componentInfo, cls):
    """Called by the butler to construct the composite type "raw".

    Note that we still need to define "_raw" and copy various fields over.

    Parameters
    ----------
    dataId : `lsst.daf.persistence.dataId.DataId`
        the data ID
    componentInfo : `dict`
        dict containing the components, as defined by the composite definition in the mapper policy
    cls : 'object'
        unused

    Returns
    -------
    exposure : `lsst.afw.image.exposure.exposure`
        The assembled exposure
    """
    from lsst.ip.isr import AssembleCcdTask

    config = AssembleCcdTask.ConfigClass()
    config.doTrim = False

    assembleTask = AssembleCcdTask(config=config)

    ampExps = componentInfo['raw_amp'].obj
    if len(ampExps) == 0:
        raise RuntimeError("Unable to read raw_amps for %s" % dataId)

    ccd = ampExps[0].getDetector(
    )  # the same (full, CCD-level) Detector is attached to all ampExps

    ampDict = {}
    for amp, ampExp in zip(ccd, ampExps):
        ampDict[amp.getName()] = ampExp

    exposure = assembleTask.assembleCcd(ampDict)

    md = componentInfo['raw_hdu'].obj
    exposure.setMetadata(md)
    #
    # We need to standardize, but have no legal way to call std_raw.  The butler should do this for us.
    #
    ccm = ComCamMapper()
    exposure = ccm.std_raw(exposure, dataId)

    return exposure
def runAssembler():
    '''Run the task to assemble amps into a ccd'''

    #Create the assemble task with default config
    assembleConfig = AssembleCcdTask.ConfigClass()
    assembleTask = AssembleCcdTask(config=assembleConfig)
    frame = 0

    #The assemble task can operate in two ways:
    #1. On a dictionary of amp size images
    #2. On a single amp mosaic image
    #Both methods should produce the same output.
    for isPerAmp in (True, False):
        assemblyInput = exampleUtils.makeAssemblyInput(isPerAmp)
        assembledExposure = assembleTask.assembleCcd(assemblyInput)
        ds9.mtv(assembledExposure.getMaskedImage(), frame=frame, title="Per amp input is %s"%(isPerAmp))
        frame += 1
Beispiel #4
0
def AssembleImage(input_file, doGainCorrection = False, trim = True):
    import os
    
    imDict = {}
    afilelist = []
    dfilename = '%s[%s]' % (input_file, 0)
    
    for i in range(16):
        filename = '%s[%i]' % (input_file, i+1)
        md = afwImage.readMetadata(filename)
        afilelist.append(filename)
        imDict[md.get('EXTNAME')] = afwImage.ImageF(filename)
        
    db = TestCamDetectorBuilder(dfilename, afilelist, inAmpCoords=True, clobberMetadata=True)
    det = db.buildDetector()
    assembleInput = {}
    for amp in det:
        im = imDict[amp.getName()]
        oscanim = im.Factory(im, amp.getRawHorizontalOverscanBBox())
        oscan = numpy.median(oscanim.getArray())
        imArr = im.getArray()
        imArr -= oscan
        #Calculate and correct for gain
        if doGainCorrection:
            # Buffer so edge rolloff doesn't interfere
            buffImArr = imArr[30:-30][30:-30]
            medCounts = numpy.median(buffImArr)
            stdCounts = numpy.std(buffImArr)
            gain = medCounts/stdCounts**2
            imArr *= gain
        assembleInput[amp.getName()] = db.makeExposure(im)
    assembleConfig = AssembleCcdTask.ConfigClass()

    if trim:
        assembleConfig.doTrim = True
        assembler = AssembleCcdTask(config=assembleConfig)
        resultExp = assembler.assembleCcd(assembleInput)
#         camGeomUtils.showCcd(resultExp.getDetector(), imageSource(resultExp), frame=0)
        return resultExp

    else:
        assembleConfig.doTrim = False
        assembler = AssembleCcdTask(config=assembleConfig)
        resultExp = assembler.assembleCcd(assembleInput)
#         camGeomUtils.showCcd(resultExp.getDetector(), imageSource(resultExp), frame=1)
        return resultExp
Beispiel #5
0
def runAssembler():
    '''Run the task to assemble amps into a ccd'''

    # Create the assemble task with default config
    assembleConfig = AssembleCcdTask.ConfigClass()
    assembleTask = AssembleCcdTask(config=assembleConfig)
    frame = 0

    # The assemble task can operate in two ways:
    # 1. On a dictionary of amp size images
    # 2. On a single amp mosaic image
    # Both methods should produce the same output.
    for isPerAmp in (True, False):
        assemblyInput = exampleUtils.makeAssemblyInput(isPerAmp)
        assembledExposure = assembleTask.assembleCcd(assemblyInput)
        ds9.mtv(assembledExposure.getMaskedImage(),
                frame=frame,
                title="Per amp input is %s" % (isPerAmp))
        frame += 1
Beispiel #6
0
def assembleUntrimmedCcd(ccd, exposures):
    """Assemble an untrimmmed CCD from per-amp Exposure objects.

    Parameters
    ----------
    ccd : `~lsst.afw.cameraGeom.Detector`
        The detector geometry for this ccd that will be used as the
        framework for the assembly of the input amplifier exposures.
    exposures : sequence of `lsst.afw.image.Exposure`
        Per-amplifier images, in the same order as ``amps``.

    Returns
    -------
    ccd : `lsst.afw.image.Exposure`
        Assembled CCD image.
    """
    ampDict = {}
    for amp, exposure in zip(ccd, exposures):
        ampDict[amp.getName()] = exposure
    config = AssembleCcdTask.ConfigClass()
    config.doTrim = False
    assembleTask = AssembleCcdTask(config=config)
    return assembleTask.assembleCcd(ampDict)
Beispiel #7
0
def AssembleImage(input_file, doGainCorrection=False, trim=True):
    import os

    imDict = {}
    afilelist = []
    dfilename = '%s[%s]' % (input_file, 0)

    for i in range(16):
        filename = '%s[%i]' % (input_file, i + 1)
        md = afwImage.readMetadata(filename)
        afilelist.append(filename)
        imDict[md.get('EXTNAME')] = afwImage.ImageF(filename)

    db = TestCamDetectorBuilder(dfilename,
                                afilelist,
                                inAmpCoords=True,
                                clobberMetadata=True)
    det = db.buildDetector()
    assembleInput = {}
    for amp in det:
        im = imDict[amp.getName()]
        oscanim = im.Factory(im, amp.getRawHorizontalOverscanBBox())
        oscan = numpy.median(oscanim.getArray())
        imArr = im.getArray()
        imArr -= oscan
        #Calculate and correct for gain
        if doGainCorrection:
            # Buffer so edge rolloff doesn't interfere
            buffImArr = imArr[30:-30][30:-30]
            medCounts = numpy.median(buffImArr)
            stdCounts = numpy.std(buffImArr)
            gain = medCounts / stdCounts**2
            imArr *= gain
        assembleInput[amp.getName()] = db.makeExposure(im)
    assembleConfig = AssembleCcdTask.ConfigClass()

    if trim:
        assembleConfig.doTrim = True
        assembler = AssembleCcdTask(config=assembleConfig)
        resultExp = assembler.assembleCcd(assembleInput)
        #         camGeomUtils.showCcd(resultExp.getDetector(), imageSource(resultExp), frame=0)
        return resultExp

    else:
        assembleConfig.doTrim = False
        assembler = AssembleCcdTask(config=assembleConfig)
        resultExp = assembler.assembleCcd(assembleInput)
        #         camGeomUtils.showCcd(resultExp.getDetector(), imageSource(resultExp), frame=1)
        return resultExp
Beispiel #8
0
    def bypass_raw(self, datasetType, pythonType, location, dataId):
        """Magic method that is called automatically if it exists.
        """
        from lsst.ip.isr import AssembleCcdTask

        config = AssembleCcdTask.ConfigClass()
        config.doTrim = False

        assembleTask = AssembleCcdTask(config=config)
        logger = lsst.log.Log.getLogger("ZtfMapper")

        # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

        assert len(location.getLocations()
                   ) == 1  # KTL says that this is always true, but check
        relativeFileName = location.getLocations()[0]
        if location.storage.exists(relativeFileName):
            fileName = location.storage.locationWithRoot(relativeFileName)
            data = afwImage.ImageF(fileName, hdu=1)
            data = pythonType(afwImage.MaskedImageF(data))
        else:
            raise IOError(f"Unable to find {relativeFileName}")

        # Get the Detector
        detector = self.camera[self._extractDetectorName(dataId)]
        #
        # Read all the data
        #
        ampDict = {}
        for i, amp in enumerate(detector, 1):
            ampExp = pythonType(amp.getRawBBox())
            ampExp.setDetector(detector)
            ampDict[amp.getName()] = ampExp

            hdu = amp.get('hdu')
            if i == 1:
                assert i == hdu  # don't read twice
                data = data.image
            else:
                data = afwImage.ImageF(fileName, hdu=hdu)

            ampExp[amp.getRawDataBBox()].image = data

            bias = afwImage.ImageF(fileName, hdu=hdu + 4)
            ampExp[amp.getRawHorizontalOverscanBBox()].image = bias

        exposure = assembleTask.assembleCcd(ampDict)

        md = afwImage.readMetadata(fileName, hdu=0)
        fix_header(md, translator_class=self.translatorClass)
        exposure.setMetadata(md)

        visitInfo = ZtfMakeRawVisitInfo(logger)(md)
        exposure.getInfo().setVisitInfo(visitInfo)

        boresight = visitInfo.getBoresightRaDec()
        if boresight.isFinite():
            exposure.setWcs(
                getWcsFromDetector(exposure.getDetector(),
                                   boresight,
                                   180 * geom.degrees,
                                   flipX=True))
        else:
            logger.warn(
                f"Unable to set WCS for {dataId} from header as RA/Dec/Angle are unavailable"
            )

        return exposure
Beispiel #9
0
def assemble_raw(dataId, componentInfo, cls):
    """Called by the butler to construct the composite type "raw".

    Note that we still need to define "_raw" and copy various fields over.

    Parameters
    ----------
    dataId : `lsst.daf.persistence.dataId.DataId`
        The data ID.
    componentInfo : `dict`
        dict containing the components, as defined by the composite definition
        in the mapper policy.
    cls : 'object'
        Unused.

    Returns
    -------
    exposure : `lsst.afw.image.Exposure`
        The assembled exposure.
    """
    from lsst.ip.isr import AssembleCcdTask

    config = AssembleCcdTask.ConfigClass()
    config.doTrim = False

    assembleTask = AssembleCcdTask(config=config)

    ampExps = componentInfo['raw_amp'].obj
    if len(ampExps) == 0:
        raise RuntimeError("Unable to read raw_amps for %s" % dataId)

    ccd = ampExps[0].getDetector()      # the same (full, CCD-level) Detector is attached to all ampExps
    #
    # Check that the geometry in the metadata matches cameraGeom
    #
    logger = lsst.log.Log.getLogger("LsstCamMapper")
    warned = False
    for i, (amp, ampExp) in enumerate(zip(ccd, ampExps)):
        ampMd = ampExp.getMetadata().toDict()

        if amp.getRawBBox() != ampExp.getBBox():  # Oh dear. cameraGeom is wrong -- probably overscan
            if amp.getRawDataBBox().getDimensions() != amp.getBBox().getDimensions():
                raise RuntimeError("Active area is the wrong size: %s v. %s" %
                                   (amp.getRawDataBBox().getDimensions(), amp.getBBox().getDimensions()))
            if not warned:
                logger.warn("amp.getRawBBox() != data.getBBox(); patching. (%s v. %s)",
                            amp.getRawBBox(), ampExp.getBBox())
                warned = True

            w, h = ampExp.getBBox().getDimensions()
            ow, oh = amp.getRawBBox().getDimensions()  # "old" (cameraGeom) dimensions
            #
            # We could trust the BIASSEC keyword, or we can just assume that
            # they've changed the number of overscan pixels (serial and/or
            # parallel).  As Jim Chiang points out, the latter is safer
            #
            bbox = amp.getRawHorizontalOverscanBBox()
            hOverscanBBox = geom.BoxI(bbox.getBegin(),
                                      geom.ExtentI(w - bbox.getBeginX(), bbox.getHeight()))
            bbox = amp.getRawVerticalOverscanBBox()
            vOverscanBBox = geom.BoxI(bbox.getBegin(),
                                      geom.ExtentI(bbox.getWidth(), h - bbox.getBeginY()))

            amp.setRawBBox(ampExp.getBBox())
            amp.setRawHorizontalOverscanBBox(hOverscanBBox)
            amp.setRawVerticalOverscanBBox(vOverscanBBox)
            #
            # This gets all the geometry right for the amplifier, but the size
            # of the untrimmed image will be wrong and we'll put the amp
            # sections in the wrong places, i.e.
            #   amp.getRawXYOffset()
            # will be wrong.  So we need to recalculate the offsets.
            #
            xRawExtent, yRawExtent = amp.getRawBBox().getDimensions()

            x0, y0 = amp.getRawXYOffset()
            ix, iy = x0//ow, y0/oh
            x0, y0 = ix*xRawExtent, iy*yRawExtent
            amp.setRawXYOffset(geom.ExtentI(ix*xRawExtent, iy*yRawExtent))
        #
        # Check the "IRAF" keywords, but don't abort if they're wrong
        #
        # Only warn about the first amp, use debug for the others
        #
        detsec = bboxFromIraf(ampMd["DETSEC"]) if "DETSEC" in ampMd else None
        datasec = bboxFromIraf(ampMd["DATASEC"]) if "DATASEC" in ampMd else None
        biassec = bboxFromIraf(ampMd["BIASSEC"]) if "BIASSEC" in ampMd else None

        logCmd = logger.warn if i == 0 else logger.debug
        if detsec and amp.getBBox() != detsec:
            logCmd("DETSEC doesn't match for %s (%s != %s)", dataId, amp.getBBox(), detsec)
        if datasec and amp.getRawDataBBox() != datasec:
            logCmd("DATASEC doesn't match for %s (%s != %s)", dataId, amp.getRawDataBBox(), detsec)
        if biassec and amp.getRawHorizontalOverscanBBox() != biassec:
            logCmd("BIASSEC doesn't match for %s (%s != %s)",
                   dataId, amp.getRawHorizontalOverscanBBox(), detsec)

    ampDict = {}
    for amp, ampExp in zip(ccd, ampExps):
        ampDict[amp.getName()] = ampExp

    exposure = assembleTask.assembleCcd(ampDict)

    md = componentInfo['raw_hdu'].obj
    fix_header(md)  # No mapper so cannot specify the translator class
    exposure.setMetadata(md)
    visitInfo = LsstCamMakeRawVisitInfo(logger)(md)
    exposure.getInfo().setVisitInfo(visitInfo)

    boresight = visitInfo.getBoresightRaDec()
    rotangle = visitInfo.getBoresightRotAngle()

    if boresight.isFinite():
        exposure.setWcs(getWcsFromDetector(exposure.getDetector(), boresight,
                                           90*geom.degrees - rotangle))
    else:
        # Should only warn for science observations but VisitInfo does not know
        logger.warn("Unable to set WCS for %s from header as RA/Dec/Angle are unavailable" %
                    (dataId,))

    return exposure
Beispiel #10
0
    db = TestCamDetectorBuilder(dfilename, afilelist, inAmpCoords=True, clobberMetadata=True)
    det = db.buildDetector()
    assembleInput = {}
    for amp in det:
        im = imDict[amp.getName()]
        oscanim = im.Factory(im, amp.getRawHorizontalOverscanBBox())
        oscan = numpy.median(oscanim.getArray())
        imArr = im.getArray()
        imArr -= oscan
        #Calculate and correct for gain
        if args.doGainCorrection:
            # Buffer so edge rolloff doesn't interfere
            buffImArr = imArr[30:-30][30:-30]
            medCounts = numpy.median(buffImArr)
            stdCounts = numpy.std(buffImArr)
            gain = medCounts/stdCounts**2
            imArr *= gain
        assembleInput[amp.getName()] = db.makeExposure(im)
    assembleConfig = AssembleCcdTask.ConfigClass()

    if args.displayTrimmed:
        assembleConfig.doTrim = True
        assembler = AssembleCcdTask(config=assembleConfig)
        resultExp = assembler.assembleCcd(assembleInput)
        camGeomUtils.showCcd(resultExp.getDetector(), imageSource(resultExp), frame=0)

    if args.displayUnTrimmed:
        assembleConfig.doTrim = False
        assembler = AssembleCcdTask(config=assembleConfig)
        resultExp = assembler.assembleCcd(assembleInput)
        camGeomUtils.showCcd(resultExp.getDetector(), imageSource(resultExp), frame=1)
    assembleInput = {}
    for amp in det:
        im = imDict[amp.getName()]
        oscanim = im.Factory(im, amp.getRawHorizontalOverscanBBox())
        oscan = numpy.median(oscanim.getArray())
        imArr = im.getArray()
        imArr -= oscan
        #Calculate and correct for gain
        if args.doGainCorrection:
            # Buffer so edge rolloff doesn't interfere
            medCounts = numpy.median(imArr[30:-30][30:-30])
            stdCounts = numpy.std(imArr[30:-30][30:-30])
            gain = medCounts / stdCounts**2
            imArr *= gain
        assembleInput[amp.getName()] = db.makeExposure(im)
    assembleConfig = AssembleCcdTask.ConfigClass()

    if args.displayTrimmed:
        assembleConfig.doTrim = True
        assembler = AssembleCcdTask(config=assembleConfig)
        resultExp = assembler.assembleCcd(assembleInput)
        camGeomUtils.showCcd(resultExp.getDetector(),
                             imageSource(resultExp),
                             frame=0)

    if args.displayUnTrimmed:
        assembleConfig.doTrim = False
        assembler = AssembleCcdTask(config=assembleConfig)
        resultExp = assembler.assembleCcd(assembleInput)
        camGeomUtils.showCcd(resultExp.getDetector(),
                             imageSource(resultExp),