Exemplo n.º 1
0
def rotate(infile, outfile, angle, xcen=None, ycen=None):
    #  Open the FITS file using pyfits. A list of the HDUs in the FITS file is
    #  returned.
    hdu_list = pyfits.open(infile)

    #  Create an object that will transfer FITS header cards between an AST
    #  FitsChan and the PyFITS header describing the primary HDU of the
    #  supplied FITS file.
    adapter = Atl.PyFITSAdapter(hdu_list[0])

    #  Create a FitsChan and use the above adapter to copy all the header
    #  cards into it.
    fitschan = Ast.FitsChan(adapter, adapter)

    #  Get the flavour of FITS-WCS used by the header cards currently in the
    #  FitsChan. This is so that we can use the same flavour when we write
    #  out the modified WCS.
    encoding = fitschan.Encoding

    #  Read WCS information from the FitsChan. Additionally, this removes all
    #  WCS information from the FitsChan. The returned wcsinfo object
    #  is an AST FrameSet, in which the current Frame describes WCS coordinates
    #  and the base Frame describes pixel coodineates. The FrameSet includes a
    #  Mapping that specifies the transformation between the two Frames.
    wcsinfo = fitschan.read()

    #  Check that the FITS header contained WCS in a form that can be
    #  understood by AST.
    if wcsinfo == None:
        print("Failed to read WCS information from {0}".format(infile))

    #  Rotation is restricted to 2D arrays, so check the FITS file has 2 pixel
    #  axes (given by Nin) and 2 WCS axes (given by Nout).
    elif wcsinfo.Nin != 2 or wcsinfo.Nout != 2:
        print("{0} is not 2-dimensional".format(infile))

    #  Proceed if the WCS information was read OK.
    else:

        #  Get the lower and upper bounds of the input image in pixel indices.
        #  All FITS arrays by definition have lower pixel bounds of [1,1] (unlike
        #  NDFs). Note, unlike pyfits AST uses FITS ordering for storing pixel axis
        #  values in an array (i.e. NAXIS1 first, NAXIS2 second, etc).
        lbnd_in = [1, 1]
        ubnd_in = [fitschan["NAXIS1"], fitschan["NAXIS2"]]

        #  Get the rotation angle and convert from degrees to radians.
        angle = float(angle) * Ast.DD2R

        #  Construct a MatrixMap that rotates by the required angle, converted to radians.
        sinang = math.sin(angle)
        cosang = math.cos(angle)
        pixmap = Ast.MatrixMap([[cosang, sinang], [-sinang, cosang]])

        #  If supplied, get the centre of rotation.
        if (xcen is not None) and (ycen is not None):
            #  Create aShiftMap to shift the origin and combine it with the
            #  MatrixMap, to give the desired centre of rotation (shift,
            #  rotate, then shift back again).
            shiftmap = Ast.ShiftMap([-xcen, -ycen])
            pixmap = Ast.CmpMap(shiftmap, pixmap)
            shiftmap.invert()
            pixmap = Ast.CmpMap(pixmap, shiftmap)

            # The dimensions of the output array are the same as the input array.
            lbnd_out = lbnd_in
            ubnd_out = ubnd_in

        #  If no centre of rotation was specified, we use the MatrixMap
        #  unchanged, and determine the bounds of the smallest output image that
        #  will hold the entire rotated input image. These are with respect to
        #  the pixel coordinates of the input array, and so some corners may have
        #  negative pixel coordinates.
        else:
            (lb1, ub1, xl, xu) = pixmap.mapbox(lbnd_in, ubnd_in, 1)
            (lb2, ub2, xl, xu) = pixmap.mapbox(lbnd_in, ubnd_in, 2)
            lbnd_out = [int(lb1), int(lb2)]
            ubnd_out = [int(ub1), int(ub2)]

        #  Get the value used to represent missing pixel values
        if "BLANK" in fitschan:
            badval = fitschan["BLANK"]
            flags = Ast.USEBAD
        else:
            badval = 0
            flags = 0

        # Resample the data array using the above mapping.
        (npix, out, out_var) = pixmap.resample(lbnd_in, ubnd_in,
                                               hdu_list[0].data, None,
                                               Ast.LINEAR, None, flags, 0.05,
                                               1000, badval, lbnd_out,
                                               ubnd_out, lbnd_out, ubnd_out)

        #  Store the rotated data in the HDU, and update the NAXISi keywords
        #  to hold the number of pixels along each edge of the rotated image.
        hdu_list[0].data = out
        fitschan["NAXIS1"] = ubnd_out[0] - lbnd_out[0] + 1
        fitschan["NAXIS2"] = ubnd_out[1] - lbnd_out[1] + 1

        #  Move the pixel origin of the output from "lbnd_out" to (1,1). Create a
        #  suitable ShiftMap, and append it to the total "old pixel coord" to
        #  "new pixel coords" mapping.
        shiftmap = Ast.ShiftMap([-lbnd_out[0], -lbnd_out[1]])
        pixmap = Ast.CmpMap(pixmap, shiftmap)

        #  Re-map the base Frame (i.e. the pixel coordinates Frame) so that it
        #  refers to the new data grid instead of the old one.
        wcsinfo.remapframe(Ast.BASE, pixmap)

        #  Attempt to write the modified WCS information to the primary HDU (i.e.
        #  convert the FrameSet to a set of FITS header cards stored in the
        #  FITS file). Indicate that we want to use original flavour of FITS-WCS.
        fitschan.Encoding = encoding
        fitschan.clear('Card')
        if fitschan.write(wcsinfo) == 0:
            print("Failed to convert the rotated WCS to Fits-WCS")

        #  If successfull, force the FitsCHan to copy its contents into the
        #  PyFITS header, then write the changed data and header to the output
        #  FITS file.
        else:
            fitschan.writefits()
            hdu_list.writeto(outfile, clobber=True, output_verify='ignore')
Exemplo n.º 2
0
else:

   #  Get the lower and upper bounds of the input image in pixel indices.
   #  All FITS arrays by definition have lower pixel bounds of [1,1] (unlike
   #  NDFs). Note, unlike pyfits AST uses FITS ordering for storing pixel axis
   #  values in an array (i.e. NAXIS1 first, NAXIS2 second, etc).
   lbnd_in = [ 1, 1 ]
   ubnd_in = [ fitschan["NAXIS1"], fitschan["NAXIS2"] ]

   #  Get the rotation angle and convert from degrees to radians.
   angle = float( sys.argv[3] )*Ast.DD2R

   #  Construct a MatrixMap that rotates by the required angle, converted to radians.
   sinang = math.sin( angle )
   cosang = math.cos( angle )
   pixmap = Ast.MatrixMap( [ [cosang,sinang], [-sinang,cosang] ] )

   #  If supplied, get the centre of rotation.
   if len(sys.argv) > 5:
      x0 =  float( sys.argv[4] )
      y0 =  float( sys.argv[5] )

      #  Create aShiftMap to shift the origin and combine it with the
      #  MatrixMap, to give the desired centre of rotation (shift,
      #  rotate, then shift back again).
      shiftmap = Ast.ShiftMap( [ -x0, -y0 ] )
      pixmap = Ast.CmpMap( shiftmap, pixmap );
      shiftmap.invert()
      pixmap = Ast.CmpMap( pixmap, shiftmap );

      # The dimensions of the output array are the same as the input array.