def perform_pixelscaleChecks(w1, w2, verbose=False, debugmode=False):
    # Check that the pixel scale in 2 directions on the image are similar, if not exit, as this script isn't coded for it (YOLO)
    pixel_size1 = utils.proj_plane_pixel_scales(w1)
    pixel_size2 = utils.proj_plane_pixel_scales(w2)
    if (pixel_size1[0] - pixel_size1[1]) / pixel_size1[0] > 0.01:
        sys.exit(
            f'ERROR  : input to determine_imageOverlap, {f1}, has pixels that are not very square, this code is not set up to deal with that YOLO'
        )
    if (pixel_size2[0] - pixel_size2[1]) / pixel_size2[0] > 0.01:
        sys.exit(
            f'ERROR  : input to determine_imageOverlap, {f2}, has pixels that are not very square, this code is not set up to deal with that YOLO'
        )

    # Check the pixel scale of two input images are similar, if not, throw a warning
    if abs(pixel_size1[0] - pixel_size2[0]) / pixel_size1[0] < 0.01:
        printme = f'The two image pixel scales are very similar, so this should not be an issue: {pixel_size1},{pixel_size2}'
        print_debug_string(printme, debugmode=debugmode)
    elif abs(pixel_size1[0] - pixel_size2[0]) / pixel_size1[0] < 0.1:
        printme = f'The two image pixel scales are within 10%, so this should not be an issue: {pixel_size1},{pixel_size2}'
        print_debug_string(printme, debugmode=debugmode)
    elif abs(pixel_size1[0] - pixel_size2[0]) / pixel_size1[0] < 2.0:
        printme = f'The two image pixel scales have a diff > 10% but smaller than a factor of 2, could be an issue: {pixel_size1},{pixel_size2}'
        print_debug_string(printme, debugmode=debugmode)
    else:
        sys.exit(
            'ERROR  : Input images to determine_imageOverlap differ in pixel scale by more than factor of 2, check if this is ok, if ok, then time to update determine_imageOverlap to allow this.'
        )

    # Print some extra information if in verbose mode
    printme = f'If SWarp is used with PIXELSCALE_TYPE default of MEDIAN, the output image pix scale is the median of pixel scales at centre of input images.'
    print_verbose_string(printme, verbose=verbose)
    return None
예제 #2
0
def test_pixscale_nodrop():
    mywcs = WCS(naxis=2)
    mywcs.wcs.cdelt = [0.1, 0.2]
    mywcs.wcs.ctype = ['RA---TAN', 'DEC--TAN']
    assert_almost_equal(proj_plane_pixel_scales(mywcs), (0.1, 0.2))

    mywcs.wcs.cdelt = [-0.1, 0.2]
    assert_almost_equal(proj_plane_pixel_scales(mywcs), (0.1, 0.2))
예제 #3
0
def test_pixscale_nodrop():
    mywcs = WCS(naxis=2)
    mywcs.wcs.cdelt = [0.1, 0.2]
    mywcs.wcs.ctype = ['RA---TAN', 'DEC--TAN']
    assert_almost_equal(proj_plane_pixel_scales(mywcs), (0.1, 0.2))

    mywcs.wcs.cdelt = [-0.1, 0.2]
    assert_almost_equal(proj_plane_pixel_scales(mywcs), (0.1, 0.2))
예제 #4
0
def test_pixscale_withdrop():
    mywcs = WCS(naxis=3)
    mywcs.wcs.cdelt = [0.1, 0.2, 1]
    mywcs.wcs.ctype = ['RA---TAN', 'DEC--TAN', 'VOPT']
    assert_almost_equal(proj_plane_pixel_scales(mywcs.celestial), (0.1, 0.2))

    mywcs.wcs.cdelt = [-0.1, 0.2, 1]
    assert_almost_equal(proj_plane_pixel_scales(mywcs.celestial), (0.1, 0.2))
예제 #5
0
def test_pixscale_withdrop():
    mywcs = WCS(naxis=3)
    mywcs.wcs.cdelt = [0.1, 0.2, 1]
    mywcs.wcs.ctype = ['RA---TAN', 'DEC--TAN', 'VOPT']
    assert_almost_equal(proj_plane_pixel_scales(mywcs.celestial), (0.1, 0.2))

    mywcs.wcs.cdelt = [-0.1, 0.2, 1]
    assert_almost_equal(proj_plane_pixel_scales(mywcs.celestial), (0.1, 0.2))
예제 #6
0
파일: core.py 프로젝트: vorugantia/gammapy
    def wcs_pixel_scale(self, method='cdelt'):
        """Pixel scale.

        Returns angles along each axis of the image pixel at the CRPIX
        location once it is projected onto the plane of intermediate world coordinates.

        Calls `~astropy.wcs.utils.proj_plane_pixel_scales`.

        Parameters
        ----------
        method : {'cdelt', 'proj_plane'} (default 'cdelt')
            Result is calculated according to the 'cdelt' or 'proj_plane' methods.

        Returns
        -------
        angle : `~astropy.coordinates.Angle`
            An angle of projection plane increments corresponding to each pixel side (axis).

        Examples
        --------
        >>> from gammapy.image import SkyImage
        >>> image = SkyImage.empty(nxpix=3, nypix=2)
        >>> image.wcs_pixel_scale()
        <Angle [ 0.02, 0.02] deg>
        """
        if method == 'cdelt':
            scales = np.abs(self.wcs.wcs.cdelt)
        elif method == 'proj_plane':
            scales = proj_plane_pixel_scales(wcs=self.wcs)
        else:
            raise ValueError('Invalid method: {}'.format(method))

        return Angle(scales, unit='deg')
예제 #7
0
def viewinwwt(filename, imageurl):
    fname = '{:s}.txt'.format(os.path.splitext(os.path.split(filename)[1])[0])
    outfile = os.path.join(public_folder, fname)
    header = fits.getheader(filename)
    reqd = {'imageurl': imageurl}
    try:
        reqd['x'] = header['CRPIX1']
        reqd['y'] = header['CRPIX2']
        ra_str = header['RA']
        dec_str = header['DEC']
        reqd['rotation'] = _calculate_rotation_angle('icrs', header)
    except:
        print('{:s} does not have the needed header keys'.format(filename))
        return
    coord = SkyCoord('{} {}'.format(ra_str, dec_str),
                     unit=(u.hourangle, u.deg))
    reqd['ra'] = coord.ra.value
    reqd['dec'] = coord.dec.value

    wcs = WCS(header)
    reqd['scale'] = proj_plane_pixel_scales(wcs)[0]
    reqd['name'] = os.path.split(filename)[0]

    request = 'name={name}&ra={ra}&dec={dec}&x={x}&y={y}&rotation={rotation}&imageurl={imageurl}'.format(
        **reqd)
    with open(outfile, 'w') as outp:
        outp.write('{0:s}{1:s}'.format(base_url, request))
    return
예제 #8
0
def imcopy(im, size=size, positions=positions):
    '''
	size=10
	position=(ra,dec), default (False,False)
	'''
    outname = os.path.splitext(im)[0] + '_' + str(size) + 'min_cut.fits'
    if os.path.isfile(outname): os.system('rm ' + outname)
    hdr = fits.getheader(im)
    w = WCS(hdr)
    xpscale, ypscale = wcsutils.proj_plane_pixel_scales(w) * 3600
    pixscale = (xpscale + ypscale) / 2.
    if positions == (False, False):
        print('RA or DEC input, False, position will be center of', im)
        px, py = hdr['NAXIS1'] / 2., hdr['NAXIS2'] / 2.
        ax, bx = px - size / 2 / pixscale * 60, px + size / 2 / pixscale * 60
        ay, by = py - size / 2 / pixscale * 60, py + size / 2 / pixscale * 60
    else:
        ra, dec = positions[0], positions[1]
        px, py = w.wcs_world2pix(ra, dec, 1)
        print('center pixel coordinates', int(px), int(py))
        ax, bx = px - size / 2 / pixscale * 60, px + size / 2 / pixscale * 60
        ay, by = py - size / 2 / pixscale * 60, py + size / 2 / pixscale * 60
    print('pixel scale =', '%.3f' % (pixscale), size,
          'arcmin rectangular cut =', int(bx - ax), 'pixels')
    region = '[' + str(int(ax)) + ':' + str(int(bx)) + ',' + str(
        int(ay)) + ':' + str(int(by)) + ']'
    print(outname, 'will be created')
    #region='[200:2048,60:2048]'
    chinim = im + region
    iraf.imcopy(chinim, output=outname)
    return 'Done'
예제 #9
0
    def _ang_size(self):
        if not hasattr(self, "_header"):
            raise AttributeError("No header has not been given.")

        pix_scale = np.abs(proj_plane_pixel_scales(self._wcs)[0])

        return pix_scale * u.Unit(self._wcs.wcs.cunit[1])
예제 #10
0
파일: ellipse.py 프로젝트: SKIRT/PTS
    def from_pixel(cls, region, wcs):

        """
        This function ...
        :param region:
        :param wcs:
        :return:
        """

        # Get center sky coordinate
        center = region.center.to_sky(wcs)

        ## GET THE PIXELSCALE
        result = utils.proj_plane_pixel_scales(wcs)
        # returns: A vector (ndarray) of projection plane increments corresponding to each pixel side (axis).
        # The units of the returned results are the same as the units of cdelt, crval, and cd for the celestial WCS
        # and can be obtained by inquiring the value of cunit property of the input WCS WCS object.
        x_pixelscale = result[0] * u("deg")
        y_pixelscale = result[1] * u("deg")
        # pixelscale = Extent(x_pixelscale, y_pixelscale)

        semimajor = region.semimajor * x_pixelscale
        semiminor = region.semiminor * y_pixelscale

        radius = SkyStretch(semimajor, semiminor)

        # Create a new SkyEllipse
        return cls(center, radius, region.angle, meta=region.meta)
예제 #11
0
    def _instantiate(self, hdul=None):
        if hdul is None:
            try:
                hdul = self.get_pyfits()
            except (AttributeError, IOError):
                return

        self.data = hdul[0].data
        self.header = hdul[0].header
        self.wcs = WCS(self.header)
        if self.wcs:
            cd1, cd2 = proj_plane_pixel_scales(self.wcs)
            cu1, cu2 = self.wcs.wcs.cunit
            cd1 = u.Quantity(cd1, unit=cu1)
            cd2 = u.Quantity(cd2, unit=cu2)
            try:
                self.pxscale = np.sqrt(cd1 * cd2).to(u.arcsec) / u.pix
            except Exception as e:
                print 'Error parsing wcs'
                print e, '\n'
                self.wcs = None
                self.pxscale = None
        else:
            self.pxscale = None

        self.tempdatafile = self.__generate_temp_file(data=hdul,
                                                      suffix='.fits',
                                                      ref=self.tempdatafile)
        self.tempphotfile = self.__generate_temp_file(suffix='.dat',
                                                      ref=self.tempphotfile)
        self.tempcoofile = self.__generate_temp_file(suffix='.coo',
                                                     ref=self.tempcoofile)
        self.tempradfile = self.__generate_temp_file(suffix='.prf',
                                                     ref=self.tempradfile)
예제 #12
0
    def to_pixel(self, wcs):

        """
        This function ...
        :param wcs:
        :return:
        """

        center = self.center.to_pixel(wcs)

        ## GET THE PIXELSCALE
        result = utils.proj_plane_pixel_scales(wcs)
        # returns: A vector (ndarray) of projection plane increments corresponding to each pixel side (axis).
        # The units of the returned results are the same as the units of cdelt, crval, and cd for the celestial WCS
        # and can be obtained by inquiring the value of cunit property of the input WCS WCS object.
        x_pixelscale = result[0] * Unit("deg/pix")
        y_pixelscale = result[1] * Unit("deg/pix")
        #pixelscale = Extent(x_pixelscale, y_pixelscale)

        major = (self.major / x_pixelscale).to("pix").value
        minor = (self.minor / y_pixelscale).to("pix").value

        radius = Extent(major, minor)

        # Create a new Ellipse and return it
        return Ellipse(center, radius, self.angle, meta=self.meta)
예제 #13
0
    def to_pixel(self, wcs):

        """
        This function ...
        :param wcs:
        :return:
        """

        center = self.center.to_pixel(wcs)

        ## GET THE PIXELSCALE
        result = utils.proj_plane_pixel_scales(wcs)
        # returns: A vector (ndarray) of projection plane increments corresponding to each pixel side (axis).
        # The units of the returned results are the same as the units of cdelt, crval, and cd for the celestial WCS
        # and can be obtained by inquiring the value of cunit property of the input WCS WCS object.
        x_pixelscale = result[0] * Unit("deg/pix")
        y_pixelscale = result[1] * Unit("deg/pix")
        #pixelscale = Extent(x_pixelscale, y_pixelscale)

        major = (self.major / x_pixelscale).to("pix").value
        minor = (self.minor / y_pixelscale).to("pix").value

        radius = Extent(major, minor)

        # Create a new Ellipse and return it
        return Ellipse(center, radius, self.angle, meta=self.meta)
예제 #14
0
    def from_pixel(cls, ellipse, wcs):

        """
        This function ...
        :param ellipse:
        :param wcs:
        :return:
        """

        center = SkyCoordinate.from_pixel(Coordinate(ellipse.center.x, ellipse.center.y), wcs)

        ## GET THE PIXELSCALE
        result = utils.proj_plane_pixel_scales(wcs)
        # returns: A vector (ndarray) of projection plane increments corresponding to each pixel side (axis).
        # The units of the returned results are the same as the units of cdelt, crval, and cd for the celestial WCS
        # and can be obtained by inquiring the value of cunit property of the input WCS WCS object.
        x_pixelscale = result[0] * Unit("deg/pix")
        y_pixelscale = result[1] * Unit("deg/pix")
        #pixelscale = Extent(x_pixelscale, y_pixelscale)

        major = ellipse.major * Unit("pix") * x_pixelscale
        minor = ellipse.minor * Unit("pix") * y_pixelscale

        radius = Extent(major, minor)

        # Create a new SkyEllipse
        return cls(center, radius, ellipse.angle, meta=ellipse.meta)
def viewinwwt(filename, imageurl):
    fname = '{:s}.txt'.format(os.path.splitext(os.path.split(filename)[1])[0])
    outfile = os.path.join(public_folder, fname)
    header = fits.getheader(filename)
    reqd = {'imageurl': imageurl}
    try:
        reqd['x'] = header['CRPIX1']
        reqd['y'] = header['CRPIX2']
        ra_str = header['RA']
        dec_str = header['DEC']
        reqd['rotation'] = _calculate_rotation_angle('icrs', header)
    except:
        print('{:s} does not have the needed header keys'.format(filename))
        return
    coord = SkyCoord('{} {}'.format(ra_str, dec_str), unit=(u.hourangle, u.deg))
    reqd['ra'] = coord.ra.value
    reqd['dec'] = coord.dec.value

    wcs = WCS(header)
    reqd['scale'] = proj_plane_pixel_scales(wcs)[0]
    reqd['name'] = os.path.split(filename)[0]

    request = 'name={name}&ra={ra}&dec={dec}&x={x}&y={y}&rotation={rotation}&imageurl={imageurl}'.format(**reqd)
    with open(outfile, 'w') as outp:
        outp.write('{0:s}{1:s}'.format(base_url, request))
    return
예제 #16
0
파일: core.py 프로젝트: cdeil/gammapy
    def wcs_pixel_scale(self, method='cdelt'):
        """Pixel scale.

        Returns angles along each axis of the image pixel at the CRPIX
        location once it is projected onto the plane of intermediate world coordinates.

        Calls `~astropy.wcs.utils.proj_plane_pixel_scales`.

        Parameters
        ----------
        method : {'cdelt', 'proj_plane'} (default 'cdelt')
            Result is calculated according to the 'cdelt' or 'proj_plane' methods.

        Returns
        -------
        angle : `~astropy.coordinates.Angle`
            An angle of projection plane increments corresponding to each pixel side (axis).

        Examples
        --------
        >>> from gammapy.image import SkyImage
        >>> image = SkyImage.empty(nxpix=3, nypix=2)
        >>> image.wcs_pixel_scale()
        <Angle [ 0.02, 0.02] deg>
        """
        if method == 'cdelt':
            scales = np.abs(self.wcs.wcs.cdelt)
        elif method == 'proj_plane':
            scales = proj_plane_pixel_scales(wcs=self.wcs)
        else:
            raise ValueError('Invalid method: {}'.format(method))

        return Angle(scales, unit='deg')
예제 #17
0
def photometry_custom(image_data, radpix, wcs):
    #aperture = CircularAperture((image_data.shape[0]/2,image_data.shape[0]/2), radpix[19])
    position = [image_data.shape[0] / 2, image_data.shape[0] / 2]
    apertures = [CircularAperture(position, r=r) for r in radpix]
    annulus_aperture = CircularAnnulus(position,
                                       r_in=radpix[19],
                                       r_out=radpix[19] + radpix[16])
    phot_table = aperture_photometry(image_data, apertures, wcs=wcs)

    annulus_masks = annulus_aperture.to_mask(method='center')
    annulus_data = annulus_masks.multiply(image_data)
    mask = annulus_masks.data
    annulus_data_1d = annulus_data[mask > 0]
    _, median_sigclip, _ = sigma_clipped_stats(annulus_data_1d)
    bkg_mean = median_sigclip

    #sky_aperture = to_sky(apertures,wcs)
    phot_array = np.zeros(20)
    bkg_sum_array = np.zeros(20)
    for i in range(0, 20):
        phot_array[i] = phot_table['aperture_sum_' + str(i)][0]
        bkg_sum_array[i] = bkg_mean * apertures[i].area

    final_sum = phot_array - bkg_sum_array

    scale = np.mean(proj_plane_pixel_scales(wcs))
    phot_Jy_custom = final_sum

    print('Backgorud outer radius =', radpix[19] + radpix[16], 'pixels')
    print(phot_table)
    return (phot_Jy_custom)
예제 #18
0
    def from_pixel(cls, ellipse, wcs):

        """
        This function ...
        :param ellipse:
        :param wcs:
        :return:
        """

        center = SkyCoordinate.from_pixel(Coordinate(ellipse.center.x, ellipse.center.y), wcs)

        ## GET THE PIXELSCALE
        result = utils.proj_plane_pixel_scales(wcs)
        # returns: A vector (ndarray) of projection plane increments corresponding to each pixel side (axis).
        # The units of the returned results are the same as the units of cdelt, crval, and cd for the celestial WCS
        # and can be obtained by inquiring the value of cunit property of the input WCS WCS object.
        x_pixelscale = result[0] * Unit("deg/pix")
        y_pixelscale = result[1] * Unit("deg/pix")
        #pixelscale = Extent(x_pixelscale, y_pixelscale)

        major = ellipse.major * Unit("pix") * x_pixelscale
        minor = ellipse.minor * Unit("pix") * y_pixelscale

        radius = Extent(major, minor)

        # Create a new SkyEllipse
        return cls(center, radius, ellipse.angle, meta=ellipse.meta)
예제 #19
0
def MakeRGB(df, p, xs, ys, r, g, b, w, bp, s, q):
	pixelscale = utils.proj_plane_pixel_scales(w)
	dx = int(0.5 * xs * ARCMIN_TO_DEG / pixelscale[0])		# pixelscale is in degrees (CUNIT)
	dy = int(0.5 * ys * ARCMIN_TO_DEG / pixelscale[1])
	
	image = mlrgb(r, g, b, minimum=bp, stretch=s, Q=q)
	
	image = Image.fromarray(image, mode='RGB')
	image = image.transpose(PIL.Image.FLIP_TOP_BOTTOM)
	
	if 'XSIZE' in df and not np.isnan(df['XSIZE'][p]):
		udx = int(0.5 * df['XSIZE'][p] * ARCMIN_TO_DEG / pixelscale[0])
	else:
		udx = dx
	if 'YSIZE' in df and not np.isnan(df['YSIZE'][p]):
		udy = int(0.5 * df['YSIZE'][p] * ARCMIN_TO_DEG / pixelscale[0])
	else:
		udy = dy
	
	if image.size != (2*udx, 2*udy):
		issmaller = True
	else:
		issmaller = False
	
	return image, issmaller
def _calculate_rotation_angle(reg_coordinate_frame, header):
    """Calculates the rotation angle from the region to the header's frame

    This attempts to be compatible with the implementation used by SAOImage
    DS9. In particular, this measures the rotation of the north axis as
    measured at the center of the image, and therefore requires a
    `~astropy.io.fits.Header` object with defined 'NAXIS1' and 'NAXIS2'
    keywords.

    Parameters
    ----------
    reg_coordinate_frame : str
        Coordinate frame used by the region file

    header : `~astropy.io.fits.Header` instance
        Header describing the image

    Returns
    -------
    y_axis_rot : float
        Degrees by which the north axis in the region's frame is rotated when
        transformed to pixel coordinates
    """
    new_wcs = WCS(header)
    region_frame = SkyCoord(
        '0d 0d',
        frame=reg_coordinate_frame,
        obstime='J2000')
    region_frame = SkyCoord(
        '0d 0d',
        frame=reg_coordinate_frame,
        obstime='J2000',
        equinox=region_frame.equinox)

    origin = SkyCoord.from_pixel(
        header['NAXIS1']/2,
        header['NAXIS2']/2,
        wcs=new_wcs,
        origin=1).transform_to(region_frame)

    offset = proj_plane_pixel_scales(new_wcs)[1]

    origin_x, origin_y = origin.to_pixel(new_wcs, origin=1)
    origin_lon = origin.data.lon.degree
    origin_lat = origin.data.lat.degree

    offset_point = SkyCoord(
        origin_lon, origin_lat+offset, unit='degree',
        frame=origin.frame.name, obstime='J2000')
    offset_x, offset_y = offset_point.to_pixel(new_wcs, origin=1)

    north_rot = np.arctan2(
        offset_y-origin_y,
        offset_x-origin_x) / np.pi*180.

    cdelt = new_wcs.wcs.get_cdelt()
    if (cdelt > 0).all() or (cdelt < 0).all():
        return north_rot - 90
    else:
        return -(north_rot - 90)
예제 #21
0
    def _ang_size(self):
        if not hasattr(self, "_header"):
            raise AttributeError("No header has not been given.")

        pix_scale = np.abs(proj_plane_pixel_scales(self._wcs)[0])

        return pix_scale * u.Unit(self._wcs.wcs.cunit[1])
예제 #22
0
def ds9_region(image_path, image, segm, wcs, ds9_region):
    """"Creates ds9 region file.

    This function creates a ds9 region file to display the sources
    detected by the segmentation function. This file is written to
    the same directory the fits files are in.

        Args:
            image_path(str, required):    Image path to particular FITs. File
            image(array, required):       This is the image data
            segm:                         The segmentation image
            wcs:                          World Coordinte System object
            ds9_region(boolean, opt):     If true, creates region file
            """
    if ds9_region is True:
        data_path = os.path.splitext(image_path)
        region_path = str(data_path[0]) + '_ds9region'
        scale = proj_plane_pixel_scales(wcs)
        image_scale = scale[0]
        reg = source_properties(image, segm, wcs=wcs)
        with open(region_path + '.reg', 'w') as f:
            f.write('# Region file format: DS9 version 7.6\n\n')
            f.write('global color=#ff7733\n')
            f.write('global width=2\n')
            f.write('fk5\n\n')
            for i in range(0, len(reg.id)):
                x = reg[i].sky_centroid_icrs.ra.to(u.deg)
                y = reg[i].sky_centroid_icrs.dec
                r = image_scale * reg[i].equivalent_radius
                f.write('circle(' + str(x.value) + ',' + str(y.value) + ',' +
                        str(r.value) + ')' + '   # Source Number:' +
                        str(reg[i].id) + '\n')
예제 #23
0
def get_postage_stamp(radecstr, size, image, image_wcs):
    """
    Extract a postage stamp image from a larger image

    Parameters
    ----------
    radecstr : str
        SkyCoord pareseable string for ra, dec coordinates

    size : 2 element tuple
        size in ra and dec in arcsec

    image : 2D numpy.ndarray
        image to cut postage stamps from

    image_wcs : astropy.wcs
        WCS for image
    """
    position = SkyCoord(radecstr)
    pix_scales = 3600. * proj_plane_pixel_scales(image_wcs)
    pix_size = (size[0] / pix_scales[0], size[1] / pix_scales[1])

    try:
        result = Cutout2D(image, position, pix_size, wcs=image_wcs)
    except:
        return None

    return result
예제 #24
0
    def __get_img_coordinates(self, header, fits_naxis1, fits_naxis2):
        """
        set the image attributes ra, dec, fov_bmin and fov_bmaj, radius
        from the image file header
        """
        wcs = WCS(header, naxis=2)
        pix_centre = [[header[fits_naxis1] / 2., header[fits_naxis2] / 2.]]
        self.ra, self.dec = wcs.wcs_pix2world(pix_centre, 1)[0]

        # The field-of-view (in pixels) is assumed to be a circle in the centre
        # of the image. This may be an ellipse on the sky, eg MOST images.
        # We leave a pixel margin at the edge that we don't use.
        # TODO: move unused pixel as argument
        unusedpix = 0.
        usable_radius_pix = self.__get_radius_pixels(header, fits_naxis1,
                                                     fits_naxis2) - unusedpix
        cdelt1, cdelt2 = proj_plane_pixel_scales(WCS(header).celestial)
        self.fov_bmin = usable_radius_pix * abs(cdelt1)
        self.fov_bmaj = usable_radius_pix * abs(cdelt2)
        self.physical_bmin = header[fits_naxis1] * abs(cdelt1)
        self.physical_bmaj = header[fits_naxis2] * abs(cdelt2)

        # set the pixels radius
        # TODO: check calcs
        self.radius_pixels = usable_radius_pix
예제 #25
0
def mask_galaxy(image, wcs, Ra, Dec, name, radius):
    """Masks galaxy at Ra, Dec within a radius given in arcminutes

    Creates a circular mask centered at a given Ra, Dec. The radius
    is given in arcmins. The wcs object is used to convert these inputs
    to pixel locations. A pixel scale is also determined. If the object
    name is suppled, SESAME is used to find object center. If no active
    internet connection is available, center location must be manually
    entered, in degrees. If no center coordinates are supplied, (0, 0)
    is the default center.

        Args:
            image(array, required):      Image data
            wcs:                         World Coordinte System object
            name(str, optional):         Name of galaxy or object
            Ra(str):                     Right Ascention
            Dec(str):                    Declination
            Radius(float, required):     Radius to be masked, in arcminutes

        Returns:
            masked_img(array):           Image which has been masked
            mask(boolean array):         Mask of the given object"""
    # Radius must be given in arcminutes
    # Dimentions of the image
    dim = (image.shape)
    y, x = dim[0], dim[1]

    # Finds the center of an object by inputting its name into SESAME
    # This requires an active internet connection
    # a, b are the coordinates of the center given in pixels

    try:
        center = SkyCoord.from_name(name)
    except Exception:
        print("No active internet connection. Manually enter Ra, Dec.")
        Ra = Ra
        Dec = Dec
        center = SkyCoord(Ra, Dec, unit="deg")

    c_pix = skycoord_to_pixel(center, wcs)
    a, b = c_pix[0], c_pix[1]
    print(center)

    radius = radius * u.arcmin

    # Finds pixel scale using WSC object. The default units can be found by
    # unit = header['CUNIT1'], they are degrees by convention
    # degrees are converted to arcmins and radius in computed in pixels
    scale = proj_plane_pixel_scales(wcs)
    pix_scale = scale[0] * u.deg.to(u.arcmin)
    print('Image Scale: ' + str(pix_scale) + ' arcmin/pix')

    rad_pix = (radius / pix_scale).value

    # Indexes each pixel and checks if its is >= radius from center
    Y, X = np.ogrid[:y, :x]
    dist_from_center = np.sqrt((X - a)**2 + (Y - b)**2)
    mask = dist_from_center <= rad_pix
    return mask
예제 #26
0
    def process_new_image_event(self, event: NewImageEvent, sender: str, *args,
                                **kwargs):
        """Puts a new images in the DB with the given ID.

        Args:
            event:  New image event
            sender: Who sent the event?

        Returns:
            Success
        """

        # filter by source
        if self._sources is not None and sender not in self._sources:
            return

        # put into queue
        log.info('Received new image event from %s.', sender)

        # download image
        try:

            log.info('Downloading file %s...', event.filename)
            image = self.vfs.read_image(event.filename)
        except FileNotFoundError:
            log.error('Could not download image.')
            return

        # get catalog
        cat = image.catalog
        if cat is None:
            # no catalog found in file
            return

        # filter by ellipticity
        cat = cat[cat['ellipticity'] < self._max_ellipticity]

        # get WCS and pixel size
        wcs = WCS(image.header)
        pix_size = abs(proj_plane_pixel_scales(wcs)[0] * 3600.)

        # calculate seeing
        seeing = np.mean(cat['fwhm']) * pix_size

        # correct for airmass?
        if self._correct_for_airmass:
            # Seeing S as function of seeing S0 at zenith and airmass a:
            # S = S0 * a^0.6
            # see https://www.astro.auth.gr/~seeing-gr/seeing_gr_files/theory/node17.html
            # need airmass
            if 'AIRMASS' in image.header:
                seeing /= image.header['AIRMASS']**0.6
            else:
                # could not correct
                return

        # log it
        if self._publisher is not None:
            self._publisher(time=Time.now().isot, seeing=seeing)
예제 #27
0
def test_pixscale_pc_rotated(angle):
    mywcs = WCS(naxis=2)
    rho = np.radians(angle)
    scale = 0.1
    mywcs.wcs.cdelt = [-scale, scale]
    mywcs.wcs.pc = [[np.cos(rho), -np.sin(rho)], [np.sin(rho), np.cos(rho)]]
    mywcs.wcs.ctype = ['RA---TAN', 'DEC--TAN']
    assert_almost_equal(proj_plane_pixel_scales(mywcs), (0.1, 0.1))
예제 #28
0
    def binsz_wcs(self):
        """Angular bin size of the underlying `~WcsGeom`

        Returns
        -------
        binsz_wcs: `~astropy.coordinates.Angle`
        """
        return Angle(proj_plane_pixel_scales(self.wcs), unit="deg")
예제 #29
0
def test_pixscale_cd_rotated(angle):
    mywcs = WCS(naxis=2)
    rho = np.radians(angle)
    scale = 0.1
    mywcs.wcs.cd = [[scale * np.cos(rho), -scale * np.sin(rho)],
                    [scale * np.sin(rho), scale * np.cos(rho)]]
    mywcs.wcs.ctype = ['RA---TAN', 'DEC--TAN']
    assert_almost_equal(proj_plane_pixel_scales(mywcs), (0.1, 0.1))
예제 #30
0
def MakeTiffCut(tiledir, outdir, positions, xs, ys, df, maketiff, makepngs):
	logger = logging.getLogger(__name__)
	os.makedirs(outdir, exist_ok=True)
	
	imgname = glob.glob(tiledir + '*.tiff')
	try:
		im = Image.open(imgname[0])
	#except IOError as e:
	except IndexError as e:
		print('No TIFF file found for tile ' + df['TILENAME'][0] + '. Will not create true-color cutout.')
		logger.error('MakeTiffCut - No TIFF file found for tile ' + df['TILENAME'][0] + '. Will not create true-color cutout.')
		return
	
	# try opening I band FITS (fallback on G, R bands)
	hdul = None
	for _i in ['i','g','r','z','Y']:
		tilename = glob.glob(tiledir+'*_{}.fits.fz'.format(_i))
		try:
			hdul = fits.open(tilename[0])
		except IOError as e:
			hdul = None
			logger.warning('MakeTiffCut - Could not find master FITS file: ' + tilename)
			continue
		else:
			break
	if not hdul:
		print('Cannot find a master fits file for this tile.')
		logger.error('MakeTiffCut - Cannot find a master fits file for this tile.')
		return
	
	w = WCS(hdul['SCI'].header)
	
	pixelscale = utils.proj_plane_pixel_scales(w)
	dx = int(0.5 * xs * ARCMIN_TO_DEG / pixelscale[0])		# pixelscale is in degrees (CUNIT)
	dy = int(0.5 * ys * ARCMIN_TO_DEG / pixelscale[1])
	
	pixcoords = utils.skycoord_to_pixel(positions, w, origin=0, mode='wcs')
	
	for i in range(len(positions)):
		if 'COADD_OBJECT_ID' in df:
			filenm = outdir + str(df['COADD_OBJECT_ID'][i])
		else:
			filenm = outdir + 'x{0}y{1}'.format(df['RA'][i], df['DEC'][i])
			#filenm = outdir + 'DESJ' + _DecConverter(df['RA'][0], df['DEC'][0])
		left = max(0, pixcoords[0][i] - dx)
		upper = max(0, im.size[1] - pixcoords[1][i] - dy)
		right = min(pixcoords[0][i] + dx, 10000)
		lower = min(im.size[1] - pixcoords[1][i] + dy, 10000)
		newimg = im.crop((left, upper, right, lower))
		
		if newimg.size != (2*dx, 2*dy):
			logger.info('MakeTiffCut - {} is smaller than user requested. This is likely because the object/coordinate was in close proximity to the edge of a tile.'.format(filenm.split('/')[-1]))
		
		if maketiff:
			newimg.save(filenm+'.tiff', format='TIFF')
		if makepngs:
			newimg.save(filenm+'.png', format='PNG')
	logger.info('MakeTiffCut - Tile {} complete.'.format(df['TILENAME'][0]))
예제 #31
0
def convert_to_imagecoord(shape, header):
    """Convert the coordlist of `shape` to image coordinates

    Parameters
    ----------
    shape : `pyregion.parser_helper.Shape`
        The `Shape` to convert coordinates

    header : `~astropy.io.fits.Header`
        Specifies what WCS transformations to use.

    Returns
    -------
    new_coordlist : list
        A list of image coordinates defining the shape.

    """
    arg_types = _generate_arg_types(len(shape.coord_list), shape.name)

    new_coordlist = []
    is_even_distance = True
    coord_list_iter = iter(zip(shape.coord_list, arg_types))

    new_wcs = WCS(header)
    pixel_scales = proj_plane_pixel_scales(new_wcs)

    for coordinate, coordinate_type in coord_list_iter:
        if coordinate_type == CoordOdd:
            even_coordinate = next(coord_list_iter)[0]

            old_coordinate = SkyCoord(coordinate, even_coordinate,
                                      frame=shape.coord_format, unit='degree',
                                      obstime='J2000')
            new_coordlist.extend(
                np.asscalar(x)
                for x in old_coordinate.to_pixel(new_wcs, origin=1)
            )

        elif coordinate_type == Distance:
            if arg_types[-1] == Angle:
                degree_per_pixel = pixel_scales[0 if is_even_distance else 1]

                is_even_distance = not is_even_distance
            else:
                degree_per_pixel = np.sqrt(proj_plane_pixel_area(new_wcs))

            new_coordlist.append(coordinate / degree_per_pixel)

        elif coordinate_type == Angle:
            new_angle = _estimate_angle(coordinate,
                                        shape.coord_format,
                                        header)
            new_coordlist.append(new_angle)

        else:
            new_coordlist.append(coordinate)

    return new_coordlist
예제 #32
0
def _calculate_rotation_angle(reg_coordinate_frame, header):
    """Calculates the rotation angle from the region to the header's frame

    This attempts to be compatible with the implementation used by SAOImage
    DS9. In particular, this measures the rotation of the north axis as
    measured at the center of the image, and therefore requires a
    `~astropy.io.fits.Header` object with defined 'NAXIS1' and 'NAXIS2'
    keywords.

    Parameters
    ----------
    reg_coordinate_frame : str
        Coordinate frame used by the region file

    header : `~astropy.io.fits.Header` instance
        Header describing the image

    Returns
    -------
    y_axis_rot : float
        Degrees by which the north axis in the region's frame is rotated when
        transformed to pixel coordinates
    """
    new_wcs = WCS(header)
    region_frame = SkyCoord('0d 0d',
                            frame=reg_coordinate_frame,
                            obstime='J2000')
    region_frame = SkyCoord('0d 0d',
                            frame=reg_coordinate_frame,
                            obstime='J2000',
                            equinox=region_frame.equinox)

    origin = SkyCoord.from_pixel(header['NAXIS1'] / 2,
                                 header['NAXIS2'] / 2,
                                 wcs=new_wcs,
                                 origin=1).transform_to(region_frame)

    offset = proj_plane_pixel_scales(new_wcs)[1]

    origin_x, origin_y = origin.to_pixel(new_wcs, origin=1)
    origin_lon = origin.data.lon.degree
    origin_lat = origin.data.lat.degree

    offset_point = SkyCoord(origin_lon,
                            origin_lat + offset,
                            unit='degree',
                            frame=origin.frame.name,
                            obstime='J2000')
    offset_x, offset_y = offset_point.to_pixel(new_wcs, origin=1)

    north_rot = np.arctan2(offset_y - origin_y,
                           offset_x - origin_x) / np.pi * 180.

    cdelt = new_wcs.wcs.get_cdelt()
    if (cdelt > 0).all() or (cdelt < 0).all():
        return north_rot - 90
    else:
        return -(north_rot - 90)
예제 #33
0
파일: paint.py 프로젝트: segasai/hips
 def draw_hips_order(self) -> int:
     """Compute HiPS tile order matching a given image pixel size."""
     # Sky image angular resolution (pixel size in degrees)
     resolution = np.min(proj_plane_pixel_scales(self.geometry.wcs))
     desired_order = hips_order_for_pixel_resolution(self.hips_survey.tile_width, resolution)
     # Return the desired order, or the highest resolution available.
     # Note that HiPS never has resolution less than 3,
     # and that limit is handled in _get_hips_order_for_resolution
     return np.min([desired_order, self.hips_survey.hips_order])
예제 #34
0
def convert_to_imagecoord(shape, header):
    """Convert the coordlist of `shape` to image coordinates

    Parameters
    ----------
    shape : `pyregion.parser_helper.Shape`
        The `Shape` to convert coordinates

    header : `~astropy.io.fits.Header`
        Specifies what WCS transformations to use.

    Returns
    -------
    new_coordlist : list
        A list of image coordinates defining the shape.

    """
    arg_types = _generate_arg_types(len(shape.coord_list), shape.name)

    new_coordlist = []
    is_even_distance = True
    coord_list_iter = iter(zip(shape.coord_list, arg_types))

    new_wcs = WCS(header)
    pixel_scales = proj_plane_pixel_scales(new_wcs)

    for coordinate, coordinate_type in coord_list_iter:
        if coordinate_type == CoordOdd:
            even_coordinate = next(coord_list_iter)[0]

            old_coordinate = SkyCoord(coordinate,
                                      even_coordinate,
                                      frame=shape.coord_format,
                                      unit='degree',
                                      obstime='J2000')
            new_coordlist.extend(
                np.asscalar(x)
                for x in old_coordinate.to_pixel(new_wcs, origin=1))

        elif coordinate_type == Distance:
            if arg_types[-1] == Angle:
                degree_per_pixel = pixel_scales[0 if is_even_distance else 1]

                is_even_distance = not is_even_distance
            else:
                degree_per_pixel = np.sqrt(proj_plane_pixel_area(new_wcs))

            new_coordlist.append(coordinate / degree_per_pixel)

        elif coordinate_type == Angle:
            new_angle = _estimate_angle(coordinate, shape.coord_format, header)
            new_coordlist.append(new_angle)

        else:
            new_coordlist.append(coordinate)

    return new_coordlist
예제 #35
0
 def get_pixscale(self, **kwargs_wcs):
     '''
     return pixel scale of input fits
         in unit of arcsec/pixel
     '''
     from astropy.wcs.utils import proj_plane_pixel_scales
     w=self.get_wcs(**kwargs_wcs)
     pixel_scales=proj_plane_pixel_scales(w)*3600 # arcsec/pixel
     return np.average(pixel_scales)
예제 #36
0
def pixel_to_angular(pixel_size, wcs):
    pixel_scales = proj_plane_pixel_scales(wcs)
    assert np.allclose(*pixel_scales)
    pixel_scale = pixel_scales[0] * wcs.wcs.cunit[0] / u.pix

    if not hasattr(pixel_size, 'unit'):
        pixel_size = pixel_size * u.pix

    angular_diameter = pixel_size * pixel_scale.to(u.arcsec / u.pix)
    return angular_diameter
예제 #37
0
def angular_to_pixel(angular_diameter, wcs):
    pixel_scales = proj_plane_pixel_scales(wcs)
    assert np.allclose(*pixel_scales)
    pixel_scale = pixel_scales[0] * wcs.wcs.cunit[0] / u.pix

    pixel_size = angular_diameter / pixel_scale.to(
        angular_diameter.unit / u.pix)
    pixel_size = pixel_size.value

    return pixel_size
예제 #38
0
def get_image_scale(wcs):
    """
    Return the image scale as a list of projection plane increments corresponding to each axis,
    calculated from the given FITS file WCS information.

    The units of the returned results are the same as the units of cdelt,
    crval, and cd for the celestial WCS and can be obtained by inquiring the
    value of cunit property of the input WCS object.
    """
    return list(proj_plane_pixel_scales(wcs))
예제 #39
0
    def __init__(self,
                 filename=None,
                 hdu=0,
                 unit=None,
                 zero_point=None,
                 pixel_scales=None,
                 wcs_rotation=None,
                 mask=None,
                 verbose=True):
        '''
        Parameters
        ----------
        filename (optional) : string
            FITS file name of the image.
        hdu : int (default: 0)
            The number of extension to load from the FITS file.
        unit (optional) : string
            Unit of the image flux for CCDData.
        zero_point (optional) : float
            Magnitude zero point.
        pixel_scales (optional) : tuple
            Pixel scales along the first and second directions, units: arcsec.
        wcs_rotation (optional) : float
            WCS rotation, east of north, units: radian.
        mask (optional) : 2D bool array
            The image mask.
        verbose : bool (default: True)
            Print out auxiliary data.
        '''
        if filename is None:
            self.data = None
        else:
            self.data = CCDData.read(filename, hdu=hdu, unit=unit, mask=mask)
            if self.data.wcs and (pixel_scales is None):
                pixel_scales = proj_plane_pixel_scales(
                    self.data.wcs) * u.degree.to('arcsec')

        self.zero_point = zero_point
        if pixel_scales is None:
            self.pixel_scales = None
        else:
            self.pixel_scales = (pixel_scales[0] * u.arcsec,
                                 pixel_scales[1] * u.arcsec)

        if self.data.wcs and (wcs_rotation is None):
            self.wcs_rotation = get_wcs_rotation(self.data.wcs)
        elif wcs_rotation is not None:
            self.wcs_rotation = wcs_rotation * u.radian
        else:
            self.wcs_rotation = None
        self.sources_catalog = None
        self.sigma_image = None
        self.sources_skycord = None
        self.ss_data = None
        self.PSF = None
예제 #40
0
 def pixel_scale(self):
     """The pixel scales of the detector in the X and Y image dimensions. """
     from astropy.wcs.utils import proj_plane_pixel_scales
     from astropy import units as u
     units = self.wcs.world_axis_units
     u1 = getattr(u, units[0])
     u2 = getattr(u, units[1])
     scales = proj_plane_pixel_scales(self.wcs)
     ps1 = (scales[0] * u1).to('arcsec').value
     ps2 = (scales[1] * u2).to('arcsec').value
     return np.asarray([ps1, ps2]) * u.arcsec
예제 #41
0
    def pixel_scales(self):
        """
        Pixel scale.

        Returns angles along each axis of the image at the CRPIX location once
        it is projected onto the plane of intermediate world coordinates.

        Returns
        -------
        angle: `~astropy.coordinates.Angle`
        """
        return Angle(proj_plane_pixel_scales(self.wcs), "deg")
예제 #42
0
파일: wcs.py 프로젝트: gammapy/gammapy
    def pixel_scales(self):
        """
        Pixel scale.

        Returns angles along each axis of the image at the CRPIX location once
        it is projected onto the plane of intermediate world coordinates.

        Returns
        -------
        angle: `~astropy.coordinates.Angle`
        """
        return Angle(proj_plane_pixel_scales(self.wcs), "deg")
예제 #43
0
파일: ellipse.py 프로젝트: SKIRT/PTS
    def from_sky(cls, region, wcs):

        """
        This function ...
        :param region:
        :param wcs:
        :return:
        """

        # Get center pixel coordinate
        center = region.center.to_pixel(wcs)

        ## GET THE PIXELSCALE
        result = utils.proj_plane_pixel_scales(wcs)
        # returns: A vector (ndarray) of projection plane increments corresponding to each pixel side (axis).
        # The units of the returned results are the same as the units of cdelt, crval, and cd for the celestial WCS
        # and can be obtained by inquiring the value of cunit property of the input WCS WCS object.
        x_pixelscale = result[0] * u("deg")
        y_pixelscale = result[1] * u("deg")
        # pixelscale = Extent(x_pixelscale, y_pixelscale)

        #print(region.semimajor)
        #print(region.semiminor)

        #print(x_pixelscale)
        #print(y_pixelscale)

        semimajor = (region.semimajor / x_pixelscale).to("").value
        semiminor = (region.semiminor / y_pixelscale).to("").value

        radius = PixelStretch(semimajor, semiminor)

        # Convert angle
        # Set the angle
        angle = region.angle
        if angle is not None:
            try: orientation = wcs.standard_orientation_angle
            except ValueError: orientation = wcs.orientation_angle
            # Add the orientation angle (w.r.t. standard E-W and S-N projection on the x and y axes) to the position angle
            # that is expressed in the standard way
            #return self.pa + orientation
            angle = angle + orientation
        else: angle = Angle(0.0, "deg")

        # Create a new PixelEllipse
        return cls(center, radius, angle, meta=region.meta, label=region.label, include=region.include, appearance=region.appearance)
예제 #44
0
    def pixelscale(self):

        """
        This function ...
        :return:
        """

        result = utils.proj_plane_pixel_scales(self)

        # returns: A vector (ndarray) of projection plane increments corresponding to each pixel side (axis).
        # The units of the returned results are the same as the units of cdelt, crval, and cd for the celestial WCS
        # and can be obtained by inquiring the value of cunit property of the input WCS WCS object.

        x_pixelscale = result[0] * Unit("deg/pix")
        y_pixelscale = result[1] * Unit("deg/pix")

        # Return the pixel scale as an extent
        return Pixelscale(x_pixelscale, y_pixelscale)
예제 #45
0
def linear_offset_coordinates(wcs, center):
    '''
    return a locally linear offset coordinate system

    does the simplest thing possible and assumes no projection distortions
    '''
    assert isinstance(center, coords.SkyCoord), \
        '`center` must by of type `SkyCoord`'
    assert center.isscalar, '`center` must have length 1'
    # Convert center to pixel coordinates
    xp, yp = skycoord_to_pixel(center, wcs)

    # Set up new WCS
    new_wcs = WCS(naxis=2)
    new_wcs.wcs.crpix = xp + 1, yp + 1
    new_wcs.wcs.crval = 0., 0.
    new_wcs.wcs.cdelt = proj_plane_pixel_scales(wcs)
    new_wcs.wcs.ctype = 'XOFFSET', 'YOFFSET'
    new_wcs.wcs.cunit = 'deg', 'deg'

    return new_wcs
예제 #46
0
def extract_image_metadata(header, title=None, image_url=None):
    """Return a dictionary of metadata pulled from a fits header."""
    try:
        wcs = WCS(header)
    except ValueError:
        raise ScrapeException('No WCS found in header')
    if not hasattr(wcs.wcs, 'cd'):
        raise ScrapeException('Insufficient WCS data in header')
    center = 0.5*(header['NAXIS1'] - 1), 0.5*(header['NAXIS2'] - 1)
    center_wcs = wcs.wcs_pix2world([center[0]], [center[1]], 0)
    corners_x = (0, 0, header['NAXIS1']-1, header['NAXIS1']-1)
    corners_y = (0, header['NAXIS2']-1, header['NAXIS2']-1, 0)
    corners_wcs = wcs.wcs_pix2world(corners_x, corners_y, 0)
    regionSTCS = 'Polygon ICRS'
    for wcs_x, wcs_y in zip(*corners_wcs):
        regionSTCS = regionSTCS + ' {} {}'.format(wcs_x, wcs_y)
    metadata = ImageMetadata(
        title=title,
        ra_center=center_wcs[0][0],
        dec_center=center_wcs[1][0],
        naxes=wcs.naxis,
        naxis='{} {}'.format(header['NAXIS1'], header['NAXIS2']),
        scale='{} {}'.format(*proj_plane_pixel_scales(wcs)),
        format='image/fits',
        image_url=image_url,
        crpix='{} {}'.format(*wcs.wcs.crpix),
        crval='{} {}'.format(*wcs.wcs.crval),
        cd_matrix='{} {} {} {}'.format(
            wcs.wcs.cd[0, 0], wcs.wcs.cd[0, 1],
            wcs.wcs.cd[1, 0], wcs.wcs.cd[1, 1]),
        reference_frame=wcs.wcs.radesys,
        regionSTCS=regionSTCS,
        )
    # metadata['inst'] = None # recommended
    # metadata['mjd_obs'] = None # recommended
    # metadata['equinox'] = wcs.wcs.equinox
    return metadata
예제 #47
0
파일: overlays.py 프로젝트: aplpy/aplpy
    def show(self, major='BMAJ', minor='BMIN', angle='BPA',
             corner='bottom left', frame=False, borderpad=0.4, pad=0.5,
             **kwargs):
        """
        Display the beam shape and size for the primary image.

        By default, this method will search for the BMAJ, BMIN, and BPA
        keywords in the FITS header to set the major and minor axes and the
        position angle on the sky.

        Parameters
        ----------

        major : float, quantity or unit, optional
            Major axis of the beam in degrees or an angular quantity (overrides
            BMAJ if present)

        minor : float, quantity or unit, optional
            Minor axis of the beam in degrees or an angular quantity (overrides
            BMIN if present)

        angle : float, quantity or unit, optional
            Position angle of the beam on the sky in degrees or an angular
            quantity (overrides BPA if present) in the anticlockwise direction.

        corner : int, optional
            The beam location. Acceptable values are 'left', 'right',
            'top', 'bottom', 'top left', 'top right', 'bottom left'
            (default), and 'bottom right'.

        frame : str, optional
            Whether to display a frame behind the beam (default is False)

        kwargs
            Additional arguments are passed to the matplotlib Ellipse class.
            See the matplotlib documentation for more details.
        """

        if isinstance(major, str):
            major = self._header[major]

        if isinstance(minor, str):
            minor = self._header[minor]

        if isinstance(angle, str):
            angle = self._header[angle]

        if isinstance(major, u.Quantity):
            major = major.to(u.degree).value
        elif isinstance(major, u.Unit):
            major = major.to(u.degree)

        if isinstance(minor, u.Quantity):
            minor = minor.to(u.degree).value
        elif isinstance(minor, u.Unit):
            minor = minor.to(u.degree)

        if isinstance(angle, u.Quantity):
            angle = angle.to(u.degree).value
        elif isinstance(angle, u.Unit):
            angle = angle.to(u.degree)

        if self._wcs.is_celestial:
            pix_scale = proj_plane_pixel_scales(self._wcs)
            sx = pix_scale[self._dimensions[0]]
            sy = pix_scale[self._dimensions[1]]
            degrees_per_pixel = np.sqrt(sx * sy)
        else:
            raise ValueError("Cannot show beam when WCS is not celestial")

        self._base_settings['minor'] = minor
        self._base_settings['major'] = major
        self._base_settings['angle'] = angle
        self._base_settings['corner'] = corner
        self._base_settings['frame'] = frame
        self._base_settings['borderpad'] = borderpad
        self._base_settings['pad'] = pad

        minor /= degrees_per_pixel
        major /= degrees_per_pixel

        try:
            self._beam.remove()
        except Exception:
            pass

        if isinstance(corner, str):
            corner = corners[corner]

        self._beam = AnchoredEllipse(self._ax.transData, width=minor,
                                     height=major, angle=angle, loc=corner,
                                     pad=pad, borderpad=borderpad,
                                     frameon=frame)

        self._ax.add_artist(self._beam)

        self.set(**kwargs)
예제 #48
0
파일: overlays.py 프로젝트: aplpy/aplpy
    def show(self, length, label=None, corner='bottom right', frame=False,
             borderpad=0.4, pad=0.5, **kwargs):
        """
        Overlay a scale bar on the image.

        Parameters
        ----------

        length : float, or quantity
            The length of the scalebar in degrees, an angular quantity, or angular unit

        label : str, optional
            Label to place below the scalebar

        corner : int, optional
            Where to place the scalebar. Acceptable values are:, 'left',
            'right', 'top', 'bottom', 'top left', 'top right', 'bottom
            left' (default), 'bottom right'

        frame : str, optional
            Whether to display a frame behind the scalebar (default is False)

        kwargs
            Additional arguments are passed to the matplotlib Rectangle and
            Text classes. See the matplotlib documentation for more details.
            In cases where the same argument exists for the two objects, the
            argument is passed to both the Text and Rectangle instance.
        """

        self._length = length
        self._base_settings['corner'] = corner
        self._base_settings['frame'] = frame
        self._base_settings['borderpad'] = borderpad
        self._base_settings['pad'] = pad

        if isinstance(length, u.Quantity):
            length = length.to(u.degree).value
        elif isinstance(length, u.Unit):
            length = length.to(u.degree)

        if self._wcs.is_celestial:
            pix_scale = proj_plane_pixel_scales(self._wcs)
            sx = pix_scale[self._dimensions[0]]
            sy = pix_scale[self._dimensions[1]]
            degrees_per_pixel = np.sqrt(sx * sy)
        else:
            raise ValueError("Cannot show scalebar when WCS is not celestial")

        length = length / degrees_per_pixel

        try:
            self._scalebar.remove()
        except Exception:
            pass

        if isinstance(corner, str):
            corner = corners[corner]

        self._scalebar = AnchoredSizeBar(self._ax.transData, length, label,
                                         corner, pad=pad, borderpad=borderpad,
                                         sep=5, frameon=frame)

        self._ax.add_artist(self._scalebar)

        self.set(**kwargs)
예제 #49
0
파일: main.py 프로젝트: vincepota/model2D
#listfiles = glob.glob('/Volumes/VINCE/dwarfs/combined_LSBVCC/*.fits*')
#listfiles = pd.read_csv('listfiles.csv').values.flatten()

for f in tqdm(listfiles):
	hdu = fits.open(f)                 # Load the multi-extension fits file

	for i in range(0,len(hdu)):		
		band = hdu[i].name

		if band == 'G':                # Look only for G-band observations

			header = hdu[i].header
			w = WCS(hdu[i].header)

			# Define class parameters
			pscale = str(utils.proj_plane_pixel_scales(w)[0] * 3600)[0:5]
			gain = str(header['GAIN'])
			seeing = str(header['FINALIQ'])
			sizeX = str(header['NAXIS2'])
			sizeY = str(header['NAXIS1'])
			saturate = str(header['SATURATE'])
	
			output = f.split('.fits')[0] + '_{}'.format(band)
			image = f + '[{}]'.format(i)

			# Inizialite the class
			c = model2D(image, output, gain, pscale, seeing, 
				        saturate, sizeX, sizeY, model2D.params, isofactor = 3.)
		
			# Create median subtracted image
			_ = c.get_median()
예제 #50
0
        (1 / cube.beam.sr.to(u.deg ** 2)) * \
        (cube.header["CDELT2"] * u.deg)**2

    if verbose:
        print("Total sum at native resolution.")
        print("Arecibo: {0}, VLA + Arecibo: {1}".format(ar.value, vla.value))
        # print("Combined VLA + Arecibo: {}".format(vla_combined.value))

    arec_sums[i] = ar.value
    vla_sums[i] = vla.value
    # vla_combined_sums[i] = vla_combined.value

    # Now convolve VLA to match Arecibo
    # This should match the previous sum

    pixscale = proj_plane_pixel_scales(arecibo.wcs)[0]
    beam_kern = arecibo.beam.as_kernel(pixscale)

    # conv_channel = convolve_fft(cube[i].value, beam_kern)

    # vla_conv = np.nansum(conv_channel) * \
    #     (1 / arecibo.beam.sr.to(u.deg ** 2)) * \
    #     (arecibo.header["CDELT2"] * u.deg)**2

    # if verbose:
    #     print("Total sum at common resolution.")
    #     print("Arecibo: {0}, VLA + Arecibo: {1}".format(ar.value, vla_conv.value))

    #     print("VLA + Arecibo should be scaled by:"
    #           " {}".format(vla_conv.value / ar.value))
예제 #51
0
파일: utils.py 프로젝트: n0d/astropy
    def __init__(self, data, position, size, wcs=None, mode='trim',
                 fill_value=np.nan, copy=False):
        """
        Parameters
        ----------
        data : `~numpy.ndarray`
            The 2D data array from which to extract the cutout array.

        position : tuple or `~astropy.coordinates.SkyCoord`
            The position of the cutout array's center with respect to
            the ``data`` array.  The position can be specified either as
            a ``(x, y)`` tuple of pixel coordinates or a
            `~astropy.coordinates.SkyCoord`, in which case ``wcs`` is a
            required input.

        size : int, array-like, `~astropy.units.Quantity`
            The size of the cutout array along each axis.  If ``size``
            is a scalar number or a scalar `~astropy.units.Quantity`,
            then a square cutout of ``size`` will be created.  If
            ``size`` has two elements, they should be in ``(ny, nx)``
            order.  Scalar numbers in ``size`` are assumed to be in
            units of pixels.  ``size`` can also be a
            `~astropy.units.Quantity` object or contain
            `~astropy.units.Quantity` objects.  Such
            `~astropy.units.Quantity` objects must be in pixel or
            angular units.  For all cases, ``size`` will be converted to
            an integer number of pixels, rounding the the nearest
            integer.  See the ``mode`` keyword for additional details on
            the final cutout size.

            .. note::
                If ``size`` is in angular units, the cutout size is
                converted to pixels using the pixel scales along each
                axis of the image at the ``CRPIX`` location.  Projection
                and other non-linear distortions are not taken into
                account.

        wcs : `~astropy.wcs.WCS`, optional
            A WCS object associated with the input ``data`` array.  If
            ``wcs`` is not `None`, then the returned cutout object will
            contain a copy of the updated WCS for the cutout data array.

        mode : {'trim', 'partial', 'strict'}, optional
            The mode used for creating the cutout data array.  For the
            ``'partial'`` and ``'trim'`` modes, a partial overlap of the
            cutout array and the input ``data`` array is sufficient.
            For the ``'strict'`` mode, the cutout array has to be fully
            contained within the ``data`` array, otherwise an
            `~astropy.nddata.utils.PartialOverlapError` is raised.   In
            all modes, non-overlapping arrays will raise a
            `~astropy.nddata.utils.NoOverlapError`.  In ``'partial'``
            mode, positions in the cutout array that do not overlap with
            the ``data`` array will be filled with ``fill_value``.  In
            ``'trim'`` mode only the overlapping elements are returned,
            thus the resulting cutout array may be smaller than the
            requested ``shape``.

        fill_value : number, optional
            If ``mode='partial'``, the value to fill pixels in the
            cutout array that do not overlap with the input ``data``.
            ``fill_value`` must have the same ``dtype`` as the input
            ``data`` array.

        copy : bool, optional
            If `False` (default), then the cutout data will be a view
            into the original ``data`` array.  If `True`, then the
            cutout data will hold a copy of the original ``data`` array.

        Returns
        -------
        result : `~astropy.nddata.utils.Cutout2D`
            A cutout object containing the 2D cutout data array and the
            updated WCS, if ``wcs`` is input.

        Examples
        --------
        >>> import numpy as np
        >>> from astropy.nddata.utils import Cutout2D
        >>> from astropy import units as u
        >>> data = np.arange(20.).reshape(5, 4)
        >>> cutout1 = Cutout2D(data, (2, 2), (3, 3))
        >>> print(cutout1.data)
        [[  5.   6.   7.]
         [  9.  10.  11.]
         [ 13.  14.  15.]]

        >>> print(cutout1.center_original)
        (2.0, 2.0)
        >>> print(cutout1.center_cutout)
        (1.0, 1.0)
        >>> print(cutout1.origin_original)
        (1, 1)

        >>> cutout2 = Cutout2D(data, (2, 2), 3)
        >>> print(cutout2.data)
        [[  5.   6.   7.]
         [  9.  10.  11.]
         [ 13.  14.  15.]]

        >>> size = u.Quantity([3, 3], u.pixel)
        >>> cutout3 = Cutout2D(data, (0, 0), size)
        >>> print(cutout3.data)
        [[ 0.  1.]
         [ 4.  5.]]

        >>> cutout4 = Cutout2D(data, (0, 0), (3 * u.pixel, 3))
        >>> print(cutout4.data)
        [[ 0.  1.]
         [ 4.  5.]]

        >>> cutout5 = Cutout2D(data, (0, 0), (3, 3), mode='partial')
        >>> print(cutout5.data)
        [[ nan  nan  nan]
         [ nan   0.   1.]
         [ nan   4.   5.]]
        """

        if isinstance(position, SkyCoord):
            if wcs is None:
                raise ValueError('wcs must be input if position is a '
                                 'SkyCoord')
            position = skycoord_to_pixel(position, wcs, mode='all')  # (x, y)

        if np.isscalar(size):
            size = np.repeat(size, 2)

        # special handling for a scalar Quantity
        if isinstance(size, u.Quantity):
            size = np.atleast_1d(size)
            if len(size) == 1:
                size = np.repeat(size, 2)

        if len(size) > 2:
            raise ValueError('size must have at most two elements')

        shape = np.zeros(2).astype(int)
        pixel_scales = None
        # ``size`` can have a mixture of int and Quantity (and even units),
        # so evaluate each axis separately
        for axis, side in enumerate(size):
            if not isinstance(side, u.Quantity):
                shape[axis] = np.int(np.round(size[axis]))     # pixels
            else:
                if side.unit == u.pixel:
                    shape[axis] = np.int(np.round(side.value))
                elif side.unit.physical_type == 'angle':
                    if wcs is None:
                        raise ValueError('wcs must be input if any element '
                                         'of size has angular units')
                    if pixel_scales is None:
                        pixel_scales = u.Quantity(
                            proj_plane_pixel_scales(wcs), wcs.wcs.cunit[axis])
                    shape[axis] = np.int(np.round(
                        (side / pixel_scales[axis]).decompose()))
                else:
                    raise ValueError('shape can contain Quantities with only '
                                     'pixel or angular units')

        data = np.asanyarray(data)
        # reverse position because extract_array and overlap_slices
        # use (y, x), but keep the input position
        pos_yx = position[::-1]

        cutout_data, input_position_cutout = extract_array(
            data, tuple(shape), pos_yx, mode=mode, fill_value=fill_value,
            return_position=True)
        if copy:
            cutout_data = np.copy(cutout_data)
        self.data = cutout_data

        self.input_position_cutout = input_position_cutout[::-1]    # (x, y)
        slices_original, slices_cutout = overlap_slices(
            data.shape, shape, pos_yx, mode=mode)

        self.slices_original = slices_original
        self.slices_cutout = slices_cutout

        self.shape = self.data.shape
        self.input_position_original = position
        self.shape_input = shape

        ((self.xmin_original, self.xmax_original),
         (self.ymin_original, self.ymax_original)) = self.bbox_original

        ((self.xmin_cutout, self.xmax_cutout),
         (self.ymin_cutout, self.ymax_cutout)) = self.bbox_cutout

        # the true origin pixel of the cutout array, including any
        # filled cutout values
        self._origin_original_true = (
            self.origin_original[0] - self.slices_cutout[1].start,
            self.origin_original[1] - self.slices_cutout[0].start)

        if wcs is not None:
            self.wcs = deepcopy(wcs)
            self.wcs.wcs.crpix -= self._origin_original_true
        else:
            self.wcs = None
예제 #52
0
    """
    Iterative m.a.d. based sigma with positive outlier rejection.
    """
    noise = mad_std(data, axis=axis)
    for _ in range(iterations):
        ind = (np.abs(data) <= thresh * noise).nonzero()
        noise = mad_std(data[ind], axis=axis)
    return noise


names = ['ic348', 'ngc1333', 'ophA']

for name in names:
    cube = SpectralCube.read('{}.13co.fits'.format(name))

    pixscale = proj_plane_pixel_scales(cube.wcs)[0]

    # cube = cube.with_mask(cube > 3 * scale * u.Jy)

    # # Want to smooth the mask edges
    mask = cube.mask.include()

    # Set smoothing parameters and # consecutive channels.
    smooth_chans = int(round_up_to_odd(200. / 66.))

    # 10 consecutive channels must be above the MAD level to be real emission.
    num_chans = 7

    peak_snr = 4.5
    # Cutoff level
    min_snr = 3
예제 #53
0
params["PA_err"] = float(contents[39].split()[-1])
params["eps"] = float(contents[40].split()[-3])
params["eps_err"] = float(contents[40].split()[-1])
params["inc"] = float(contents[41].split()[-3])
params["inc_err"] = float(contents[41].split()[-1])
# Both x and y are on the same line
params["xcent"] = float(contents[42].split()[-6])
params["xcent_err"] = float(contents[42].split()[-4][:-1])
params["ycent"] = float(contents[42].split()[-3])
params["ycent_err"] = float(contents[42].split()[-1])

# Now convert xcent and ycent to RA and Dec.
params["RAcent"], params["Deccent"] = \
    mywcs.celestial.wcs_pix2world(params["xcent"], params["ycent"], 0)
# Add angular uncertainties in deg.
pix_scale = proj_plane_pixel_scales(mywcs.celestial)
params["RAcent_err"] = pix_scale[0] * params["xcent_err"]
params["Deccent_err"] = pix_scale[1] * params["ycent_err"]

params["Vsys"] = float(contents[44].split()[-3])
params["Vsys_err"] = float(contents[44].split()[-1])

params["points_used"] = float(contents[56].split()[-1])
params["iterations"] = float(contents[57].split()[-1])
params["chi^2"] = float(contents[58].split()[-1])
params["DOF"] = float(contents[59].split()[-1])

# Column names are always on line 62, and data starts on 64
colnames = contents[62].split()

data = []
예제 #54
0
def make_cutouts(data, catalog, wcs=None, origin=0, verbose=True):
    """Make cutouts of catalog targets from a 2D image array.
    Expects input image WCS to be in the TAN projection.

    Parameters
    ----------
    data : 2D `~numpy.ndarray` or `~astropy.nddata.NDData`
        The 2D cutout array.
    catalog : `~astropy.table.table.Table`
        Catalog table defining the sources to cut out. Must contain
        unit information as the cutout tool does not assume default units.
    wcs : `~astropy.wcs.wcs.WCS`
        WCS if the input image is `~numpy.ndarray`.
    origin : int
        Whether SkyCoord.from_pixel should use 0 or 1-based pixel coordinates.
    verbose : bool
        Print extra info. Default is `True`.

    Returns
    -------
    cutouts : list
        A list of NDData. If cutout failed for a target,
       `None` will be added as a place holder. Output WCS
       will in be in Tan projection.

    Notes
    -----
    The input Catalog must have the following columns, which MUST have
    units information where applicable:

        * ``'id'`` - ID string; no unit necessary.
        * ``'coords'`` - SkyCoord (Overrides ra, dec, x and y columns).
        * ``'ra'`` or ``'x'``- RA (angular units e.g., deg, H:M:S, arcsec etc..)
          or pixel x position (only in `~astropy.units.pix`).
        * ``'dec'`` or ``'y'`` - Dec (angular units e.g., deg, D:M:S, arcsec etc..)
          or pixel y position (only in `~astropy.units.pix`).
        * ``'cutout_width'`` - Cutout width (e.g., in arcsec, pix).
        * ``'cutout_height'`` - Cutout height (e.g., in arcsec, pix).

    Optional columns:
        * ``'cutout_pa'`` - Cutout angle (e.g., in deg, arcsec). This is only
          use if user chooses to rotate the cutouts. Positive value
          will result in a clockwise rotation.

    If saved to fits, cutouts are organized as follows:
        <output_dir>/
            <id>.fits

    Each cutout image is a simple single-extension FITS with updated WCS.
    Its header has the following special keywords:

        * ``OBJ_RA`` - RA of the cutout object in degrees.
        * ``OBJ_DEC`` - DEC of the cutout object in degrees.
        * ``OBJ_ROT`` - Rotation of cutout object in degrees.

    """
    # Do not rotate if column is missing.
    if 'cutout_pa' in catalog.colnames:
        if catalog['cutout_pa'].unit is None:
            raise u.UnitsError("Units not specified for cutout_pa.")
        apply_rotation = True
    else:
        apply_rotation = False

    # Optional dependencies...
    if apply_rotation:
        try:
            from reproject.interpolation.high_level import reproject_interp
        except ImportError as e:
            raise ImportError("Optional requirement not met: " + e.msg)

    # Search for wcs:
    if isinstance(data, NDData):
            if wcs is not None:
                raise Exception("Ambiguous: WCS defined in NDData and parameters.")
            wcs = data.wcs
    elif not isinstance(data, np.ndarray):
        raise TypeError("Input image should be a 2D `~numpy.ndarray` "
                        "or `~astropy.nddata.NDData")
    elif wcs is None:
        raise Exception("WCS information was not provided.")

    if wcs.wcs.ctype[0] != 'RA---TAN' or  wcs.wcs.ctype[1] != 'DEC--TAN':
        raise Exception("Expected  WCS to be in the TAN projection.")

    # Calculate the pixel scale of input image:
    pixel_scales = proj_plane_pixel_scales(wcs)
    pixel_scale_width = pixel_scales[0] * u.Unit(wcs.wcs.cunit[0]) / u.pix
    pixel_scale_height = pixel_scales[1] * u.Unit(wcs.wcs.cunit[1]) / u.pix

    # Check if `SkyCoord`s are available:
    if 'coords' in catalog.colnames:
        coords = catalog['coords']
        if not isinstance(coords, SkyCoord):
            raise TypeError('The coords column is not a SkyCoord')
    elif 'ra' in catalog.colnames and 'dec' in catalog.colnames:
        if 'x' in catalog.colnames and 'y' in catalog.colnames:
            raise Exception("Ambiguous catalog: Both (ra, dec) and pixel positions provided.")
        if catalog['ra'].unit is None or catalog['dec'].unit is None:
            raise u.UnitsError("Units not specified for ra and/or dec columns.")
        coords = SkyCoord(catalog['ra'], catalog['dec'], unit=(catalog['ra'].unit,
                                                               catalog['dec'].unit))
    elif 'x' in catalog.colnames and 'y' in catalog.colnames:
        coords = SkyCoord.from_pixel(catalog['x'].astype(float), catalog['y'].astype(float), wcs, origin=origin)
    else:
        try:
            coords = SkyCoord.guess_from_table(catalog)
        except Exception as e:
            raise e

    coords = coords.transform_to(wcs_to_celestial_frame(wcs))

    # Figure out cutout size:
    if 'cutout_width' in catalog.colnames:
        if catalog['cutout_width'].unit is None:
            raise u.UnitsError("Units not specified for cutout_width.")
        if catalog['cutout_width'].unit == u.pix:
            width = catalog['cutout_width'].astype(float)  # pix
        else:
            width = (catalog['cutout_width'] / pixel_scale_width).decompose().value  # pix
    else:
        raise Exception("cutout_width column not found in catalog.")

    if 'cutout_height' in catalog.colnames:
        if catalog['cutout_height'].unit is None:
            raise u.UnitsError("Units not specified for cutout_height.")
        if catalog['cutout_height'].unit == u.pix:
            height = catalog['cutout_height'].astype(float)  # pix
        else:
            height = (catalog['cutout_height'] / pixel_scale_height).decompose().value  # pix
    else:
        raise Exception("cutout_height column not found in catalog.")

    cutcls = partial(Cutout2D, data.data, wcs=wcs, mode='partial')
    cutouts = []
    for position, x_pix, y_pix, row in zip(coords, width, height, catalog):

        if apply_rotation:
            pix_rot = row['cutout_pa'].to(u.degree).value

            # Construct new rotated WCS:
            cutout_wcs = WCS(naxis=2)
            cutout_wcs.wcs.ctype = ['RA---TAN', 'DEC--TAN']
            cutout_wcs.wcs.crval = [position.ra.deg, position.dec.deg]
            cutout_wcs.wcs.crpix = [(x_pix + 1) * 0.5, (y_pix + 1) * 0.5]

            try:
                cutout_wcs.wcs.cd = wcs.wcs.cd
                cutout_wcs.rotateCD(-pix_rot)
            except AttributeError:
                cutout_wcs.wcs.cdelt = wcs.wcs.cdelt
                cutout_wcs.wcs.crota = [0, -pix_rot]

            cutout_hdr = cutout_wcs.to_header()

            # Rotate the image using reproject
            try:
                cutout_arr = reproject_interp(
                    (data, wcs), cutout_hdr, shape_out=(math.floor(y_pix + math.copysign(0.5, y_pix)),
                                                        math.floor(x_pix + math.copysign(0.5, x_pix))), order=1)
            except Exception:
                if verbose:
                    log.info('reproject failed: '
                             'Skipping {0}'.format(row['id']))
                cutouts.append(None)
                continue

            cutout_arr = cutout_arr[0]  # Ignore footprint
            cutout_hdr['OBJ_ROT'] = (pix_rot, 'Cutout rotation in degrees')
        else:
            # Make cutout or handle exceptions by adding None to output list
            try:
                cutout = cutcls(position, size=(y_pix, x_pix))
            except NoConvergence:
                if verbose:
                    log.info('WCS solution did not converge: '
                             'Skipping {0}'.format(row['id']))
                cutouts.append(None)
                continue
            except NoOverlapError:
                if verbose:
                    log.info('Cutout is not on image: '
                             'Skipping {0}'.format(row['id']))
                cutouts.append(None)
                continue
            else:
                cutout_hdr = cutout.wcs.to_header()
                cutout_arr = cutout.data

        # If cutout result is empty, skip that target
        if np.array_equiv(cutout_arr, 0):
            if verbose:
                log.info('No data in cutout: Skipping {0}'.format(row['id']))
            cutouts.append(None)
            continue

        # Finish constructing header.
        cutout_hdr['OBJ_RA'] = (position.ra.deg, 'Cutout object RA in deg')
        cutout_hdr['OBJ_DEC'] = (position.dec.deg, 'Cutout object DEC in deg')

        cutouts.append(NDData(data=cutout_arr, wcs=WCS(cutout_hdr), meta=cutout_hdr))

    return cutouts
예제 #55
0
def test_pixscale_cd():
    mywcs = WCS(naxis=2)
    mywcs.wcs.cd = [[-0.1, 0], [0, 0.2]]
    mywcs.wcs.ctype = ['RA---TAN', 'DEC--TAN']
    assert_almost_equal(proj_plane_pixel_scales(mywcs), (0.1, 0.2))
예제 #56
0

            TMASSfile = os.path.join(TMASSdir, '_'.join([thisTarget, thisWaveband]) + '.fits')
            TMASSimg  = AstroImage(TMASSfile)

            PSFproperties  = TMASSimg.get_PSF()
            TMASS_PSFwidth = np.sqrt(PSFproperties[0]*PSFproperties[1])

            # Grab image dimensions
            ny, nx     = TMASSimg.arr.shape
            yc, xc     = np.array(TMASSimg.arr.shape)//2

            # Grab the image center coordinates
            TMASSwcs = WCS(TMASSimg.header)
            RA_cen, Dec_cen = TMASSwcs.wcs_pix2world(xc, yc, 0)
            TMASS_pl_sc = proj_plane_pixel_scales(TMASSwcs)
            TMASS_pl_sc = np.sqrt(TMASS_pl_sc[0]*TMASS_pl_sc[1])*3600.0

            # Compute distances from image center
            yy, xx = np.mgrid[0:ny, 0:nx]
            dist = np.sqrt((xx - xc)**2 + (yy - yc)**2)
            dist *= TMASS_pl_sc

            # Check if there are specified "good angles" for this target. If
            # there are, then build a mask to make sure radial profiles are
            # constructed using only user-specified regions of the nebula.
            if thisTarget in angleDict.keys():
                # This target has a specified "good angle" range.
                TMASS_angleMap = (np.rad2deg(np.arctan2((yy - yc), (xx - xc)))
                    - 90.0 + 360.0) % 360.0
                minAng, maxAng = np.min(angleDict[thisTarget]), np.max(angleDict[thisTarget])
예제 #57
0
파일: utils.py 프로젝트: Cadair/astropy
    def __init__(self, data, position, size, wcs=None, mode='trim',
                 fill_value=np.nan, copy=False):
        if isinstance(position, SkyCoord):
            if wcs is None:
                raise ValueError('wcs must be input if position is a '
                                 'SkyCoord')
            position = skycoord_to_pixel(position, wcs, mode='all')  # (x, y)

        if np.isscalar(size):
            size = np.repeat(size, 2)

        # special handling for a scalar Quantity
        if isinstance(size, u.Quantity):
            size = np.atleast_1d(size)
            if len(size) == 1:
                size = np.repeat(size, 2)

        if len(size) > 2:
            raise ValueError('size must have at most two elements')

        shape = np.zeros(2).astype(int)
        pixel_scales = None
        # ``size`` can have a mixture of int and Quantity (and even units),
        # so evaluate each axis separately
        for axis, side in enumerate(size):
            if not isinstance(side, u.Quantity):
                shape[axis] = int(np.round(size[axis]))     # pixels
            else:
                if side.unit == u.pixel:
                    shape[axis] = int(np.round(side.value))
                elif side.unit.physical_type == 'angle':
                    if wcs is None:
                        raise ValueError('wcs must be input if any element '
                                         'of size has angular units')
                    if pixel_scales is None:
                        pixel_scales = u.Quantity(
                            proj_plane_pixel_scales(wcs), wcs.wcs.cunit[axis])
                    shape[axis] = int(np.round(
                        (side / pixel_scales[axis]).decompose()))
                else:
                    raise ValueError('shape can contain Quantities with only '
                                     'pixel or angular units')

        data = np.asanyarray(data)
        # reverse position because extract_array and overlap_slices
        # use (y, x), but keep the input position
        pos_yx = position[::-1]

        cutout_data, input_position_cutout = extract_array(
            data, tuple(shape), pos_yx, mode=mode, fill_value=fill_value,
            return_position=True)
        if copy:
            cutout_data = np.copy(cutout_data)
        self.data = cutout_data

        self.input_position_cutout = input_position_cutout[::-1]    # (x, y)
        slices_original, slices_cutout = overlap_slices(
            data.shape, shape, pos_yx, mode=mode)

        self.slices_original = slices_original
        self.slices_cutout = slices_cutout

        self.shape = self.data.shape
        self.input_position_original = position
        self.shape_input = shape

        ((self.ymin_original, self.ymax_original),
         (self.xmin_original, self.xmax_original)) = self.bbox_original

        ((self.ymin_cutout, self.ymax_cutout),
         (self.xmin_cutout, self.xmax_cutout)) = self.bbox_cutout

        # the true origin pixel of the cutout array, including any
        # filled cutout values
        self._origin_original_true = (
            self.origin_original[0] - self.slices_cutout[1].start,
            self.origin_original[1] - self.slices_cutout[0].start)

        if wcs is not None:
            self.wcs = deepcopy(wcs)
            self.wcs.wcs.crpix -= self._origin_original_true
            self.wcs.array_shape = self.data.shape
            if wcs.sip is not None:
                self.wcs.sip = Sip(wcs.sip.a, wcs.sip.b,
                                   wcs.sip.ap, wcs.sip.bp,
                                   wcs.sip.crpix - self._origin_original_true)
        else:
            self.wcs = None
예제 #58
0
def make_signal_mask(cube, smooth_chans=200. / 66., min_chan=7, peak_snr=5.,
                     min_snr=3.5, edge_thresh=1.5, verbose=False):
    '''
    Create a robust signal mask by requiring spatial and spectral
    connectivity.
    '''

    import astropy.units as u
    from astropy.convolution import Box1DKernel
    from signal_id import Noise
    from scipy import ndimage as nd
    from astropy.wcs.utils import proj_plane_pixel_scales
    from astropy.utils.console import ProgressBar
    import skimage.morphology as mo
    import numpy as np
    from radio_beam import Beam
    from itertools import groupby, chain
    from operator import itemgetter
    import matplotlib.pyplot as p

    pixscale = proj_plane_pixel_scales(cube.wcs)[0]

    # # Want to smooth the mask edges
    mask = cube.mask.include().copy()

    # Set smoothing parameters and # consecutive channels.
    smooth_chans = int(round_up_to_odd(smooth_chans))

    # consecutive channels to be real emission.
    num_chans = min_chan

    # Smooth the cube, then create a noise model
    spec_kernel = Box1DKernel(smooth_chans)
    smooth_cube = cube.spectral_smooth(spec_kernel)

    noise = Noise(smooth_cube)
    noise.estimate_noise(spectral_flat=True)
    noise.get_scale_cube()

    snr = noise.snr.copy()

    snr[np.isnan(snr)] = 0.0

    posns = np.where(snr.max(axis=0) >= min_snr)

    bad_pos = np.where(snr.max(axis=0) < min_snr)
    mask[:, bad_pos[0], bad_pos[1]] = False

    for i, j in ProgressBar(zip(*posns)):

        # Look for all pixels above min_snr
        good_posns = np.where(snr[:, i, j] > min_snr)[0]

        # Reject if the total is less than connectivity requirement
        if good_posns.size < num_chans:
            mask[:, i, j] = False
            continue

        # Find connected pixels
        sequences = []
        for k, g in groupby(enumerate(good_posns), lambda (i, x): i - x):
            sequences.append(map(itemgetter(1), g))

        # Check length and peak. Require a minimum of 3 pixels above the noise
        # to grow from.
        sequences = [seq for seq in sequences if len(seq) >= 3 and
                     np.nanmax(snr[:, i, j][seq]) >= peak_snr]

        # Continue if no good sequences found
        if len(sequences) == 0:
            mask[:, i, j] = False
            continue

        # Now take each valid sequence and expand the edges until the smoothed
        # spectrum approaches zero.
        edges = [[seq[0], seq[-1]] for seq in sequences]
        for n, edge in enumerate(edges):
            # Lower side
            if n == 0:
                start_posn = edge[0]
                stop_posn = 0
            else:
                start_posn = edge[0] - edges[n - 1][0]
                stop_posn = edges[n - 1][0]

            for pt in np.arange(start_posn, stop_posn, -1):
                # if smoothed[pt] <= mad * edge_thresh:
                if snr[:, i, j][pt] <= edge_thresh:
                    break

                sequences[n].insert(0, pt)

            # Upper side
            start_posn = edge[1]
            if n == len(edges) - 1:
                stop_posn = cube.shape[0]
            else:
                stop_posn = edges[n + 1][0]

            for pt in np.arange(start_posn, stop_posn, 1):
                # if smoothed[pt] <= mad * edge_thresh:
                if snr[:, i, j][pt] <= edge_thresh:
                    break

                sequences[n].insert(0, pt)

        # Final check for the min peak level and ensure all meet the
        # spectral connectivity requirement
        sequences = [seq for seq in sequences if len(seq) >= num_chans and
                     np.nanmax(snr[:, i, j][seq]) >= peak_snr]

        if len(sequences) == 0:
            mask[:, i, j] = False
            continue

        bad_posns = \
            list(set(np.arange(cube.shape[0])) - set(list(chain(*sequences))))

        mask[:, i, j][bad_posns] = False

        if verbose:
            p.subplot(121)
            p.plot(cube.spectral_axis.value, noise.snr[:, i, j])
            min_val = cube.spectral_axis.value[np.where(mask[:, i, j])[0][-1]]
            max_val = cube.spectral_axis.value[np.where(mask[:, i, j])[0][0]]
            p.vlines(min_val, 0,
                     np.nanmax(noise.snr[:, i, j]))
            p.vlines(max_val, 0,
                     np.nanmax(noise.snr[:, i, j]))
            p.plot(cube.spectral_axis.value,
                   noise.snr[:, i, j] * mask[:, i, j], 'bD')

            p.subplot(122)
            p.plot(cube.spectral_axis.value, cube[:, i, j], label='Cube')
            p.plot(cube.spectral_axis.value, smooth_cube[:, i, j],
                   label='Smooth Cube')
            p.axvline(min_val)
            p.axvline(max_val)
            p.plot(cube.spectral_axis.value,
                   smooth_cube[:, i, j] * mask[:, i, j], 'bD')
            p.draw()
            raw_input("Next spectrum?")
            p.clf()