Example #1
0
def sources_mask(shape, x, y, a, b, theta, mask=None, scale=1.0):
    """Create a mask to cover all sources."""
    image = np.zeros(shape, dtype=bool)
    sep.mask_ellipse(image, x, y, a, b, theta, r=scale)
    if mask is not None:
        image |= np.array(mask)
    return image
Example #2
0
def spec_from_ellipse(cube, varcube = None,
                      x0 = 0., y0 = 0., a = 1.,
                      b = 1., theta = 0., r = 1.):
    
    """
    Get the spectrum within an elliptical region
    Args:
        cube (Spectral Cube): A datacube object
        varcube (Spectral Cube, optional): Variance cube
        x0, y0 (float, optional): Centroid of ellipse
        a, b (float, optional): semi-major and semi-minor axes
        theta (float, optional): rotation angle of the semi-major
            axis from the positive x axis.
        r (float, optional): Scaling factor for a and b.
            If not 1, a = r*a and b = r*b. 
    Returns:
        spec (OneDSpectrum): The extracted spectrum.
        var (OneDSpectrum): Variance in spectrum.
            Only returned if varcube is supplied.
    """
    #TODO: Use photutils aperture object for this.
    # Create 2D mask first
    mask = np.zeros(cube.shape[1:], dtype=np.bool)
    sep.mask_ellipse(mask, x0, y0, a, b, theta,r)
    
    return spec_from_mask(cube, mask, varcube=varcube)
Example #3
0
File: test.py Project: cmccully/sep
def test_mask_ellipse():
    arr = np.zeros((20, 20), dtype=np.bool)

    # should mask 5 pixels:
    sep.mask_ellipse(arr, 10., 10., 1.0, 1.0, 0.0, r=1.001)
    assert arr.sum() == 5

    # should mask 13 pixels:
    sep.mask_ellipse(arr, 10., 10., 1.0, 1.0, 0.0, r=2.001)
    assert arr.sum() == 13
Example #4
0
def test_mask_ellipse_alt():
    """mask_ellipse with cxx, cyy, cxy parameters."""
    arr = np.zeros((20, 20), dtype=np.bool)

    # should mask 5 pixels:
    sep.mask_ellipse(arr, 10., 10., cxx=1.0, cyy=1.0, cxy=0.0, r=1.001)
    assert arr.sum() == 5

    # should mask 13 pixels:
    sep.mask_ellipse(arr, 10., 10., cxx=1.0, cyy=1.0, cxy=0.0, r=2.001)
    assert arr.sum() == 13
Example #5
0
File: test.py Project: cmccully/sep
def test_mask_ellipse_dep():
    """Deprecated version of mask_ellipse"""
    arr = np.zeros((20, 20), dtype=np.bool)

    # should mask 5 pixels:
    sep.mask_ellipse(arr, 10., 10., cxx=1.0, cyy=1.0, cxy=0.0, scale=1.001)
    assert arr.sum() == 5

    # should mask 13 pixels:
    sep.mask_ellipse(arr, 10., 10., cxx=1.0, cyy=1.0, cxy=0.0, scale=2.001)
    assert arr.sum() == 13
Example #6
0
def test_mask_ellipse_alt():
    """mask_ellipse with cxx, cyy, cxy parameters."""
    arr = np.zeros((20, 20), dtype=np.bool)

    # should mask 5 pixels:
    sep.mask_ellipse(arr, 10., 10., cxx=1.0, cyy=1.0, cxy=0.0, r=1.001)
    assert arr.sum() == 5

    # should mask 13 pixels:
    sep.mask_ellipse(arr, 10., 10., cxx=1.0, cyy=1.0, cxy=0.0, r=2.001)
    assert arr.sum() == 13
Example #7
0
def sep_ellipse_mask(sources, image_shape, scale=5.0):

    logger.info('building ellipse mask')

    mask = np.zeros(image_shape, dtype=bool)
    sep.mask_ellipse(mask, sources['x'], sources['y'], sources['a'], 
                     sources['b'], sources['theta'], scale)

    logger.info('{:.2f}% of patch masked'.format(100 * mask.sum()/mask.size))

    return mask
Example #8
0
def sep_ellipse_mask(sources, image_shape, scale=5.0):

    logger.info('building ellipse mask')

    mask = np.zeros(image_shape, dtype=bool)

    sep.mask_ellipse(mask, sources['x'], sources['y'], sources['a'],
                     sources['b'], sources['theta'], scale)

    logger.info('{:.2f}% of image masked'.format(100 * mask.sum() / mask.size))

    return mask
Example #9
0
def gaia_star_mask(img,
                   wcs,
                   pix=0.168,
                   mask_a=694.7,
                   mask_b=4.04,
                   size_buffer=1.4,
                   gaia_bright=18.0,
                   factor_b=1.3,
                   factor_f=1.9):
    """Find stars using Gaia and mask them out if necessary.

    Using the stars found in the GAIA TAP catalog, we build a bright star mask following
    similar procedure in Coupon et al. (2017).

    We separate the GAIA stars into bright (G <= 18.0) and faint (G > 18.0) groups, and
    apply different parameters to build the mask.
    """
    gaia_stars = image_gaia_stars(img,
                                  wcs,
                                  pixel=pix,
                                  mask_a=mask_a,
                                  mask_b=mask_b,
                                  verbose=False,
                                  visual=False,
                                  size_buffer=size_buffer)

    # Make a mask image
    msk_star = np.zeros(img.shape).astype('uint8')

    if gaia_stars is not None:
        gaia_b = gaia_stars[gaia_stars['phot_g_mean_mag'] <= gaia_bright]
        sep.mask_ellipse(msk_star,
                         gaia_b['x_pix'],
                         gaia_b['y_pix'],
                         gaia_b['rmask_arcsec'] / factor_b / pix,
                         gaia_b['rmask_arcsec'] / factor_b / pix,
                         0.0,
                         r=1.0)

        gaia_f = gaia_stars[gaia_stars['phot_g_mean_mag'] > gaia_bright]
        sep.mask_ellipse(msk_star,
                         gaia_f['x_pix'],
                         gaia_f['y_pix'],
                         gaia_f['rmask_arcsec'] / factor_f / pix,
                         gaia_f['rmask_arcsec'] / factor_f / pix,
                         0.0,
                         r=1.0)

        return gaia_stars, msk_star

    return None, msk_star
Example #10
0
def make_HSC_detect_mask(bin_msk,
                         img,
                         objects,
                         segmap,
                         r=10.0,
                         radius=1.5,
                         threshold=0.01):
    '''Make HSC detection and bright star mask, 
    based on HSC binary mask flags.
    
    Parameters:
    -----------
    bin_msk: 2-D np.array, can be loaded from HSC image cutouts
    objects: table, returned from sep.extract_obj
    segmap: 2-D np.array, returned from sep.extract_obj
    r: float, blow-up parameter
    radius: float, convolution radius
    threshold: float, threshold of making mask after convolution

    Returns:
    -----------
    HSC_detect_mask: 2-D boolean np.array
    
    See also:
    -----------------
    convert_HSC_binary_mask(bin_msk)
    '''
    import sep
    TDmask = convert_HSC_binary_mask(bin_msk)
    cen_mask = np.zeros(bin_msk.shape, dtype=np.bool)
    cen_obj = objects[segmap[int(bin_msk.shape[0] / 2.),
                             int(bin_msk.shape[1] / 2.)] - 1]

    fraction_radius = sep.flux_radius(img, cen_obj['x'], cen_obj['y'],
                                      10 * cen_obj['a'], 0.5)[0]
    ba = np.divide(cen_obj['b'], cen_obj['a'])
    sep.mask_ellipse(cen_mask,
                     cen_obj['x'],
                     cen_obj['y'],
                     fraction_radius,
                     fraction_radius * ba,
                     cen_obj['theta'],
                     r=r)
    from astropy.convolution import convolve, Gaussian2DKernel
    HSC_mask = (TDmask[:, :, 5]).astype(bool) * (
        ~cen_mask) + TDmask[:, :, 9].astype(bool)
    # Convolve the image with a Gaussian kernel with the width of 1.5 pixel
    cvl = convolve(HSC_mask.astype('float'), Gaussian2DKernel(radius))
    HSC_detect_mask = cvl >= threshold
    return HSC_detect_mask
Example #11
0
def iraf_star_mask(img,
                   threshold,
                   fwhm,
                   mask=None,
                   bw=500,
                   bh=500,
                   fw=4,
                   fh=4,
                   zeropoint=27.0,
                   mag_lim=24.0):
    """Detect all stellar objects using DAOFind and IRAFStarFinder."""
    bkg_star = sep.Background(img, mask=mask, bw=bw, bh=bh, fw=fw, fh=fh)

    dao_finder = DAOStarFinder(fwhm=fwhm,
                               threshold=threshold * bkg_star.globalrms)
    irf_finder = IRAFStarFinder(fwhm=fwhm,
                                threshold=threshold * bkg_star.globalrms)

    stars_dao = dao_finder(img - bkg_star.globalback)
    stars_irf = irf_finder(img - bkg_star.globalback)

    msk_star = np.zeros(img.shape).astype('uint8')

    if len(stars_irf) > 0:
        stars_irf_use = stars_irf[(-2.5 * np.log10(stars_irf['flux']) +
                                   zeropoint) <= mag_lim]
        sep.mask_ellipse(msk_star,
                         stars_irf_use['xcentroid'],
                         stars_irf_use['ycentroid'],
                         fwhm,
                         fwhm,
                         0.0,
                         r=1.0)
    else:
        stars_irf_use = None

    if len(stars_dao) > 0:
        stars_dao_use = stars_dao[(-2.5 * np.log10(stars_dao['flux']) +
                                   zeropoint) <= mag_lim]
        sep.mask_ellipse(msk_star,
                         stars_dao_use['xcentroid'],
                         stars_dao_use['ycentroid'],
                         fwhm,
                         fwhm,
                         0.0,
                         r=1.0)
    else:
        stars_dao_use = None

    return stars_dao_use, stars_irf_use, msk_star
Example #12
0
    def get_trace_source(self, x, y, a=1, b=1, theta=0):
        """ ccdpixels -> traceindex
        
        The method get the RGBA values within an ellipe centered in `x` and `y` 
        with a major and minor axes length `a` and `b` and angle `theta`.
        The index of the traces that maximize the color overlap is then returned.
        
        Parameters
        ----------
        x, y: [float, float]
            x and y central position of the ellipses

        a, b: [float, float] -optional-
            major and minor axis lengths
        
        theta: [float] -optional-
            rotation angle (in rad) of the ellipse.
        
        Returns
        -------
        traceindex
        """
        try:
            from sep import mask_ellipse
        except:
            raise ImportError(
                "You need sep (Python verion of Sextractor) to run this method => sudo pip install sep"
            )

        masking = np.zeros(self._mapshape, dtype="bool")
        mask_ellipse(masking,
                     x * self.subpixelization,
                     y * self.subpixelization,
                     a * self.subpixelization,
                     b * self.subpixelization,
                     theta=theta)
        if not np.any(masking):
            return np.asarray([])

        sum_mask = np.sum(np.sum(
            [(self._facecolors.flatten() == v)
             for v in np.concatenate(self._maskimage.T.T[masking])],
            axis=0).reshape(self._facecolors.shape),
                          axis=1)

        return np.asarray(self.trace_indexes)[sum_mask == sum_mask.max(
        )] if sum_mask.max() > 0 else np.asarray([])
Example #13
0
    def get_mask(self, from_sources=None, **kwargs):
        """ get data mask

        Parameters
        ----------
        from_source: [None/bool/DataFrame] -optional-
            A mask will be extracted from the given source.
            (This uses, sep.mask_ellipse)
            Accepted format:
            - None or False: ignored.
            - True: this uses the self.sources
            - DataFrame: this will using this dataframe as source.
                         this dataframe must contain: x,y,a,b,theta

            => accepted kwargs: 'r' the scale (diameter) of the ellipse (5 default)

        #
        # anything else, self.mask is returned #
        #

        Returns
        -------
        2D array (True where should be masked out)
        """
        # Source mask
        if from_sources is not None and from_sources is not False:
            if type(from_sources)== bool and from_sources:
                from_sources = self.sources
            elif type(from_sources) is not pandas.DataFrame:
                raise ValueError("cannot parse the given from_source could be bool, or DataFrame")

            from sep import mask_ellipse
            ellipsemask = np.asarray(np.zeros(self.shape),dtype="bool")
            # -- Apply the mask to falsemask
            mask_ellipse(ellipsemask, *from_sources[["x","y","a","b","theta"]].astype("float").values.T,
                         r=kwargs.get('r',5)
                         )
            return ellipsemask

        return self.mask
Example #14
0
def bg_subtract2(im, obj, flux, fluxerr, r=None):
    if r is None:
        a = obj['a']
        b = obj['b']
    else:
        a = r
        b = r

    theta = max(min(obj['theta'], np.pi / 2.00001), -np.pi / 2.00001)

    outer = np.zeros(im.shape, bool)
    sep.mask_ellipse(outer, obj['x'], obj['y'], a, b, theta, r=5)

    inner = np.zeros(im.shape, bool)
    sep.mask_ellipse(inner, obj['x'], obj['y'], a, b, theta, r=3)

    area = np.zeros(im.shape, bool)
    sep.mask_ellipse(area, obj['x'], obj['y'], a, b, theta)
    area = area.sum()

    mask = outer * ~inner
    bgap = im * mask
    bgap = bgap[bgap != 0]
    mms = sigma_clipped_stats(bgap)

    flux -= mms[1] * area
    fluxerr = np.sqrt(fluxerr**2 + area * mms[2] * (1 + area / len(bgap)))
    return flux, fluxerr
Example #15
0
def make_obj_mask(cat, img_shape, grow_r=1.0):
    """
    Use SEP to build a mask based on objects in input catalog.

    Parameters
    ----------
    cat : astropy.table.Table
        Source catalog form SEP.
    img_shape : array-like
        The shape of the image to be masked.
    grow_r : float, optional
        Fraction to grow the objects sizes.

    Returns
    -------
    mask : 2D ndarray
        Mask with same shape as img_shape.
    """
    mask = np.zeros(img_shape, dtype='uint8')
    sep.mask_ellipse(mask, cat['x'], cat['y'], cat['a'], cat['b'],
                     cat['theta'], grow_r)
    return mask
Example #16
0
def sources_mask(shape, x, y, a, b, theta, mask=None, scale=1.0):
    """Create a mask to cover all sources.

    Parameters
    ----------
    shape: int or tuple of ints
        Shape of the new array.
    x,y: array_like
        Center of ellipse(s).
    a, b, theta: array_like (optional)
        Parameters defining the extent of the ellipe(s).
    mask: numpy.ndarray (optional)
        An optional mask.
        Default: `None`
    scale: array_like (optional)
        Scale factor of ellipse(s).
        Default: 1.0
    """
    image = np.zeros(shape, dtype=bool)
    sep.mask_ellipse(image, x, y, a, b, theta, r=scale)
    if mask is not None:
        image |= np.array(mask)
    return image
Example #17
0
def findsources(image,cube,check=False,output='.',spectra=False,helio=0,nsig=2.,
                minarea=10.,regmask=None,clean=True,outspec='Spectra',marz=False, 
		rphot=False, sname='MUSE'):

    """      

    Take a detection image (collapse of a cube), or median 
    of an RGB, or whatever you want (but aligned to the cube)
    and run sourceextractor 

   
    Use SEP utilities http://sep.readthedocs.org/en/stable/

    image   -> fits file of image to process
    check   -> if true write a bunch of check mages
    output  -> where to dump the output
    cube    -> the cube used to extract spectra
    spectra -> if True, extract spectra in VACUUM wave!!
    helio   -> pass additional heliocentric correction
    nsig    -> number of skyrms used for source id 
    minarea -> minimum area for extraction 
    regmask -> ds9 region file (image) of regions to be masked before extraction [e.g. edges]
    clean   -> clean souces 
    outspec -> where to store output spectra 
    marz    -> write spectra in also marz format (spectra needs to be true). 
               If set to numerical value, this is used as an r-band magnitude limit.
    rphot   -> perform r-band aperture photometry and add r-band magnitudes to the catalogue
    sname   -> prefix for the source names. Default = MUSE

    """

    import sep
    from astropy.io import fits
    from astropy import wcs
    from astropy import coordinates
    from astropy import units as u
    from astropy import table
    import numpy as np
    import os
    try:
        from mypython.ifu import muse_utils as utl
        from mypython.fits import pyregmask as msk
    except ImportError:
        from mypython import ifu
        from ifu import muse_utils as utl
        from mypython import fits
        from fits import pyregmask as msk
        from astropy.io import fits
    from shutil import copyfile
    import glob

    #open image
    img=fits.open(image)
    try:
        header=img[1].header
    except:
        header= img[0].header
    imgwcs = wcs.WCS(header)
    try:
        #this is ok for narrow band images 
        data=img[1].data
    except:
        #white cubex images
        data=img[0].data
    data=data.byteswap(True).newbyteorder()
    #grab effective dimension
    nex,ney=data.shape
    #close fits
    img.close()

    #create bad pixel mask
    if(regmask):
        Mask=msk.PyMask(ney,nex,regmask,header=img[0].header)
        for ii in range(Mask.nreg):
            Mask.fillmask(ii)
            if(ii == 0):
                badmask=Mask.mask
            else:
                badmask+=Mask.mask
            badmask=1.*badmask
    else:
        badmask=np.zeros((nex,ney))

    if(check):
        print('Dumping badmask')
        hdumain  = fits.PrimaryHDU(badmask,header=header)
        hdulist = fits.HDUList([hdumain])
        hdulist.writeto(output+"/badmask.fits",overwrite=True)
    

    #check background level, but do not subtract it
    print('Checking background levels')
    bkg = sep.Background(data,mask=badmask)    
    print('Residual background level ', bkg.globalback)
    print('Residual background rms ', bkg.globalrms)

    if(check):
        print('Dumping sky...')
        #dump sky properties
        back = bkg.back() 
        rms = bkg.rms()  
        hdumain  = fits.PrimaryHDU(back,header=header)
        hdubk  = fits.ImageHDU(back)
        hdurms  = fits.ImageHDU(rms)
        hdulist = fits.HDUList([hdumain,hdubk,hdurms])
        hdulist.writeto(output+"/skyprop.fits",overwrite=True)

    #extracting sources at nsigma
    thresh = nsig * bkg.globalrms
    # segmap = np.zeros((header["NAXIS1"],header["NAXIS2"]))
    objects, segmap=sep.extract(data,thresh,segmentation_map=True,
                               minarea=minarea,clean=clean,mask=badmask,deblend_cont=0.0001)
    print("Extracted {} objects... ".format(len(objects)))
    
    
    if(spectra):
        if not os.path.exists(outspec):
            os.makedirs(outspec)

    if((check) | (spectra)):
        #create a detection mask alla cubex
        srcmask=np.zeros((1,data.shape[0],data.shape[1]))
        nbj=1
        print('Generating spectra...')
        #loop over detections
        for obj in objects:
            #init mask
            tmpmask=np.zeros((data.shape[0],data.shape[1]),dtype=np.bool)
            tmpmask3d=np.zeros((1,data.shape[0],data.shape[1]),dtype=np.bool)
            #fill this mask
            sep.mask_ellipse(tmpmask,obj['x'],obj['y'],obj['a'],obj['b'],obj['theta'],r=2)
            tmpmask3d[0,:,:]=tmpmask[:,:]
            srcmask=srcmask+tmpmask3d*nbj
            if(spectra):
                savename="{}/id{}.fits".format(outspec,nbj)
                if not os.path.exists(savename):
                    utl.cube2spec(cube,obj['x'],obj['y'],None,write=savename,
                                shape='mask',helio=helio,mask=tmpmask3d,tovac=True)
                else:
                    print("{} already exists. Skipping it...".format(savename))
            #go to next
            nbj=nbj+1

    if(check):
        print('Dumping source mask...')
        hdumain  = fits.PrimaryHDU(srcmask,header=header)
        hdubk  = fits.ImageHDU(srcmask)
        hdulist = fits.HDUList([hdumain,hdubk])
        hdulist.writeto(output+"/source.fits",overwrite=True)
        
        print('Dumping segmentation map')
        hdumain  = fits.PrimaryHDU(segmap,header=header)
        hdubk  = fits.ImageHDU(segmap)
        hdulist = fits.HDUList([hdumain,hdubk])
        hdulist.writeto(output+"/segmap.fits",overwrite=True)
    
    #Generate source names using coordinates and name prefix
    ra, dec = imgwcs.wcs_pix2world(objects['x'], objects['y'],0)
    coord = coordinates.FK5(ra*u.degree, dec*u.degree)
    rastr  = coord.ra.to_string(u.hour, precision=2, sep='')
    decstr = coord.dec.to_string(u.degree, precision=1, sep='', alwayssign=True)
    name = [sname+'J{0}{1}'.format(rastr[k], decstr[k]) for k in range(len(rastr))]
    ids  = np.arange(len(name))

    #write source catalogue
    print('Writing catalogue..')
    tab = table.Table(objects)
    tab.add_column(table.Column(name),0,name='name')
    tab.add_column(table.Column(ids),0,name='ID')
    tab.write(output+'/catalogue.fits',overwrite=True)
    
    #cols = fits.ColDefs(objects)
    #cols.add_col(fits.Column(name, format='A'))
    #tbhdu = fits.BinTableHDU.from_columns(cols)
    #tbhdu.writeto(output+'/catalogue.fits',clobber=True)
    
    #rband photometry
    if (rphot):
        if not os.path.exists(output+'/Image_R.fits'):
            rimg, rvar, rwcsimg = utl.cube2img(cube, filt=129, write=output+'/Image_R.fits')
        phot_r = sourcephot(output+'/catalogue.fits', output+'/Image_R.fits', output+'/segmap.fits', image)
        phot_r.add_column(table.Column(name),1,name='name')

    tbhdu = fits.open(output+'/catalogue.fits')[1]
    tbhdu2 = fits.BinTableHDU(phot_r)
    hdulist = fits.HDUList([fits.PrimaryHDU(), tbhdu, tbhdu2])
    hdulist.writeto(output+'/catalogue.fits',overwrite=True)	

    if((marz) & (spectra)):
        #if marz is True but no magnitude limit set, create marz file for whole catalogue
        if marz==True:
            marz_file(image, output+'/catalogue.fits', outspec, output)
        else:
            #create folder and catalogue with just sources brighter than mag limit
            if os.path.exists(output + '/spectra_r' + str(marz)):
	            files = glob.glob(output +  '/spectra_r' + 
                          str(marz) +'/*')
	            for f in files:
       		        os.remove(f)
            else:
	            os.mkdir(output +  '/spectra_r' + str(marz))
            
            mag = phot_r['MAGSEG']

            #add in x y pixels from original catalogue
            x, y = tbhdu.data['x'], tbhdu.data['y']
            phot_r['x'], phot_r['y'] = x, y

            #add in ra,dec 
            img = fits.open(image)
            mywcs = wcs.WCS(img[0].header)
            ra, dec = mywcs.all_pix2world(x,y,0)
            phot_r['RA'] = ra
            phot_r['dec'] = dec

            for i in range(len(mag)):
	            if mag[i] < marz:
		            copyfile((output + '/spectra/id' + str(i+1) 
                              + '.fits'), (output + '/spectra_r' + 
                              str(marz) + '/id' + str(i+1) + '.fits'))

            #Write photometry catalog with objects below magnitude limit excluded
            phot_r.remove_rows(phot_r['MAGSEG'] > marz)
            catalogue_lim_name = (output + '/catalogue_r' + 
                                  str(marz) +'.fits')
            if os.path.exists(catalogue_lim_name):
                os.remove(catalogue_lim_name)
            phot_r.write(catalogue_lim_name)

            outspec = output + '/spectra_r' + str(marz)
            marz_file(image, output+'/catalogue_r' + str(marz) +'.fits', outspec, output, r_lim=marz)

    
    print('All done')
    return objects
Example #18
0
def sourcephot(catalogue,image,segmap,detection,instrument='MUSE',dxp=0.,dyp=0.,
               noise=[False],zpab=False, kn=2.5, circap=1.0):

    """ 

    Get a source catalogue from findsources and a fits image with ZP
    and compute magnitudes in that filter 

    catalogue -> source cat from findsources
    image     -> fits image with ZP in header
    segmap    -> fits of segmentation map 
    detection -> the detection image, used to compute Kron radius 

    instrument -> if not MUSE, map positions from detection to image

    dxp,dyp    -> shifts in pixel of image to register MUSE and image astrometry   
   
    noise      -> if set to a noise model, use equation noise[0]*noise[1]*npix**noise[2]
                  to compute the error

    zpab  -> if ZPAB (zeropoint AB) not stored in header, must be supplied

    kn   -> factor to be used when scaling Kron apertures [sextractor default 2.5]
  
    circap -> radius in arcsec for aperture photmetry to be used when Kron aperture fails 

    """  

    from astropy.io import fits
    import numpy as np
    import sep
    import matplotlib.pyplot as plt
    from astropy.table import Table
    from astropy import wcs 


    #grab root name 
    rname=((image.split('/')[-1]).split('.fits'))[0]
    print ('Working on {}'.format(rname))

    #open the catalogue/fits 
    cat=fits.open(catalogue)
    img=fits.open(image)
    seg=fits.open(segmap)
    det=fits.open(detection)

    #grab reference wcs from detection image 
    try:
        wref=wcs.WCS(det[1].header)
    except:
        wref = wcs.WCS(det[0].header)
    psref=wref.pixel_scale_matrix[1,1]*3600.
    print ('Reference pixel size {}'.format(psref))


    #if not handling MUSE, special cases for format of data
    if('MUSE' not in instrument):
        #handle instrument cases
        if('LRIS' in instrument):
            #data 
            imgdata=img[1].data
            #place holder for varaince as will use noise model below
            vardata=imgdata*0+1
            vardata=vardata.byteswap(True).newbyteorder()
            #grab wcs image
            wimg=wcs.WCS(img[1].header)
            psimg=wimg.pixel_scale_matrix[1,1]*3600.
            #store the ZP 
            if(zpab):
                img[0].header['ZPAB']=zpab
        else:
            print('Instrument not supported!!')
            exit()
    else:
        #for muse, keep eveything the same
        imgdata=img[0].data
        vardata=img[1].data
        psimg=psref

    #grab flux and var
    dataflx=np.nan_to_num(imgdata.byteswap(True).newbyteorder())
    datavar=np.nan_to_num(vardata.byteswap(True).newbyteorder())
    # import pdb; pdb.set_trace()
    #grab detection and seg mask
    try:
        detflx=np.nan_to_num(det[1].data.byteswap(True).newbyteorder())
    except:
        detflx = np.nan_to_num(det[0].data.byteswap(True).newbyteorder())

    #go back to 1d
    if(len(seg[0].data.shape)>2):
        segmask=(np.nan_to_num(seg[0].data.byteswap(True).newbyteorder()))[0,:,:]
    else:
        segmask=(np.nan_to_num(seg[0].data.byteswap(True).newbyteorder()))


    #if needed, map the segmap to new image with transformation
    if('MUSE' not in instrument):
        #allocate space for transformed segmentation map
        segmasktrans=np.zeros(dataflx.shape)
        print("Remapping segmentation map to new image...")

        #loop over original segmap and map to trasformed one
        #Just use nearest pixel, and keep only 1 when multiple choices 
        for xx in range(segmask.shape[0]):
            for yy in range(segmask.shape[1]):
                #go to world
                radec=wref.wcs_pix2world([[yy,xx]],0)
                #back to new instrument pixel 
                newxy=wimg.wcs_world2pix(radec,0)
                #apply shift to register WCS
                newxy[0][1]=newxy[0][1]+dyp
                newxy[0][0]=newxy[0][0]+dxp
                segmasktrans[newxy[0][1],newxy[0][0]]=segmask[xx,yy]
                
                #grow buffer as needed by individual instruments
                #This accounts for resampling to finer pixel size
                if('LRIS' in instrument):
                    segmasktrans[newxy[0][1]+1,newxy[0][0]+1]=segmask[xx,yy]
                    segmasktrans[newxy[0][1]-1,newxy[0][0]-1]=segmask[xx,yy]
                    segmasktrans[newxy[0][1]+1,newxy[0][0]-1]=segmask[xx,yy]
                    segmasktrans[newxy[0][1]-1,newxy[0][0]+1]=segmask[xx,yy]
                    segmasktrans[newxy[0][1]+1,newxy[0][0]]=segmask[xx,yy]
                    segmasktrans[newxy[0][1]-1,newxy[0][0]]=segmask[xx,yy]
                    segmasktrans[newxy[0][1],newxy[0][0]-1]=segmask[xx,yy]
                    segmasktrans[newxy[0][1],newxy[0][0]+1]=segmask[xx,yy]
                 
        #dump the transformed segmap for checking 
        hdumain  = fits.PrimaryHDU(segmasktrans,header=img[1].header)
        hdulist = fits.HDUList(hdumain)
        hdulist.writeto("{}_segremap.fits".format(rname),clobber=True)
    else:
        #no transformation needed
        segmasktrans=segmask

    #source to extract
    nsrc=len(cat[1].data)
    print('Extract photometry for {} sources'.format(nsrc))
    phot = Table(names=('ID', 'MAGAP', 'MAGAP_ERR','FXAP', 'FXAP_ERR', 
                        'RAD', 'MAGSEG', 'MAGSEG_ERR', 'FXSEG', 'FXSEG_ERR','ZP'), 
                 dtype=('i4','f4','f4','f4','f4','f4','f4','f4','f4','f4','f4'))
    
   
    #create check aperture mask 
    checkaperture=np.zeros(dataflx.shape)
    print('Computing photometry for objects...')

    #loop over each source
    for idobj in range(nsrc):
        
        #########
        #Find positions etc and transform as appropriate
        #########
                
        #extract MUSE source paramaters 
        x= cat[1].data['x'][idobj]
        y= cat[1].data['y'][idobj]
        a= cat[1].data['a'][idobj]
        b= cat[1].data['b'][idobj]
        theta= cat[1].data['theta'][idobj]

        #compute kron radius on MUSE detection image 
        #Kron rad in units of a,b
        tmpdata=np.copy(detflx)
        tmpmask=np.copy(segmask)
        #mask all other sources to avoid overlaps but keep desired one
        pixels=np.where(tmpmask == idobj+1) 
        tmpmask[pixels]=0

        #compute kron radius [pixel of reference image]
        kronrad, flg = sep.kron_radius(tmpdata,x,y,a,b,theta,6.0,mask=tmpmask)

        #plt.imshow(np.log10(tmpdata+1),origin='low')
        #plt.show()
        #exit()

        #now check if size is sensible in units of MUSE data 
        rmin = 2.0  #MUSE pix 
        use_circle = kronrad * np.sqrt(a*b) < rmin
      
        #use circular aperture of 2" in muse pixel unit
        rcircap = circap/psref
        
        #now use info to compute photometry and apply 
        #spatial transformation if needed
        if('MUSE' not in instrument):
            #map centre of aperture - +1 reference
            #go to world
            radec=wref.wcs_pix2world([[x,y]],1)
            #back to new instrument pixel 
            newxy=wimg.wcs_world2pix(radec,1)
            #apply shift to register WCS
            xphot=newxy[0][0]+dxp
            yphot=newxy[0][1]+dyp
                      
            #scale radii to new pixel size 
            rminphot=rcircap*psref/psimg
            aphot=a*psref/psimg
            bphot=b*psref/psimg
            #Kron radius in units of a,b

        else:
            #for muse, transfer to same units
            xphot=x
            yphot=y
            rminphot=rcircap
            aphot=a
            bphot=b     
            
        #####
        #Compute local sky 
        #####
        skyreg=kn*kronrad*np.sqrt(aphot*bphot)+15
        if (yphot-skyreg < 0.0): yphot=skyreg
        if (xphot-skyreg < 0.0): xphot=skyreg
        if (yphot+skyreg > segmasktrans.shape[0]-1): yphot=segmasktrans.shape[0]-1-skyreg
        if (xphot+skyreg > segmasktrans.shape[1]-1): xphot=segmasktrans.shape[1]-1-skyreg
        #print(int(yphot-skyreg),int(yphot+skyreg),int(xphot-skyreg),int(xphot+skyreg))
        cutskymask=segmasktrans[int(yphot-skyreg):int(yphot+skyreg),int(xphot-skyreg):int(xphot+skyreg)]
        cutskydata=dataflx[int(yphot-skyreg):int(yphot+skyreg),int(xphot-skyreg):int(xphot+skyreg)]
        skymedian=np.nan_to_num(np.median(cutskydata[np.where(cutskymask < 1.0)]))

        #print skymedian    

        #plt.imshow(cutskymask,origin='low')
        #plt.show()
        #if(idobj > 30):
        #    exit()


        #########
        #Now grab the Kron mag computed using detection image
        #########
   
        #mask all other objects to avoid blending   
        tmpdata=np.copy(dataflx)
        #apply local sky subtraction 
        tmpdata=tmpdata-skymedian
        tmpvar=np.copy(datavar)
        tmpmask=np.copy(segmasktrans)
        pixels=np.where(tmpmask == idobj+1) 
        tmpmask[pixels]=0

        #plt.imshow(tmpmask,origin='low')
        #plt.show()
        #exit()

        #circular aperture
        if(use_circle):        
           
            #flux in circular aperture
            flux_kron, err, flg = sep.sum_circle(tmpdata,xphot,yphot,rminphot,mask=tmpmask)
            #propagate variance
            fluxvar, err, flg = sep.sum_circle(tmpvar,xphot,yphot,rminphot,mask=tmpmask)
            #store Rused in arcsec
            rused=rminphot*psimg

            #update check aperture
            tmpcheckaper=np.zeros(dataflx.shape,dtype=bool)
            sep.mask_ellipse(tmpcheckaper,xphot,yphot,1.,1.,0.,r=rminphot)
            checkaperture=checkaperture+tmpcheckaper*(idobj+1)

        #kron apertures 
        else:
            #kron flux 
            flux_kron, err, flg = sep.sum_ellipse(tmpdata,xphot, yphot, aphot, bphot, theta, kn*kronrad,
                                                  mask=tmpmask)            
            #propagate variance 
            fluxvar, err, flg = sep.sum_ellipse(tmpvar,xphot,yphot, aphot, bphot, theta, kn*kronrad,
                                                mask=tmpmask)
            #translate in radius
            rused=kn*kronrad*psimg*np.sqrt(aphot*bphot)

            #update check aperture
            tmpcheckaper=np.zeros(dataflx.shape,dtype=bool)
            sep.mask_ellipse(tmpcheckaper,xphot,yphot,aphot,bphot,theta,r=kn*kronrad)
            checkaperture=checkaperture+tmpcheckaper*(idobj+1)

        #compute error for aperture
        if(noise[0]):
            #use model 
            appix=np.where(tmpcheckaper > 0)
            errflux_kron=noise[0]*noise[1]*len(appix[0])**noise[2]
        else:
            #propagate variance 
            errflux_kron=np.sqrt(fluxvar)

        #go to mag 
        if(flux_kron > 0):
            mag_aper=-2.5*np.log10(flux_kron)+img[0].header['ZPAB']
            errmg_aper=2.5*np.log10(1.+errflux_kron/flux_kron)
        else:
            mag_aper=99.0
            errmg_aper=99.0
        
        #find out if non detections
        if(errflux_kron >= flux_kron):
            errmg_aper=9
            mag_aper=-2.5*np.log10(2.*errflux_kron)+img[0].header['ZPAB']
          
        #######
        #grab the photometry in the segmentation map 
        #####

        #This may not work well for other instruments 
        #if images are not well aligned
        pixels=np.where(segmasktrans == idobj+1) 
        #add flux in pixels
        tmpdata=np.copy(dataflx)
        #apply sky sub
        tmpdata=tmpdata-skymedian
        flux_seg=np.sum(tmpdata[pixels])
        
        #compute noise from model or adding variance 
        if(noise[0]):
            #from model 
            errfx_seg=noise[0]*noise[1]*len(pixels[0])**noise[2]
        else:
            #add variance in pixels to compute error
            errfx_seg=np.sqrt(np.sum(datavar[pixels]))
  
        #go to mag with calibrations 
        if(flux_seg > 0):
            mag_seg=-2.5*np.log10(flux_seg)+img[0].header['ZPAB']
            errmg_seg=2.5*np.log10(1.+errfx_seg/flux_seg)     
        else:
            mag_seg=99.0
            errmg_seg=99.0
      
        #find out if non detections
        if(errfx_seg >= flux_seg):
            errmg_seg=9
            mag_seg=-2.5*np.log10(2.*errfx_seg)+img[0].header['ZPAB']
        
        #stash by id
        phot.add_row((idobj+1,mag_aper,errmg_aper,flux_kron,errflux_kron,rused,mag_seg,errmg_seg,
                      flux_seg,errfx_seg,img[0].header['ZPAB']))

    #dump the aperture check image 
    hdumain  = fits.PrimaryHDU(checkaperture,header=img[1].header)
    hdulist = fits.HDUList(hdumain)
    hdulist.writeto("{}_aper.fits".format(rname),clobber=True)

    #close
    cat.close()
    img.close()
    seg.close()
    det.close()

    return phot
Example #19
0
def findsources(image,
                cube,
                varima=None,
                check=False,
                output='./',
                spectra=False,
                helio=0,
                nsig=2.,
                minarea=10.,
                deblend_cont=0.0001,
                regmask=None,
                invregmask=False,
                fitsmask=None,
                clean=True,
                outspec='Spectra',
                marz=False,
                rphot=False,
                detphot=False,
                sname='MUSE'):
    """      

    Take a detection image (collapse of a cube), or median 
    of an RGB, or whatever you want (but aligned to the cube)
    and run sourceextractor 

   
    Use SEP utilities http://sep.readthedocs.org/en/stable/

    image   -> fits file of image to process
    cube    -> the cube used to extract spectra
    varima  -> the noise image corresponding to the science image (std), optional
    check   -> if true write a bunch of check mages
    output  -> where to dump the output
    spectra -> if True, extract spectra in VACUUM wave!!
    helio   -> pass additional heliocentric correction
    nsig    -> number of skyrms used for source id 
    minarea -> minimum area for extraction 
    regmask -> ds9 region file (image) of regions to be masked before extraction [e.g. edges]
    invregmask -> if True invert the mask (region defines good area)
    fitsmask -> Fits file with good mask, overrides regmask
    clean   -> clean souces 
    outspec -> where to store output spectra 
    marz    -> write spectra in also marz format (spectra needs to be true). 
               If set to numerical value, this is used as an r-band magnitude limit.
    detphot -> perform aperture phtometry on the detection image and add magnitues to the catalogue            
    rphot   -> perform r-band aperture photometry and add r-band magnitudes to the catalogue
    sname   -> prefix for the source names. Default = MUSE

    """

    import sep
    from astropy.io import fits
    from astropy import wcs
    from astropy import coordinates
    from astropy import units as u
    from astropy import table
    import numpy as np
    import os
    from mypython.ifu import muse_utils as utl
    from mypython.fits import pyregmask as msk
    from shutil import copyfile
    import glob

    #open image
    img = fits.open(image)
    header = img[0].header
    imgwcs = wcs.WCS(header)
    try:
        #this is ok for narrow band images
        data = img[1].data
    except:
        #white cubex images
        data = img[0].data

    data = data.byteswap(True).newbyteorder()
    #grab effective dimension
    nex, ney = data.shape
    #close fits
    img.close()

    if (varima):
        var = fits.open(varima)
        try:
            datavar = var[1].data
        except:
            datavar = var[0].data

        datavar = datavar.byteswap(True).newbyteorder()
        #grab effective dimension
        stdx, stdy = datavar.shape
        #close fits
        var.close()

        if (stdx != nex) or (stdy != ney):
            print(
                "The noise image does not have the same dimensions as the science image"
            )
            return -1

    #create bad pixel mask
    if (fitsmask):
        print("Using FITS image for badmask")
        hdumsk = fits.open(fitsmask)
        try:
            badmask = hdumsk[1].data
        except:
            badmask = hdumsk[0].data
        badmask = badmask.byteswap(True).newbyteorder()
    elif (regmask):
        print("Using region file for badmask")
        Mask = msk.PyMask(ney, nex, regmask, header=img[0].header)
        for ii in range(Mask.nreg):
            Mask.fillmask(ii)
            if (ii == 0):
                badmask = Mask.mask
            else:
                badmask += Mask.mask
            badmask = 1. * badmask
    else:
        badmask = np.zeros((nex, ney))

    if (regmask) and (invregmask) and not (fitsmask):
        badmask = 1 - badmask

    if (check):
        print('Dumping badmask')
        hdumain = fits.PrimaryHDU(badmask, header=header)
        hdulist = fits.HDUList([hdumain])
        hdulist.writeto(output + "/badmask.fits", overwrite=True)

    #check background level, but do not subtract it
    print('Checking background levels')
    bkg = sep.Background(data, mask=badmask)
    print('Residual background level ', bkg.globalback)
    print('Residual background rms ', bkg.globalrms)

    if (check):
        print('Dumping sky...')
        #dump sky properties
        back = bkg.back()
        rms = bkg.rms()
        hdumain = fits.PrimaryHDU(back, header=header)
        hdubk = fits.ImageHDU(back)
        hdurms = fits.ImageHDU(rms)
        hdulist = fits.HDUList([hdumain, hdubk, hdurms])
        hdulist.writeto(output + "/skyprop.fits", overwrite=True)

    if (varima):
        #Use nsigma threshold and a pixel by pixel effective treshold based on variance map
        thresh = nsig
        objects, segmap = sep.extract(data,
                                      thresh,
                                      var=datavar,
                                      segmentation_map=True,
                                      minarea=minarea,
                                      clean=clean,
                                      mask=badmask,
                                      deblend_cont=deblend_cont,
                                      deblend_nthresh=32)
    else:
        #extracting sources at nsigma, use constant threshold
        thresh = nsig * bkg.globalrms
        objects, segmap = sep.extract(data,
                                      thresh,
                                      segmentation_map=True,
                                      minarea=minarea,
                                      clean=clean,
                                      mask=badmask,
                                      deblend_cont=deblend_cont,
                                      deblend_nthresh=32)

    print("Extracted {} objects... ".format(len(objects)))
    ids = np.arange(len(objects)) + 1

    if (spectra):
        if not os.path.exists(outspec):
            os.makedirs(outspec)

    if ((check) | (spectra)):
        #create a detection mask a'la cubex
        srcmask = np.zeros((data.shape[0], data.shape[1]))
        print('Generating spectra...')
        #loop over detections
        for nbj in ids:
            obj = objects[nbj - 1]
            #init mask
            tmpmask = np.zeros((data.shape[0], data.shape[1]), dtype=np.bool)
            #fill this mask
            sep.mask_ellipse(tmpmask,
                             obj['x'],
                             obj['y'],
                             obj['a'],
                             obj['b'],
                             obj['theta'],
                             r=2)
            #add in global mask
            srcmask = srcmask + tmpmask * nbj
            #verify conflicts, resolve using segmentation map
            if np.nanmax(srcmask) > nbj:
                blended = (srcmask > nbj)
                srcmask[blended] = segmap[blended]

        #Now loop again and extract spectra if required
        if (spectra):
            #Verify that the source mask has the same number of objects as the object list
            if not len(np.unique(srcmask[srcmask > 0])) == len(objects):
                print(
                    "Mismatch between number of objects and number of spectra to extract."
                )
            for nbj in ids:
                savename = "{}/id{}.fits".format(outspec, nbj)
                tmpmask3d = np.zeros((1, data.shape[0], data.shape[1]))
                tmpmask3d[0, :, :] = srcmask[:, :]
                tmpmask3d[tmpmask3d != nbj] = 0
                tmpmask3d[tmpmask3d > 0] = 1
                tmpmask3d = np.array(tmpmask3d, dtype=np.bool)
                utl.cube2spec(cube,
                              None,
                              None,
                              None,
                              write=savename,
                              shape='mask',
                              helio=helio,
                              mask=tmpmask3d,
                              tovac=True)

    if (check):
        print('Dumping source mask...')
        hdumain = fits.PrimaryHDU(srcmask, header=header)
        hdubk = fits.ImageHDU(srcmask)
        hdulist = fits.HDUList([hdumain, hdubk])
        hdulist.writeto(output + "/source.fits", overwrite=True)

        print('Dumping segmentation map')
        hdumain = fits.PrimaryHDU(segmap, header=header)
        hdubk = fits.ImageHDU(segmap)
        hdulist = fits.HDUList([hdumain, hdubk])
        hdulist.writeto(output + "/segmap.fits", overwrite=True)

    #Generate source names using coordinates and name prefix
    ra, dec = imgwcs.wcs_pix2world(objects['x'], objects['y'], 0)
    coord = coordinates.FK5(ra * u.degree, dec * u.degree)
    rastr = coord.ra.to_string(u.hour, precision=2, sep='', pad=True)
    decstr = coord.dec.to_string(u.degree,
                                 precision=1,
                                 sep='',
                                 alwayssign=True,
                                 pad=True)
    name = [
        sname + 'J{0}{1}'.format(rastr[k], decstr[k])
        for k in range(len(rastr))
    ]

    #Generate a column to be used to flag the sources to be used in the analysis
    #True for all sources at this point
    use_source = np.ones_like(name, dtype=bool)

    #write source catalogue
    print('Writing catalogue..')
    tab = table.Table(objects)
    tab.add_column(table.Column(dec), 0, name='DEC')
    tab.add_column(table.Column(ra), 0, name='RA')
    tab.add_column(table.Column(name), 0, name='name')
    tab.add_column(table.Column(ids), 0, name='ID')
    tab.add_column(table.Column(use_source), name='use_source')
    tab.write(output + '/catalogue.fits', overwrite=True)

    if (detphot):
        #Run source photometry on the extraction image
        whiteimg, whitevar, whitewcsimg = utl.cube2img(cube,
                                                       write=output +
                                                       '/Image_white.fits')
        phot_det = sourcephot(output + '/catalogue.fits',
                              output + '/Image_white.fits',
                              output + '/segmap.fits',
                              image,
                              zpab=28.35665)
        phot_det.add_column(table.Column(name), 1, name='name')
        tbhdu = fits.open(output + '/catalogue.fits')
        tbhdu.append(fits.BinTableHDU(phot_det))
        tbhdu[-1].header['PHOTBAND'] = 'Detection'
        tbhdu.writeto(output + '/catalogue.fits', overwrite=True)

    #rband photometry
    if (rphot):
        rimg, rvar, rwcsimg = utl.cube2img(cube,
                                           filt=129,
                                           write=output + '/Image_R.fits')
        phot_r = sourcephot(output + '/catalogue.fits',
                            output + '/Image_R.fits', output + '/segmap.fits',
                            image)
        phot_r.add_column(table.Column(name), 1, name='name')

        tbhdu = fits.open(output + '/catalogue.fits')
        tbhdu.append(fits.BinTableHDU(phot_r))
        tbhdu[-1].header['PHOTBAND'] = 'SDSS_r'
        tbhdu.writeto(output + '/catalogue.fits', overwrite=True)

    if ((marz) & (spectra)):
        #if marz is True but no magnitude limit set, create marz file for whole catalogue
        if marz > 10 and (rphot):
            #Requires testing
            hdu = fits.open(output + '/catalogue.fits')
            hdu[1].data['use_source'][hdu[2].data['MAGAP'] > marz] = False
            hdu.writeto(output + '/catalogue.fits', overwrite=True)

            marz_file(output + '/catalogue.fits', outspec, output, r_lim=marz)
        else:
            marz_file(output + '/catalogue.fits', outspec, output)

    print('All done')
    return objects
Example #20
0
def findsources(image,
                cube,
                check=False,
                output='./',
                spectra=False,
                helio=0,
                nsig=2.,
                minarea=10.,
                regmask=None,
                clean=True,
                outspec='Spectra'):
    """      

    Take a detection image (collapse of a cube), or median 
    of an RGB, or whatever you want (but aligned to the cube)
    and run sourceextractor 

   
    Use SEP utilities http://sep.readthedocs.org/en/stable/

    image   -> fits file of image to process
    check   -> if true write a bunch of check mages
    output  -> where to dump the output
    cube    -> the cube used to extract spectra
    spectra -> if True, extract spectra in VACUUM wave!!
    helio   -> pass additional heliocentric correction
    nsig    -> number of skyrms used for source id 
    minarea -> minimum area for extraction 
    regmask -> ds9 region file (image) of regions to be masked before extraction [e.g. edges]
    clean   -> clean souces 
    outspec -> where to store output spectra 

    """

    import sep
    from astropy.io import fits
    import numpy as np
    import os
    from mypython.ifu import muse_utils as utl
    from mypython.fits import pyregmask as msk

    #open image
    img = fits.open(image)
    header = img[0].header
    try:
        #this is ok for narrow band images
        data = img[1].data
    except:
        #white cubex images
        data = img[0].data
    data = data.byteswap(True).newbyteorder()
    #grab effective dimension
    nex, ney = data.shape
    #close fits
    img.close()

    #create bad pixel mask
    if (regmask):
        Mask = msk.PyMask(ney, nex, regmask)
        for ii in range(Mask.nreg):
            Mask.fillmask(ii)
            if (ii == 0):
                badmask = Mask.mask
            else:
                badmask += Mask.mask
            badmask = 1. * badmask
    else:
        badmask = np.zeros((nex, ney))

    if (check):
        print('Dumping badmask')
        hdumain = fits.PrimaryHDU(badmask, header=header)
        hdulist = fits.HDUList([hdumain])
        hdulist.writeto(output + "/badmask.fits", clobber=True)

    #check background level, but do not subtract it
    print 'Checking background levels'
    bkg = sep.Background(data, mask=badmask)
    print 'Residual background level ', bkg.globalback
    print 'Residual background rms ', bkg.globalrms

    if (check):
        print 'Dumping sky...'
        #dump sky properties
        back = bkg.back()
        rms = bkg.rms()
        hdumain = fits.PrimaryHDU(back, header=header)
        hdubk = fits.ImageHDU(back)
        hdurms = fits.ImageHDU(rms)
        hdulist = fits.HDUList([hdumain, hdubk, hdurms])
        hdulist.writeto(output + "/skyprop.fits", clobber=True)

    #extracting sources at nsigma
    thresh = nsig * bkg.globalrms
    segmap = np.zeros((header["NAXIS1"], header["NAXIS2"]))
    objects, segmap = sep.extract(data,
                                  thresh,
                                  segmentation_map=True,
                                  minarea=minarea,
                                  clean=clean,
                                  mask=badmask)
    print "Extracted {} objects... ".format(len(objects))

    if (spectra):
        if not os.path.exists(outspec):
            os.makedirs(outspec)

    if ((check) | (spectra)):
        #create a detection mask alla cubex
        srcmask = np.zeros((1, data.shape[0], data.shape[1]))
        nbj = 1
        print('Generating spectra...')
        #loop over detections
        for obj in objects:
            #init mask
            tmpmask = np.zeros((data.shape[0], data.shape[1]), dtype=np.bool)
            tmpmask3d = np.zeros((1, data.shape[0], data.shape[1]),
                                 dtype=np.bool)
            #fill this mask
            sep.mask_ellipse(tmpmask,
                             obj['x'],
                             obj['y'],
                             obj['a'],
                             obj['b'],
                             obj['theta'],
                             r=2)
            tmpmask3d[0, :, :] = tmpmask[:, :]
            srcmask = srcmask + tmpmask3d * nbj
            if (spectra):
                savename = "{}/id{}.fits".format(outspec, nbj)
                utl.cube2spec(cube,
                              obj['x'],
                              obj['y'],
                              None,
                              write=savename,
                              shape='mask',
                              helio=helio,
                              mask=tmpmask3d,
                              tovac=True)
            #go to next
            nbj = nbj + 1

    if (check):
        print 'Dumping source mask...'
        hdumain = fits.PrimaryHDU(srcmask, header=header)
        hdubk = fits.ImageHDU(srcmask)
        hdulist = fits.HDUList([hdumain, hdubk])
        hdulist.writeto(output + "/source.fits", clobber=True)

        print 'Dumping segmentation map'
        hdumain = fits.PrimaryHDU(segmap, header=header)
        hdubk = fits.ImageHDU(segmap)
        hdulist = fits.HDUList([hdumain, hdubk])
        hdulist.writeto(output + "/segmap.fits", clobber=True)

    #write source catalogue
    print 'Writing catalogue..'
    cols = fits.ColDefs(objects)
    tbhdu = fits.BinTableHDU.from_columns(cols)
    tbhdu.writeto(output + '/catalogue.fits', clobber=True)

    print 'All done'
    return objects
Example #21
0
def make_binary_mask(img,
                     w,
                     segmap,
                     radius=10.0,
                     threshold=0.01,
                     gaia=True,
                     factor_b=1.2,
                     sep_objcat=None,
                     sep_mag=18.0,
                     sep_zp=27.0,
                     sep_blowup=15,
                     show_fig=True):
    '''Make binary mask for a given segmentation map. 
    We convolve the segmentation map using a Gaussian kernal to expand the size of mask.

    Parameters:
    ----------
    img: 2-D numpy array, image data
    w: wcs of the input image
    segmap: 2-D numpy array, segmentation map given by `extract_obj()`
    radius: float, the width of Gaussian kernel
    threshold: float, it can change the size of mask. Lower threshold, larger mask.

    Returns:
    -------
    binary_mask: 2-D numpy boolean array.
    '''

    # Remove the central object
    seg_nocen = imtools.seg_remove_cen_obj(segmap)
    seg_conv = copy.deepcopy(seg_nocen)
    seg_conv[seg_nocen > 0] = 1

    # Convolve the image with a Gaussian kernel with the width of 10 pixel
    # This is actually pretty slow, because the image is very large.
    seg_conv = convolve(seg_conv.astype('float'), Gaussian2DKernel(radius))
    seg_mask = seg_conv >= threshold

    if sep_objcat is not None:
        t = Table(sep_objcat)
        cen_inx = segmap[int(img.shape[0] / 2.), int(img.shape[1] / 2.)] - 1
        cen_obj = sep_objcat[cen_inx]
        t.remove_row(cen_inx)
        t.sort('flux')
        t.reverse()
        bright_objs = t[sep_zp - 2.5 * np.log10(t['flux']) < sep_mag]
        print('The number of bright objects: ', len(bright_objs))
        for skyobj in bright_objs:
            sep.mask_ellipse(seg_mask,
                             skyobj['x'],
                             skyobj['y'],
                             skyobj['a'],
                             skyobj['b'],
                             skyobj['theta'],
                             r=sep_blowup)
    if gaia is False:
        if show_fig:
            from .display import display_single, IMG_CMAP, SEG_CMAP
            display_single(seg_mask.astype(int), cmap=SEG_CMAP)
        return seg_mask
    else:
        # Combine this mask with Gaia star mask
        gaia_mask = imtools.gaia_star_mask(img,
                                           w,
                                           gaia_bright=18,
                                           factor_f=10000,
                                           factor_b=factor_b)[1].astype('bool')
        # If gaia mask overlaps with the center of target galaxy:
        #if gaia_mask[int(img.shape[0] / 2.), int(img.shape[1] / 2.)] is True:
        from scipy.ndimage import measurements
        lw, num = measurements.label(gaia_mask)
        indx = lw[int(img.shape[0] / 2.), int(img.shape[1] / 2.)]
        gaia_mask[lw == indx] = False

        if show_fig:
            from .display import display_single, IMG_CMAP, SEG_CMAP
            display_single((seg_mask + gaia_mask).astype(int), cmap=SEG_CMAP)

        binary_mask = seg_mask + gaia_mask
        return binary_mask
Example #22
0
def findsources(image,cube,check=False,output='./',spectra=False,helio=0,nsig=2.,
                minarea=10.,regmask=None,clean=True,outspec='Spectra'):

    """      

    Take a detection image (collapse of a cube), or median 
    of an RGB, or whatever you want (but aligned to the cube)
    and run sourceextractor 

   
    Use SEP utilities http://sep.readthedocs.org/en/stable/

    image   -> fits file of image to process
    check   -> if true write a bunch of check mages
    output  -> where to dump the output
    cube    -> the cube used to extract spectra
    spectra -> if True, extract spectra in VACUUM wave!!
    helio   -> pass additional heliocentric correction
    nsig    -> number of skyrms used for source id 
    minarea -> minimum area for extraction 
    regmask -> ds9 region file (image) of regions to be masked before extraction [e.g. edges]
    clean   -> clean souces 
    outspec -> where to store output spectra 

    """

    import sep
    from astropy.io import fits
    import numpy as np
    import os
    from mypython.ifu import muse_utils as utl
    from mypython.fits import pyregmask as msk

    #open image
    img=fits.open(image)
    header=img[0].header
    try:
        #this is ok for narrow band images 
        data=img[1].data
    except:
        #white cubex images
        data=img[0].data
    data=data.byteswap(True).newbyteorder()
    #close fits
    img.close()

    #create bad pixel mask
    if(regmask):
        Mask=msk.PyMask(header["NAXIS1"],header["NAXIS2"],regmask)
        for ii in range(Mask.nreg):
            Mask.fillmask(ii)
            if(ii == 0):
                badmask=Mask.mask
            else:
                badmask+=Mask.mask
            badmask=1.*badmask
    else:
        badmask=np.zeros((header["NAXIS1"],header["NAXIS2"]))

    if(check):
        print('Dumping badmask')
        hdumain  = fits.PrimaryHDU(badmask,header=header)
        hdulist = fits.HDUList([hdumain])
        hdulist.writeto(output+"/badmask.fits",clobber=True)
    
    #check background level, but do not subtract it
    print 'Checking background levels'
    bkg = sep.Background(data,mask=badmask)    
    print 'Residual background level ', bkg.globalback
    print 'Residual background rms ', bkg.globalrms

    if(check):
        print 'Dumping sky...'
        #dump sky properties
        back = bkg.back() 
        rms = bkg.rms()  
        hdumain  = fits.PrimaryHDU(back,header=header)
        hdubk  = fits.ImageHDU(back)
        hdurms  = fits.ImageHDU(rms)
        hdulist = fits.HDUList([hdumain,hdubk,hdurms])
        hdulist.writeto(output+"/skyprop.fits",clobber=True)

    #extracting sources at nsigma
    thresh = nsig * bkg.globalrms
    segmap = np.zeros((header["NAXIS1"],header["NAXIS2"]))
    objects,segmap=sep.extract(data,thresh,segmentation_map=True,
                               minarea=minarea,clean=clean,mask=badmask)
    print "Extracted {} objects... ".format(len(objects))
    
    if(spectra):
        if not os.path.exists(outspec):
            os.makedirs(outspec)

    if((check) | (spectra)):
        #create a detection mask alla cubex
        srcmask=np.zeros((1,data.shape[0],data.shape[1]))
        nbj=1
        print('Generating spectra...')
        #loop over detections
        for obj in objects:
            #init mask
            tmpmask=np.zeros((data.shape[0],data.shape[1]),dtype=np.bool)
            tmpmask3d=np.zeros((1,data.shape[0],data.shape[1]),dtype=np.bool)
            #fill this mask
            sep.mask_ellipse(tmpmask,obj['x'],obj['y'],obj['a'],obj['b'],obj['theta'],r=2)
            tmpmask3d[0,:,:]=tmpmask[:,:]
            srcmask=srcmask+tmpmask3d*nbj
            if(spectra):
                savename="{}/id{}.fits".format(outspec,nbj)
                utl.cube2spec(cube,obj['x'],obj['y'],None,write=savename,
                              shape='mask',helio=helio,mask=tmpmask3d,tovac=True)
            #go to next
            nbj=nbj+1

    if(check):
        print 'Dumping source mask...'
        hdumain  = fits.PrimaryHDU(srcmask,header=header)
        hdubk  = fits.ImageHDU(srcmask)
        hdulist = fits.HDUList([hdumain,hdubk])
        hdulist.writeto(output+"/source.fits",clobber=True)
        
        print 'Dumping segmentation map'
        hdumain  = fits.PrimaryHDU(segmap,header=header)
        hdubk  = fits.ImageHDU(segmap)
        hdulist = fits.HDUList([hdumain,hdubk])
        hdulist.writeto(output+"/segmap.fits",clobber=True)
    

    #write source catalogue
    print 'Writing catalogue..'
    cols = fits.ColDefs(objects)
    tbhdu = fits.BinTableHDU.from_columns(cols)
    tbhdu.writeto(output+'/catalogue.fits',clobber=True)

    print 'All done'
    return objects
Example #23
0
def sourcephot(catalogue,image,segmap,detection,instrument='MUSE',dxp=0.,dyp=0.,
               noise=[False],zpab=False, kn=2.5, circap=1.0):

    """ 

    Get a source catalogue from findsources and a fits image with ZP
    and compute magnitudes in that filter 

    catalogue -> source cat from findsources
    image     -> fits image with ZP in header
    segmap    -> fits of segmentation map 
    detection -> the detection image, used to compute Kron radius 

    instrument -> if not MUSE, map positions from detection to image

    dxp,dyp    -> shifts in pixel of image to register MUSE and image astrometry   
   
    noise      -> if set to a noise model, use equation noise[0]*noise[1]*npix**noise[2]
                  to compute the error

    zpab  -> if ZPAB (zeropoint AB) not stored in header, must be supplied

    kn   -> factor to be used when scaling Kron apertures [sextractor default 2.5]
  
    circap -> radius in arcsec for aperture photmetry to be used when Kron aperture fails 

    """  

    from astropy.io import fits
    import numpy as np
    import sep
    import matplotlib.pyplot as plt
    from astropy.table import Table
    from astropy import wcs 


    #grab root name 
    rname=((image.split('/')[-1]).split('.fits'))[0]
    print ('Working on {}'.format(rname))

    #open the catalogue/fits 
    cat=fits.open(catalogue)
    img=fits.open(image)
    seg=fits.open(segmap)
    det=fits.open(detection)

    #grab reference wcs from detection image 
    wref=wcs.WCS(det[0].header)
    psref=wref.pixel_scale_matrix[1,1]*3600.
    print ('Reference pixel size {}'.format(psref))


    #if not handling MUSE, special cases for format of data
    if('MUSE' not in instrument):
        #handle instrument cases
        if('LRIS' in instrument):
            #data 
            imgdata=img[1].data
            #place holder for varaince as will use noise model below
            vardata=imgdata*0+1
            vardata=vardata.byteswap(True).newbyteorder()
            #grab wcs image
            wimg=wcs.WCS(img[1].header)
            psimg=wimg.pixel_scale_matrix[1,1]*3600.
            #store the ZP 
            if(zpab):
                img[0].header['ZPAB']=zpab
        else:
            print 'Instrument not supported!!'
            exit()
    else:
        #for muse, keep eveything the same
        imgdata=img[0].data
        vardata=img[1].data
        psimg=psref

    #grab flux and var
    dataflx=np.nan_to_num(imgdata.byteswap(True).newbyteorder())
    datavar=np.nan_to_num(vardata.byteswap(True).newbyteorder())
    #grab detection and seg mask 
    detflx=np.nan_to_num(det[0].data.byteswap(True).newbyteorder())
    #go back to 1d
    segmask=(np.nan_to_num(seg[0].data.byteswap(True).newbyteorder()))[0,:,:]

    #if needed, map the segmap to new image with transformation
    if('MUSE' not in instrument):
        #allocate space for transformed segmentation map
        segmasktrans=np.zeros(dataflx.shape)
        print "Remapping segmentation map to new image..."

        #loop over original segmap and map to trasformed one
        #Just use nearest pixel, and keep only 1 when multiple choices 
        for xx in range(segmask.shape[0]):
            for yy in range(segmask.shape[1]):
                #go to world
                radec=wref.wcs_pix2world([[yy,xx]],0)
                #back to new instrument pixel 
                newxy=wimg.wcs_world2pix(radec,0)
                #apply shift to register WCS
                newxy[0][1]=newxy[0][1]+dyp
                newxy[0][0]=newxy[0][0]+dxp
                segmasktrans[newxy[0][1],newxy[0][0]]=segmask[xx,yy]
                
                #grow buffer as needed by individual instruments
                #This accounts for resampling to finer pixel size
                if('LRIS' in instrument):
                    segmasktrans[newxy[0][1]+1,newxy[0][0]+1]=segmask[xx,yy]
                    segmasktrans[newxy[0][1]-1,newxy[0][0]-1]=segmask[xx,yy]
                    segmasktrans[newxy[0][1]+1,newxy[0][0]-1]=segmask[xx,yy]
                    segmasktrans[newxy[0][1]-1,newxy[0][0]+1]=segmask[xx,yy]
                    segmasktrans[newxy[0][1]+1,newxy[0][0]]=segmask[xx,yy]
                    segmasktrans[newxy[0][1]-1,newxy[0][0]]=segmask[xx,yy]
                    segmasktrans[newxy[0][1],newxy[0][0]-1]=segmask[xx,yy]
                    segmasktrans[newxy[0][1],newxy[0][0]+1]=segmask[xx,yy]
                 
        #dump the transformed segmap for checking 
        hdumain  = fits.PrimaryHDU(segmasktrans,header=img[1].header)
        hdulist = fits.HDUList(hdumain)
        hdulist.writeto("{}_segremap.fits".format(rname),clobber=True)
    else:
        #no transformation needed
        segmasktrans=segmask

    #source to extract
    nsrc=len(cat[1].data)
    print('Extract photometry for {} sources'.format(nsrc))
    phot = Table(names=('ID', 'MAGAP', 'MAGAP_ERR','FXAP', 'FXAP_ERR', 
                        'RAD', 'MAGSEG', 'MAGSEG_ERR', 'FXSEG', 'FXSEG_ERR','ZP'), 
                 dtype=('i4','f4','f4','f4','f4','f4','f4','f4','f4','f4','f4'))
    
   
    #create check aperture mask 
    checkaperture=np.zeros(dataflx.shape)
    print('Computing photometry for objects...')

    #loop over each source
    for idobj in range(nsrc):
        
        #########
        #Find positions etc and transform as appropriate
        #########
                
        #extract MUSE source paramaters 
        x= cat[1].data['x'][idobj]
        y= cat[1].data['y'][idobj]
        a= cat[1].data['a'][idobj]
        b= cat[1].data['b'][idobj]
        theta= cat[1].data['theta'][idobj]

        #compute kron radius on MUSE detection image 
        #Kron rad in units of a,b
        tmpdata=np.copy(detflx)
        tmpmask=np.copy(segmask)
        #mask all other sources to avoid overlaps but keep desired one
        pixels=np.where(tmpmask == idobj+1) 
        tmpmask[pixels]=0

        #compute kron radius [pixel of reference image]
        kronrad, flg = sep.kron_radius(tmpdata,x,y,a,b,theta,6.0,mask=tmpmask)

        #plt.imshow(np.log10(tmpdata+1),origin='low')
        #plt.show()
        #exit()

        #now check if size is sensible in units of MUSE data 
        rmin = 2.0  #MUSE pix 
        use_circle = kronrad * np.sqrt(a*b) < rmin
      
        #use circular aperture of 2" in muse pixel unit
        rcircap = circap/psref
        
        #now use info to compute photometry and apply 
        #spatial transformation if needed
        if('MUSE' not in instrument):
            #map centre of aperture - +1 reference
            #go to world
            radec=wref.wcs_pix2world([[x,y]],1)
            #back to new instrument pixel 
            newxy=wimg.wcs_world2pix(radec,1)
            #apply shift to register WCS
            xphot=newxy[0][0]+dxp
            yphot=newxy[0][1]+dyp
                      
            #scale radii to new pixel size 
            rminphot=rcircap*psref/psimg
            aphot=a*psref/psimg
            bphot=b*psref/psimg
            #Kron radius in units of a,b

        else:
            #for muse, transfer to same units
            xphot=x
            yphot=y
            rminphot=rcircap
            aphot=a
            bphot=b     
            
        #####
        #Compute local sky 
        #####
        skyreg=kn*kronrad*np.sqrt(aphot*bphot)+15
        cutskymask=segmasktrans[yphot-skyreg:yphot+skyreg,xphot-skyreg:xphot+skyreg]
        cutskydata=dataflx[yphot-skyreg:yphot+skyreg,xphot-skyreg:xphot+skyreg]
        skymedian=np.nan_to_num(np.median(cutskydata[np.where(cutskymask < 1.0)]))

        #print skymedian    
        #plt.imshow(cutskymask,origin='low')
        #plt.show()
        #if(idobj > 30):
        #    exit()


        #########
        #Now grab the Kron mag computed using detection image
        #########
   
        #mask all other objects to avoid blending   
        tmpdata=np.copy(dataflx)
        #apply local sky subtraction 
        tmpdata=tmpdata-skymedian
        tmpvar=np.copy(datavar)
        tmpmask=np.copy(segmasktrans)
        pixels=np.where(tmpmask == idobj+1) 
        tmpmask[pixels]=0

        #plt.imshow(tmpmask,origin='low')
        #plt.show()
        #exit()

        #circular aperture
        if(use_circle):        
           
            #flux in circular aperture
            flux_kron, err, flg = sep.sum_circle(tmpdata,xphot,yphot,rminphot,mask=tmpmask)
            #propagate variance
            fluxvar, err, flg = sep.sum_circle(tmpvar,xphot,yphot,rminphot,mask=tmpmask)
            #store Rused in arcsec
            rused=rminphot*psimg

            #update check aperture
            tmpcheckaper=np.zeros(dataflx.shape,dtype=bool)
            sep.mask_ellipse(tmpcheckaper,xphot,yphot,1.,1.,0.,r=rminphot)
            checkaperture=checkaperture+tmpcheckaper*(idobj+1)

        #kron apertures 
        else:
            #kron flux 
            flux_kron, err, flg = sep.sum_ellipse(tmpdata,xphot, yphot, aphot, bphot, theta, kn*kronrad,
                                                  mask=tmpmask)            
            #propagate variance 
            fluxvar, err, flg = sep.sum_ellipse(tmpvar,xphot,yphot, aphot, bphot, theta, kn*kronrad,
                                                mask=tmpmask)
            #translate in radius
            rused=kn*kronrad*psimg*np.sqrt(aphot*bphot)

            #update check aperture
            tmpcheckaper=np.zeros(dataflx.shape,dtype=bool)
            sep.mask_ellipse(tmpcheckaper,xphot,yphot,aphot,bphot,theta,r=kn*kronrad)
            checkaperture=checkaperture+tmpcheckaper*(idobj+1)

        #compute error for aperture
        if(noise[0]):
            #use model 
            appix=np.where(tmpcheckaper > 0)
            errflux_kron=noise[0]*noise[1]*len(appix[0])**noise[2]
        else:
            #propagate variance 
            errflux_kron=np.sqrt(fluxvar)

        #go to mag 
        if(flux_kron > 0):
            mag_aper=-2.5*np.log10(flux_kron)+img[0].header['ZPAB']
            errmg_aper=2.5*np.log10(1.+errflux_kron/flux_kron)
        else:
            mag_aper=99.0
            errmg_aper=99.0
        
        #find out if non detections
        if(errflux_kron >= flux_kron):
            errmg_aper=9
            mag_aper=-2.5*np.log10(2.*errflux_kron)+img[0].header['ZPAB']
          
        #######
        #grab the photometry in the segmentation map 
        #####

        #This may not work well for other instruments 
        #if images are not well aligned
        pixels=np.where(segmasktrans == idobj+1) 
        #add flux in pixels
        tmpdata=np.copy(dataflx)
        #apply sky sub
        tmpdata=tmpdata-skymedian
        flux_seg=np.sum(tmpdata[pixels])
        
        #compute noise from model or adding variance 
        if(noise[0]):
            #from model 
            errfx_seg=noise[0]*noise[1]*len(pixels[0])**noise[2]
        else:
            #add variance in pixels to compute error
            errfx_seg=np.sqrt(np.sum(datavar[pixels]))
  
        #go to mag with calibrations 
        if(flux_seg > 0):
            mag_seg=-2.5*np.log10(flux_seg)+img[0].header['ZPAB']
            errmg_seg=2.5*np.log10(1.+errfx_seg/flux_seg)     
        else:
            mag_seg=99.0
            errmg_seg=99.0
      
        #find out if non detections
        if(errfx_seg >= flux_seg):
            errmg_seg=9
            mag_seg=-2.5*np.log10(2.*errfx_seg)+img[0].header['ZPAB']
        
        #stash by id
        phot.add_row((idobj+1,mag_aper,errmg_aper,flux_kron,errflux_kron,rused,mag_seg,errmg_seg,
                      flux_seg,errfx_seg,img[0].header['ZPAB']))

    #dump the aperture check image 
    hdumain  = fits.PrimaryHDU(checkaperture,header=img[1].header)
    hdulist = fits.HDUList(hdumain)
    hdulist.writeto("{}_aper.fits".format(rname),clobber=True)

    #close
    cat.close()
    img.close()
    seg.close()
    det.close()

    return phot
Example #24
0
def evaluate_sky(img, sigma=1.5, radius=10, pixel_scale=0.168, central_mask_radius=7.0, 
                 threshold=0.005, deblend_cont=0.001, deblend_nthresh=20, 
                 clean_param=1.0, show_fig=True, show_hist=True, f_factor=None):
    '''Evaluate the mean sky value.
    Parameters:
    ----------
    img: 2-D numpy array, the input image
    show_fig: bool. If True, it will show you the masked sky image.
    show_hist: bool. If True, it will show you the histogram of the sky value.
    
    Returns:
    -------
    median: median of background pixels, in original unit
    std: standard deviation, in original unit
    '''
    import sep
    import copy 
    from slug.imutils import extract_obj, make_binary_mask
    from astropy.convolution import convolve, Gaussian2DKernel
    b = 35  # Box size
    f = 5   # Filter width

    bkg = sep.Background(img, maskthresh=0, bw=b, bh=b, fw=f, fh=f)
    # first time
    objects, segmap = extract_obj(img - bkg.globalback, b=35, f=5, sigma=sigma,
                                    minarea=20, pixel_scale=pixel_scale,
                                    deblend_nthresh=deblend_nthresh, deblend_cont=deblend_cont,
                                    clean_param=clean_param, show_fig=False)
    
    seg_sky = copy.deepcopy(segmap)
    seg_sky[segmap > 0] = 1
    seg_sky = seg_sky.astype(bool)
    # Blow up the mask
    for obj in objects:
        sep.mask_ellipse(seg_sky, obj['x'], obj['y'], obj['a'], obj['b'], obj['theta'], r=radius)
    bkg_mask_1 = seg_sky
    
    data = copy.deepcopy(img - bkg.globalback)
    data[bkg_mask_1 == 1] = 0

    # Second time
    obj_lthre, seg_lthre = extract_obj(data, b=35, f=5, sigma=sigma + 1,
                                       minarea=5, pixel_scale=pixel_scale,
                                       deblend_nthresh=deblend_nthresh, deblend_cont=deblend_cont,
                                       clean_param=clean_param, show_fig=False)
    seg_sky = copy.deepcopy(seg_lthre)
    seg_sky[seg_lthre > 0] = 1
    seg_sky = seg_sky.astype(bool)
    # Blow up the mask
    for obj in obj_lthre:
        sep.mask_ellipse(seg_sky, obj['x'], obj['y'], obj['a'], obj['b'], obj['theta'], r=radius/2)
    bkg_mask_2 = seg_sky
    
    bkg_mask = (bkg_mask_1 + bkg_mask_2).astype(bool)
    
    cen_obj = objects[segmap[int(bkg_mask.shape[0] / 2.), int(bkg_mask.shape[1] / 2.)] - 1]
    fraction_radius = sep.flux_radius(img, cen_obj['x'], cen_obj['y'], 10*cen_obj['a'], 0.5)[0]
    
    ba = np.divide(cen_obj['b'], cen_obj['a'])
    
    if fraction_radius < int(bkg_mask.shape[0] / 8.):
        sep.mask_ellipse(bkg_mask, cen_obj['x'], cen_obj['y'], fraction_radius, fraction_radius * ba,
                        cen_obj['theta'], r=central_mask_radius)
    elif fraction_radius < int(bkg_mask.shape[0] / 4.):
        sep.mask_ellipse(bkg_mask, cen_obj['x'], cen_obj['y'], fraction_radius, fraction_radius * ba,
                        cen_obj['theta'], r=1.2)
    
    # Estimate sky from histogram of binned image
    import copy
    from scipy import stats
    from astropy.stats import sigma_clip
    from astropy.nddata import block_reduce
    data = copy.deepcopy(img)
    data[bkg_mask] = np.nan
    if f_factor is None:
        f_factor = round(6 / pixel_scale)
    rebin = block_reduce(data, f_factor)
    sample = rebin.flatten()
    if show_fig:
        display_single(rebin)
        plt.savefig('./{}-bkg.png'.format(np.random.randint(1000)), dpi=100, bbox_inches='tight')
    
    temp = sigma_clip(sample)
    sample = temp.data[~temp.mask]

    kde = stats.gaussian_kde(sample)
    print(f_factor)
    mean = np.nanmean(sample) / f_factor**2
    median = np.nanmedian(sample) / f_factor**2
    std = np.nanstd(sample, ddof=1) / f_factor / np.sqrt(len(sample))

    xlim = np.std(sample, ddof=1) * 7
    x = np.linspace(-xlim + np.median(sample), xlim + np.median(sample), 100)
    offset = x[np.argmax(kde.evaluate(x))] / f_factor**2
    
    print('mean', mean)
    print('median', median)
    print('std', std)

    bkg_global = sep.Background(img, 
                                mask=bkg_mask, maskthresh=0,
                                bw=f_factor, bh=f_factor, 
                                fw=f_factor/2, fh=f_factor/2)
    print("#SEP sky: Mean Sky / RMS Sky = %10.5f / %10.5f" % (bkg_global.globalback, bkg_global.globalrms))

    if show_hist:
        fig, ax = plt.subplots(figsize=(8,6))

        ax.plot(x, kde.evaluate(x), linestyle='dashed', c='black', lw=2,
                label='KDE')
        ax.hist(sample, bins=x, normed=1);
        ax.legend(loc='best', frameon=False, fontsize=20)

        ax.set_xlabel('Pixel Value', fontsize=20)
        ax.set_ylabel('Normed Number', fontsize=20)
        ax.tick_params(labelsize=20)
        ylim = ax.get_ylim()
        ax.text(-0.1 * f_factor + np.median(sample), 0.9 * (ylim[1] - ylim[0]) + ylim[0], 
                r'$\mathrm{offset}='+str(round(offset, 6))+'$', fontsize=20)
        ax.text(-0.1 * f_factor + np.median(sample), 0.8 * (ylim[1] - ylim[0]) + ylim[0],
                r'$\mathrm{median}='+str(round(median, 6))+'$', fontsize=20)
        ax.text(-0.1 * f_factor + np.median(sample), 0.7 * (ylim[1] - ylim[0]) + ylim[0],
                r'$\mathrm{std}='+str(round(std, 6))+'$', fontsize=20)
        plt.vlines(np.median(sample), 0, ylim[1], linestyle='--')

    return median, std, sample
Example #25
0
# 2.Break the data into detections. Generate a catalogue of them. Get the propertie of each catalogue.
thresh = eval(dic['thresh1']) * bkg.globalrms
objs = sep.extract(DataSubtracted, thresh, minarea=eval(dic['MinDetectPixel1']), conv=KernelDict[dic['ConvKernel1']], deblend_nthresh=eval(dic['NDeblendThreshold1']), deblend_cont=eval(dic['DeblendCont1']))
print 'Objects list created successfully.'
# ps:sep.extract() function will return an structured array of the properties for each object. To list each property, type objs['thresh'].
# Delete the central galaxy from the array. The central galaxy is difined to be the object that is closest to the center of the image.(Useful to SDSS Montage image, need some update in the future for images of other origion.)
x = objs['x'].copy()
y = objs['y'].copy()
# ??_??
k = (y[:]-height)**2 + (x[:]-width)**2
objs = delete(objs,argmin(k))

# 3.Generate mask.
mask = zeros(shape(data), dtype = uint8)# mask_ellipse's argument must be in ubyte (uint8) format.
sep.mask_ellipse(mask, objs['x'], objs['y'], objs['a'], objs['b'], objs['theta'], eval(dic['MaskScalingFactor1']))
# Masked pixels are 1, and unmasked pixels are 0.
sep.mask_ellipse(mask,eval(dic['GalaxyCenterY']),eval(dic['GalaxyCenterX']),1,1,0,7)
# Add central mask.
print 'Mask image created successfully.'

# 4.Compute an masked data array.
DataMasked  = data - 5000*mask
#ObjIndex = nonzero(mask) # find the index of all the objects.
#for i in range(len(ObjIndex[0])):
#        DataMasked[ObjIndex[0][i],ObjIndex[1][i]] = 0
print 'Masked image created successfully'
sss = '_bw='+dic['BoxWidth1']+'_thr='+dic['thresh1']+'_sf='+dic['MaskScalingFactor1']+'.fits'

# 5. Go through the pipeline for the central subregion if the SubregionHeight is not set to None. 
# Cut a subregion from the original data.
Example #26
0
def findsources(image,cube,check=False,output='./',spectra=False,helio=0.0):

    """      
    Take a detection image (collapse of a cube), or median 
    of an RGB, or whatever you want (but aligned to the cube)
    and run sourceextractor 

    Use SEP utilities http://sep.readthedocs.org/en/v0.4.x/

    image -> fits file of image to process
    check -> if true write a bunch of check mages
    output -> where to dump the output
    cube   -> the cube used to extract spectra
    spectra -> if True, extract spectra
    helio   -> pass additional heliocentric correction

    """

    import sep
    from astropy.io import fits
    import numpy as np
    import os
    from mypython.ifu import muse_utils as utl

    #open image
    img=fits.open(image)
    header=img[0].header
    data=img[1].data
    data=data.byteswap(True).newbyteorder()
    #close fits
    img.close()

    #check bacground level, but do not subtract it
    print 'Checking background levels'
    bkg = sep.Background(data)    
    print 'Residual background level ', bkg.globalback
    print 'Residual background rms ', bkg.globalrms

    if(check):
        print 'Dumping sky...'
        #dump sky properties
        back = bkg.back() 
        rms = bkg.rms()  
        hdumain  = fits.PrimaryHDU(back,header=header)
        hdubk  = fits.ImageHDU(back)
        hdurms  = fits.ImageHDU(rms)
        hdulist = fits.HDUList([hdumain,hdubk,hdurms])
        hdulist.writeto(output+"/skyprop.fits",clobber=True)

    #extracting sources 
    thresh = 2. * bkg.globalrms
    objects = sep.extract(data,thresh, minarea=10, clean=0.0)
    print "Extracted {} objects... ".format(len(objects))
    
    if(spectra):
        if not os.path.exists("Spectra"):
            os.makedirs("Spectra")

    if((check) | (spectra)):
        #create a detection mask
        srcmask=np.zeros((data.shape[0],data.shape[1]))
        nbj=1
        #loop over detections
        for obj in objects:
            #init mask
            tmpmask=np.zeros((data.shape[0],data.shape[1]),dtype=np.bool)
            #fill this mask
            sep.mask_ellipse(tmpmask,obj['x'],obj['y'],obj['a'],obj['b'],obj['theta'],r=2)
            srcmask=srcmask+tmpmask*nbj
            if(spectra):
                savename="Spectra/id{}.fits".format(nbj)
                utl.cube2spec(cube,obj['x'],obj['y'],None,write=savename,
                              shape='mask',helio=helio,mask=tmpmask)
            #go to next
            nbj=nbj+1

    if(check):
        print 'Dumping source mask...'
        hdumain  = fits.PrimaryHDU(srcmask,header=header)
        hdubk  = fits.ImageHDU(srcmask)
        hdulist = fits.HDUList([hdumain,hdubk])
        hdulist.writeto(output+"/source.fits",clobber=True)
        
    #write source catalogue
    print 'Writing catalogue..'
    cols = fits.ColDefs(objects)
    tbhdu = fits.BinTableHDU.from_columns(cols)
    tbhdu.writeto(output+'/catalogue.fits',clobber=True)

    print 'All done'
    return objects