示例#1
0
def makePixelToTanPixel(bbox, orientation, focalPlaneToPupil, pixelSizeMm):
    """!Make an XYTransform whose forward direction converts PIXEL to TAN_PIXEL for one detector

    PIXELS and TAN_PIXELS are defined in @ref afwCameraGeomCoordSys in doc/cameraGeom.dox

    @param[in] bbox  detector bounding box (an lsst.afw.geom.Box2I)
    @param[in] orientation  orientation of detector in focal plane (an lsst.afw.cameraGeom.Orientation)
    @param[in] focalPlaneToPupil  an lsst.afw.math.XYTransform that converts from focal plane (mm)
        to pupil coordinates (radians) in the forward direction
    @param[in] pixelSizeMm  size of the pixel in mm in X and Y (an lsst.afw.geom.Extent2D)
    """
    pixelToFocalPlane = orientation.makePixelFpTransform(pixelSizeMm)
    pixelToPupil = afwGeom.MultiXYTransform(
        (pixelToFocalPlane, focalPlaneToPupil))
    # pupilToTanPix is affine and matches pupilToPix at pupil center
    # Note: focal plane to pupil is typically a radial transform,
    # and linearizing the inverse transform of that may fail,
    # so linearize the forward direction instead. (pixelToPupil is pixelToFocalPlane,
    # an affine transform, followed by focalPlaneToPupil,
    # so the same consideration applies to pixelToPupil)
    pixAtPupilCtr = pixelToPupil.reverseTransform(afwGeom.Point2D(0, 0))
    tanPixToPupilAffine = pixelToPupil.linearizeForwardTransform(pixAtPupilCtr)
    pupilToTanPix = afwGeom.AffineXYTransform(tanPixToPupilAffine.invert())

    return afwGeom.MultiXYTransform((pixelToPupil, pupilToTanPix))
示例#2
0
    def testSimpleCurvedFocalPlane(self):
        """Test a trivial curved focal plane with square pixels

        The CCD's lower left pixel is centered on the boresight
        pupil center = focal plane center
        CCD x is along focal plane x
        """
        bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(1000, 1000))
        pixelSizeMm = afwGeom.Extent2D(0.02, 0.02)
        plateScale = 25.0   # arcsec/mm
        yaw = 0 * afwGeom.degrees
        fpPosition = afwGeom.Point2D(0, 0)  # focal-plane position of ref position on detector (mm)
        refPoint = afwGeom.Point2D(0, 0)  # ref position on detector (pos of lower left corner)
        orientation = cameraGeom.Orientation(
            fpPosition,
            refPoint,
            yaw,
        )
        pixelToFocalPlane = orientation.makePixelFpTransform(pixelSizeMm)
        plateScaleRad = afwGeom.Angle(plateScale, afwGeom.arcseconds).asRadians()
        focalPlaneToPupil = afwGeom.RadialXYTransform((0.0, plateScaleRad, 0.0, 0.001 * plateScaleRad))
        pixelToPupil = afwGeom.MultiXYTransform((pixelToFocalPlane, focalPlaneToPupil))

        pixelToTanPixel = makePixelToTanPixel(
            bbox=bbox,
            orientation=orientation,
            focalPlaneToPupil=focalPlaneToPupil,
            pixelSizeMm=pixelSizeMm,
        )

        # pupil center should be pixel position 0, 0 and tan pixel position 0, 0
        pixAtPupilCtr = pixelToPupil.reverseTransform(afwGeom.Point2D(0, 0))
        self.assertPairsNearlyEqual(pixAtPupilCtr, [0, 0])
        tanPixAtPupilCr = pixelToTanPixel.forwardTransform(pixAtPupilCtr)
        self.assertPairsNearlyEqual(tanPixAtPupilCr, [0, 0])

        # build same camera geometry transforms without optical distortion
        focalPlaneToPupilNoDistortion = afwGeom.RadialXYTransform((0.0, plateScaleRad))
        pixelToPupilNoDistortion = afwGeom.MultiXYTransform(
            (pixelToFocalPlane, focalPlaneToPupilNoDistortion))

        for x in (100, 200, 1000):
            for y in (100, 500, 800):
                pixPos = afwGeom.Point2D(x, y)
                tanPixPos = pixelToTanPixel.forwardTransform(pixPos)
                # pix to tan pix should be radial
                self.assertAlmostEqual(
                    math.atan2(pixPos[1], pixPos[0]),
                    math.atan2(tanPixPos[1], tanPixPos[0]),
                )

                # for a given pupil angle (which, together with a pointing, gives a position on the sky):
                # - pupil to pixels gives pixPos
                # - undistorted pupil to pixels gives tanPixPos
                pupilPos = pixelToPupil.forwardTransform(pixPos)
                desTanPixPos = pixelToPupilNoDistortion.reverseTransform(pupilPos)
                self.assertPairsNearlyEqual(desTanPixPos, tanPixPos)
示例#3
0
    def testCurvedFocalPlane(self):
        """Test a curved focal plane (with rectangular pixels)
        """
        bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                             afwGeom.Extent2I(1000, 1000))
        pixelSizeMm = afwGeom.Extent2D(0.02, 0.03)
        plateScale = 25.0  # arcsec/mm
        yaw = afwGeom.Angle(20, afwGeom.degrees)
        fpPosition = afwGeom.Point2D(
            50, 25)  # focal-plane position of ref position on detector (mm)
        refPoint = afwGeom.Point2D(
            -0.5, -0.5)  # ref position on detector (pos of lower left corner)
        orientation = cameraGeom.Orientation(
            fpPosition,
            refPoint,
            yaw,
        )
        plateScaleRad = afwGeom.Angle(plateScale,
                                      afwGeom.arcseconds).asRadians()
        focalPlaneToPupil = afwGeom.RadialXYTransform(
            (0.0, plateScaleRad, 0.0, 0.001 * plateScaleRad))

        pixelToTanPixel = makePixelToTanPixel(
            bbox=bbox,
            orientation=orientation,
            focalPlaneToPupil=focalPlaneToPupil,
            pixelSizeMm=pixelSizeMm,
            plateScale=plateScale,
        )

        # the center point of the detector should not move
        ctrPointPix = afwGeom.Box2D(bbox).getCenter()
        ctrPointTanPix = pixelToTanPixel.forwardTransform(ctrPointPix)
        for i in range(2):
            self.assertAlmostEquals(ctrPointTanPix[i], ctrPointPix[i])

        # two points separated by x pixels in tan pixels coordinates
        # should be separated x * rad/tanPix in pupil coordinates,
        # where rad/tanPix = plate scale in rad/MM * mean pixel size in mm
        radPerTanPixel = plateScaleRad * (pixelSizeMm[0] +
                                          pixelSizeMm[1]) / 2.0
        pixelToFocalPlane = orientation.makePixelFpTransform(pixelSizeMm)
        pixelToPupil = afwGeom.MultiXYTransform(
            (pixelToFocalPlane, focalPlaneToPupil))
        prevPointPupil = None
        prevPointTanPix = None
        for pointPix in (
                afwGeom.Point2D(0, 0),
                afwGeom.Point2D(1000, 2000),
                afwGeom.Point2D(-100.5, 27.23),
                afwGeom.Point2D(-95.3, 0.0),
        ):
            pointPupil = pixelToPupil.forwardTransform(pointPix)
            pointTanPix = pixelToTanPixel.forwardTransform(pointPix)
            if prevPointPupil:
                pupilSep = numpy.linalg.norm(pointPupil - prevPointPupil)
                tanPixSep = numpy.linalg.norm(pointTanPix - prevPointTanPix)
                self.assertAlmostEquals(tanPixSep * radPerTanPixel, pupilSep)
            prevPointPupil = pointPupil
            prevPointTanPix = pointTanPix
示例#4
0
    def testCurvedFocalPlane(self):
        """Test a curved focal plane (with rectangular pixels)
        """
        bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(1000, 1000))
        pixelSizeMm = afwGeom.Extent2D(0.02, 0.03)
        plateScale = 25.0   # arcsec/mm
        yaw = afwGeom.Angle(20, afwGeom.degrees)
        fpPosition = afwGeom.Point2D(50, 25)  # focal-plane position of ref position on detector (mm)
        refPoint = afwGeom.Point2D(-0.5, -0.5)  # ref position on detector (pos of lower left corner)
        orientation = cameraGeom.Orientation(
            fpPosition,
            refPoint,
            yaw,
        )
        pixelToFocalPlane = orientation.makePixelFpTransform(pixelSizeMm)
        plateScaleRad = afwGeom.Angle(plateScale, afwGeom.arcseconds).asRadians()
        focalPlaneToPupil = afwGeom.RadialXYTransform((0.0, plateScaleRad, 0.0, 0.001 * plateScaleRad))
        pixelToPupil = afwGeom.MultiXYTransform((pixelToFocalPlane, focalPlaneToPupil))

        pixelToTanPixel = makePixelToTanPixel(
            bbox=bbox,
            orientation=orientation,
            focalPlaneToPupil=focalPlaneToPupil,
            pixelSizeMm=pixelSizeMm,
        )

        # the center point of the pupil frame should not move
        pixAtPupilCtr = pixelToPupil.reverseTransform(afwGeom.Point2D(0, 0))
        tanPixAtPupilCr = pixelToTanPixel.forwardTransform(pixAtPupilCtr)
        self.assertPairsNearlyEqual(pixAtPupilCtr, tanPixAtPupilCr)

        # build same camera geometry transforms without optical distortion
        focalPlaneToPupilNoDistortion = afwGeom.RadialXYTransform((0.0, plateScaleRad))
        pixelToPupilNoDistortion = afwGeom.MultiXYTransform(
            (pixelToFocalPlane, focalPlaneToPupilNoDistortion))

        for x in (100, 200, 1000):
            for y in (100, 500, 800):
                pixPos = afwGeom.Point2D(x, y)
                tanPixPos = pixelToTanPixel.forwardTransform(pixPos)

                # for a given pupil position (which, together with a pointing, gives a position on the sky):
                # - pupil to pixels gives pixPos
                # - undistorted pupil to pixels gives tanPixPos
                pupilPos = pixelToPupil.forwardTransform(pixPos)
                desTanPixPos = pixelToPupilNoDistortion.reverseTransform(pupilPos)
                self.assertPairsNearlyEqual(desTanPixPos, tanPixPos)
示例#5
0
def makePixelToTanPixel(bbox, orientation, focalPlaneToPupil, pixelSizeMm,
                        plateScale):
    """!Make an XYTransform whose forward direction converts PIXEL to TAN_PIXEL for one detector

    PIXELS and TAN_PIXELS are defined in @ref afwCameraGeomCoordSys in doc/cameraGeom.dox

    @param[in] bbox  detector bounding box (an lsst.afw.geom.Box2I)
    @param[in] orientation  orientation of detector in focal plane (an lsst.afw.cameraGeom.Orientation)
    @param[in] focalPlaneToPupil  an lsst.afw.math.XYTransform that converts from focal plane (mm)
        to pupil coordinates (radians) in the forward direction
    @param[in] pixelSizeMm  size of the pixel in mm in X and Y (an lsst.afw.geom.Extent2D)
    @param[in] plateScale  plate scale of the camera in arcsec/mm (a double)
    """
    pixelToFocalPlane = orientation.makePixelFpTransform(pixelSizeMm)

    meanPixelSizeMm = (pixelSizeMm[0] + pixelSizeMm[1]) / 2.0
    radPerMeanPix = afwGeom.Angle(
        plateScale, afwGeom.arcseconds).asRadians() * meanPixelSizeMm

    detCtrPix = afwGeom.Box2D(bbox).getCenter()
    detCtrTanPix = detCtrPix  # by definition

    detCtrPupil = focalPlaneToPupil.forwardTransform(
        pixelToFocalPlane.forwardTransform(detCtrPix))

    pupilTanPixAngRad = -orientation.getYaw().asRadians()
    pupilTanPixSin = math.sin(pupilTanPixAngRad)
    pupilTanPixCos = math.cos(pupilTanPixAngRad)
    tanPixToPupilRotMat = numpy.array((
        (pupilTanPixCos, pupilTanPixSin),
        (-pupilTanPixSin, pupilTanPixCos),
    )) * radPerMeanPix
    tanPixToPupilRotTransform = afwGeom.AffineTransform(tanPixToPupilRotMat)

    tanPixCtrMinus0Pupil = tanPixToPupilRotTransform(detCtrTanPix)
    tanPix0Pupil = numpy.array(detCtrPupil) - numpy.array(tanPixCtrMinus0Pupil)

    tanPixToPupilAffine = afwGeom.AffineTransform(tanPixToPupilRotMat,
                                                  numpy.array(tanPix0Pupil))
    pupilToTanPix = afwGeom.AffineXYTransform(tanPixToPupilAffine.invert())
    return afwGeom.MultiXYTransform(
        (pixelToFocalPlane, focalPlaneToPupil, pupilToTanPix))