Exemplo n.º 1
0
def iraf_star_finder(data, guess, threshold):

    bg = type('background', (object,), dict(zip(
        ('mean', 'median', 'stddev'),
        sigma_clipped_stats(data[np.isfinite(data)])
    )))

    threshold = (5 * bg.stddev) if threshold is None else threshold

    if not guess is None:

        finder = IRAFStarFinder(threshold, guess)
        stars = finder(data - bg.median)

    else:

        guess = [2]

        while guess.count(guess[-1]) < 3:

            finder = IRAFStarFinder(threshold, guess[-1])
            stars = finder(data - bg.median)

            guess.append(np.round(stars['fwhm'].mean(), 3))

            if guess[-2] != guess[-1]: break

    return stars
Exemplo n.º 2
0
def PSF_IRAF(IMG, results, options):
    """
    Apply the photutils IRAF wrapper to the image to extract a PSF fwhm
    """
    if 'ap_set_psf' in options:
        logging.info('%s: PSF set by user: %.4e' % (options['ap_name'], options['ap_set_psf']))
        return IMG, {'psf fwhm': options['ap_set_psf']}
    elif 'ap_guess_psf' in options:
        logging.info('%s: PSF initialized by user: %.4e' % (options['ap_name'], options['ap_guess_psf']))
        fwhm_guess = options['ap_guess_psf']
    else:
        fwhm_guess = max(1., 1./options['ap_pixscale'])

    edge_mask = np.zeros(IMG.shape, dtype = bool)
    edge_mask[int(IMG.shape[0]/4.):int(3.*IMG.shape[0]/4.),
              int(IMG.shape[1]/4.):int(3.*IMG.shape[1]/4.)] = True
    
    dat = IMG - results['background']
    # photutils wrapper for IRAF star finder
    count = 0
    sources = 0
    psf_iter = deepcopy(psf_guess)
    try:
        while count < 5 and sources < 20:
            iraffind = IRAFStarFinder(fwhm = psf_iter, threshold = 6.*results['background noise'], brightest = 50)
            irafsources = iraffind.find_stars(dat, edge_mask)
            psf_iter = np.median(irafsources['fwhm'])
            if np.median(irafsources['sharpness']) >= 0.95:
                break
            count += 1
            sources = len(irafsources['fwhm'])
    except:
        return IMG, {'psf fwhm': fwhm_guess}
    if len(irafsources) < 5:
        return IMG, {'psf fwhm': fwhm_guess}
    
    if 'ap_doplot' in options and options['ap_doplot']:    
        plt.imshow(np.clip(IMG - results['background'], a_min = 0, a_max = None), origin = 'lower',
                   cmap = 'Greys_r', norm = ImageNormalize(stretch=LogStretch()))
        for i in range(len(irafsources['fwhm'])):
            plt.gca().add_patch(Ellipse((irafsources['xcentroid'][i],irafsources['ycentroid'][i]), 16/options['ap_pixscale'], 16/options['ap_pixscale'],
                                        0, fill = False, linewidth = 0.5, color = 'y'))
        plt.savefig('%sPSF_Stars_%s.jpg' % (options['ap_plotpath'] if 'ap_plotpath' in options else '', options['ap_name']), dpi = 600)
        plt.close()

    psf = np.median(irafsources['fwhm'])
    return IMG, {'psf fwhm': psf, 'auxfile psf': 'psf fwhm: %.3f pix' % psf}
Exemplo n.º 3
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
Exemplo n.º 4
0
    def find_stars(self):

        fwhm = self.settings.image.seeing / self.settings.image.scale
        threshold = self.settings.image.threshold
        background = sigma_clipped_stats(self.hdu.data)[1]
        max_stars = self.settings.image.max_stars

        finder = IRAFStarFinder(threshold, fwhm)
        stars = finder(self.hdu.data - np.median(self.hdu.data))

        if not stars:
            showerror('Error', 'Failed to find stars')
            return

        i = np.argsort(stars['mag'])[:max_stars]
        self.points = list(zip(stars['xcentroid'][i], stars['ycentroid'][i]))

        self.transform_points()

        self.canvas.draw()
def process_file(filename):
    """
    Process FITS file to get desired header info and image statistics
    """
    outstr = ""
    with fits.open(filename) as hdul:
        hdr = hdul[0].header
        if hdr['NAXIS'] == 3:
            im = np.flipud(hdul[0].data[:, :, 0])
        else:
            im = hdul[0].data

        for c in CARDS:
            outstr += f"{hdr[c]},"

        for k, r in REGIONS.items():
            cutout = im[r['y'], r['x']]
            im_mean, im_med, im_std = sigma_clipped_stats(cutout,
                                                          sigma=3,
                                                          maxiters=5)
            outstr += f"{im_mean:.3f},{im_med:.3f},{im_std:.3f},"

        subim = im[REGIONS['Polaris']['y'], REGIONS['Polaris']['x']]
        mean, median, std = sigma_clipped_stats(subim, sigma=3, maxiters=10)
        finder = IRAFStarFinder(fwhm=2.0, threshold=5 * std)
        try:
            sources = finder(subim - median)
            if sources is not None:
                sources.sort(['mag'])
                polaris = sources[0]
                for k in ['mag', 'flux', 'peak', 'xcentroid', 'ycentroid']:
                    outstr += f"{polaris[k]:.3f},"
            else:
                outstr += ",,,,,"
        except:
            outstr += ",,,,,"
        outstr += f"{filename}"

    return outstr
Exemplo n.º 6
0
def get_sources(detection_frame,
                mask=False,
                sigma=5.0,
                mode='DAO',
                fwhm=2.5,
                threshold=None,
                npix=4,
                return_segm_image=False):
    """
    Main method used to identify sources in a detection frame and estimate their position.
    Different modes are available, accesible through the ``mode`` keyword :

    * DAO : uses the :class:`photutils:photutils.DAOStarFinder` method, adapted from DAOPHOT.
    * IRAF : uses the :class:`photutils:photutils.IRAFStarFinder` method, adapted from IRAF.
    * PEAK : uses the :func:`photutils:photutils.find_peaks` method, looking for local peaks above a given threshold.
    * ORB : uses the :func:`ORB:orb.utils.astrometry.detect_stars` method, fitting stars in the frame
    * SEGM : uses the :func:`photutils:photutils.detect_sources` method, segmenting the image.

    The most reliable is SEGM.

    Parameters
    ----------
    detection_frame : 2D :class:`~numpy:numpy.ndarray`
        Map on which the sources should be visible.
    mask : 2D :class:`~numpy:numpy.ndarray` or bool,  Default = False
        (Optional) If passed, only sources inside the mask are detected.
    sigma : float
        (Optional) Signal to Noise of the detections we want to keep. Only used if threshold is None. In this case, the signal and the noise are computed with sigma-clipping on the deteciton frame. Default = 5
    threshold : float or 2D :class:`~numpy:numpy.ndarray` of floats
        (Optional) Threshold above which we consider having a detection. Default is None
    mode : str
        (Optional) One of the detection mode listed above. Dafault = 'DAO'
    fwhm : float
        (Optional) Expected FWHM of the sources. Default : 2.5
    npix : int
        (Optional) Only used by the 'SEGM' method : minimum number of connected pixels with flux above the threshold to make a credible source. Default = 4
    return_segm_image : bool, Default = False
        (Optional) Only used in the 'SEGM' mode. If True, returns the obtained segmentation image.

    Returns
    -------
    sources : :class:`~pandas:pandas.DataFrame`
        A DataFrame where each row represents a detection, with at least the positions named as ``xcentroid``, ``ycentroid`` (WARNING : using astropy convention). The other columns depend on the mode used.

    """
    if mask is False:
        mask = np.ones_like(detection_frame)
    if threshold is None:
        mean, median, std = sigma_clipped_stats(
            detection_frame, sigma=3.0, iters=5,
            mask=~mask.astype(bool))  #On masque la region hors de l'anneau
        threshold = median + sigma * std
    #On detecte sur toute la frame, mais on garde que ce qui est effectivement dans l'anneau
    if mode == 'DAO':
        daofind = DAOStarFinder(fwhm=fwhm, threshold=threshold)
        sources = daofind(detection_frame)
    elif mode == 'IRAF':
        irafind = IRAFStarFinder(threshold=threshold, fwhm=fwhm)
        sources = irafind(detection_frame)
    elif mode == 'PEAK':
        sources = find_peaks(detection_frame, threshold=threshold)
        sources.rename_column('x_peak', 'xcentroid')
        sources.rename_column('y_peak', 'ycentroid')
    elif mode == 'ORB':
        astro = Astrometry(detection_frame, instrument='sitelle')
        path, fwhm_arc = astro.detect_stars(min_star_number=5000,
                                            r_max_coeff=1.,
                                            filter_image=False)
        star_list = astro.load_star_list(path)
        sources = Table([star_list[:, 0], star_list[:, 1]],
                        names=('ycentroid', 'xcentroid'))
    elif mode == 'SEGM':
        logging.info('Detecting')
        segm = detect_sources(detection_frame, threshold, npixels=npix)
        deblend = True
        labels = segm.labels
        if deblend:
            # while labels.shape != (0,):
            #     try:
            #         #logging.info('Deblending')
            #         # fwhm = 3.
            #         # s = fwhm / (2.0 * np.sqrt(2.0 * np.log(2.0)))
            #         # kernel = Gaussian2DKernel(s, x_size = 3, y_size = 3)
            #         # kernel = Box2DKernel(3, mode='integrate')
            #         deblended = deblend_sources(detection_frame, segm, npixels=npix, labels=labels)#, filter_kernel=kernel)
            #         success = True
            #     except ValueError as e:
            #         #warnings.warn('Deblend was not possible.\n %s'%e)
            #         source_id = int(e.args[0].split('"')[1])
            #         id = np.argwhere(labels == source_id)[0,0]
            #         labels = np.concatenate((labels[:id], labels[id+1:]))
            #         success = False
            #     if success is True:
            #         break
            try:
                logging.info('Deblending')
                # fwhm = 3.
                # s = fwhm / (2.0 * np.sqrt(2.0 * np.log(2.0)))
                # kernel = Gaussian2DKernel(s, x_size = 3, y_size = 3)
                # kernel = Box2DKernel(3, mode='integrate')
                deblended = deblend_sources(
                    detection_frame, segm,
                    npixels=npix)  #, filter_kernel=kernel)
            except ValueError as e:
                warnings.warn('Deblend was not possible.\n %s' % e)
                deblended = segm
            logging.info('Retieving properties')
            sources = source_properties(detection_frame, deblended).to_table()
        else:
            deblended = segm
            logging.info('Retieving properties')
            sources = source_properties(detection_frame, deblended).to_table()
        logging.info('Filtering Quantity columns')
        for col in sources.colnames:
            if type(sources[col]) is Quantity:
                sources[col] = sources[col].value
    sources = mask_sources(sources, mask)  # On filtre
    df = sources.to_pandas()
    if return_segm_image:
        return deblended.array, df
    else:
        return df
Exemplo n.º 7
0
    cax = divider.append_axes("right", size="3%", pad=0.05)
    plt.colorbar(im, cax=cax)
    plt.show()

#%%
import numpy as np
import matplotlib.pyplot as plt
from photutils import IRAFStarFinder
from photutils import CircularAperture as CircAp

IRAFfind = IRAFStarFinder(
    fwhm=FWHM,
    threshold=thresh_snr,
    sigma_radius=1.5,
    minsep_fwhm=2.5,  # default values: sigma_radius=1.5, minsep_fwhm=2.5,
    sharplo=0.2,
    sharphi=3.0,  # default values: sharplo=0.5, sharphi=2.0,
    roundlo=0.0,
    roundhi=0.5,  # default values: roundlo=0.0, roundhi=0.2,
    sky=None,
    exclude_border=True)  # default values: sky=None, exclude_border=False)

# The IRAFStarFinder object ("IRAFfind") gets at least one input: the image.
# Then it returns the astropy table which contains the aperture photometry results:
IRAFfound = IRAFfind(img)

if len(IRAFfound) == 0:
    print('No star founded using IRAFStarFinder')
else:
    # Use the object "found" for aperture photometry:
    print(len(IRAFfound), 'stars founded')
Exemplo n.º 8
0
def extract_sources(image,
                    noise_threshold,
                    fwhm,
                    star_finder='DAO',
                    image_var=None,
                    background_subtraction=True,
                    write_to=None,
                    debug=True):
    """Extract sources from an image with a StarFinder routine.

    Long description...

    Args:
        image (np.ndarray or str):
            Image array or the name of a file containing the image array.
        noise_threshold (float):
            Multiple of the uncertainty/ standard deviation of the image.
        fwhm (float):
            Expected full width at half maximum (FWHM) of the sources in units of pixels.
        star_finder (str, optional):
            Choose whether the 'DAO' or 'IRAF' StarFinder implementations from photutils shall be used. Default is
            'DAO'.
        image_var (float or str):
            Variance of the image used for the StarFinder threshold (=noise_threshold * sqrt(image_var)). If not
            provided, the code extracts this value from sigma clipped stats. If provided as str-type, the code tries to
            use this as a key to the FITS file HDU list.
        background_subtraction (bool, optional):
            Let the StarFinder consider the background subtraction. Set False for ignoring background flux. Default is
            `True`.
        write_to (str, optional):
            If provided as a str, the list of identified sources is saved to this file.
        debug (bool, optional):
            Show debugging information. Default is `False`.

    Returns:
        sources (astropy.table.Table): Table of identified sources, None if no
            sources are detected.
    """

    # Set logger level
    if debug:
        logger.setLevel('DEBUG')

    # Input parameters
    if isinstance(image, np.ndarray):
        filename = 'current cube'
    elif isinstance(image, str):
        logger.info(
            "The argument image '{}' is interpreted as file name.".format(
                image))
        filename = image
        image = fits.getdata(filename)
        image = image.squeeze()
    else:
        raise SpecklepyTypeError('extract_sources()',
                                 argname='image',
                                 argtype=type(image),
                                 expected='np.ndarray or str')

    # Prepare noise statistics
    mean, median, std = sigma_clipped_stats(image, sigma=3.0)
    logger.info(
        f"Noise statistics for {filename}:\n\tMean = {mean:.3}\n\tMedian = {median:.3}\n\tStdDev = {std:.3}"
    )

    # Set detection threshold
    if image_var is None:
        threshold = noise_threshold * std
    else:
        if isinstance(image_var, str):
            # Try to load variance extension from file
            image_var = fits.getdata(filename, image_var)
            image_var = np.mean(image_var)
        threshold = noise_threshold * np.sqrt(image_var)

    # Set sky background
    if background_subtraction:
        logger.info(f"Considering mean sky background of {mean}")
        sky = mean
    else:
        sky = 0.0

    # Instantiate StarFinder object
    if not isinstance(star_finder, str):
        raise SpecklepyTypeError('extract_sources',
                                 argname='starfinder',
                                 argtype=type(star_finder),
                                 expected='str')
    if 'dao' in star_finder.lower():
        star_finder = DAOStarFinder(fwhm=fwhm, threshold=threshold, sky=sky)
    elif 'iraf' in star_finder.lower():
        star_finder = IRAFStarFinder(fwhm=fwhm, threshold=threshold, sky=sky)
    else:
        raise SpecklepyValueError('extract_sources',
                                  argname='star_finder',
                                  argvalue=star_finder,
                                  expected="'DAO' or 'IRAF")

    # Find stars
    logger.info("Extracting sources...")
    sources = star_finder(image)

    # Reformatting sources table
    sources.sort('flux', reverse=True)
    sources.rename_column('xcentroid', 'x')
    sources.rename_column('ycentroid', 'y')
    sources.keep_columns(['x', 'y', 'flux'])

    # Add terminal output
    logger.info(f"Extracted {len(sources)} sources")
    logger.debug(sources)

    # Save sources table to file, if requested
    if write_to is not None:
        logger.info("Writing list of sources to file {}".format(write_to))
        sources.write(write_to, format='ascii.fixed_width', overwrite=True)

    return sources
Exemplo n.º 9
0
def Star_Mask_IRAF(IMG, results, options):
    """Masking routine which identifies stars and masks a region around them.

    An IRAF star finder wrapper (from photutils) is applied to the
    image and then the identified sources are masked form the image.
    The size of the mask depends on the flux in the source roughly as
    sqrt(log(f)), thus an inverse of a Gaussian.

    See Also
    --------
    ap_savemask : bool, default False
      indicates if the mask should be saved after fitting

    Notes
    ----------
    :References:
    - 'background'
    - 'background noise'
    - 'psf fwhm'
    - 'center'
    - 'mask' (optional)

    Returns
    -------
    IMG : ndarray
      Unaltered galaxy image

    results : dict
      .. code-block:: python

        {'mask':  # 2d mask image with boolean datatype (ndarray)
        }

    """

    fwhm = results["psf fwhm"]
    use_center = results["center"]

    # Find scale of bounding box for galaxy. Stars will only be found within this box
    smaj = results["fit R"][-1] if "fit R" in results else max(IMG.shape)
    xbox = int(1.5 * smaj)
    ybox = int(1.5 * smaj)
    xbounds = [
        max(0, int(use_center["x"] - xbox)),
        min(int(use_center["x"] + xbox), IMG.shape[1]),
    ]
    ybounds = [
        max(0, int(use_center["y"] - ybox)),
        min(int(use_center["y"] + ybox), IMG.shape[0]),
    ]

    # Run photutils wrapper for IRAF star finder
    dat = IMG - results["background"]
    iraffind = IRAFStarFinder(fwhm=fwhm,
                              threshold=10.0 * results["background noise"],
                              brightest=50)
    irafsources = iraffind(dat[ybounds[0]:ybounds[1], xbounds[0]:xbounds[1]])
    mask = np.zeros(IMG.shape, dtype=bool)
    # Mask star pixels and area around proportionate to their total flux
    XX, YY = np.meshgrid(range(IMG.shape[0]),
                         range(IMG.shape[1]),
                         indexing="ij")
    if irafsources:
        for x, y, f in zip(irafsources["xcentroid"], irafsources["ycentroid"],
                           irafsources["flux"]):
            if (np.sqrt((x - (xbounds[1] - xbounds[0]) / 2)**2 +
                        (y - (ybounds[1] - ybounds[0]) / 2)**2) <
                    10 * results["psf fwhm"]):
                continue
            # compute distance of every pixel to the identified star
            R = np.sqrt((YY - (x + xbounds[0]))**2 + (XX -
                                                      (y + ybounds[0]))**2)
            # Compute the flux of the star
            # f = np.sum(IMG[R < 10*fwhm])
            # Compute radius to reach background noise level, assuming gaussian
            Rstar = (fwhm / 2.355) * np.sqrt(2 * np.log(f / (np.sqrt(
                2 * np.pi * fwhm / 2.355) * results["background noise"])))
            mask[R < Rstar] = True

    if "mask" in results:
        mask = np.logical_or(mask, results["mask"])

    # Plot star mask for diagnostic purposes
    if "ap_doplot" in options and options["ap_doplot"]:
        plt.imshow(
            np.clip(
                dat[ybounds[0]:ybounds[1], xbounds[0]:xbounds[1]],
                a_min=0,
                a_max=None,
            ),
            origin="lower",
            cmap="Greys_r",
            norm=ImageNormalize(stretch=LogStretch()),
        )
        dat = mask.astype(float)[ybounds[0]:ybounds[1], xbounds[0]:xbounds[1]]
        dat[dat == 0] = np.nan
        plt.imshow(dat, origin="lower", cmap="Reds_r", alpha=0.7)
        plt.savefig(
            "%smask_%s.jpg" % (
                options["ap_plotpath"] if "ap_plotpath" in options else "",
                options["ap_name"],
            ),
            dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
        )
        plt.close()

    return IMG, {"mask": mask}
Exemplo n.º 10
0
def jwst_camera_fpa_data(data_dir,
                         pattern,
                         standardized_data_dir,
                         parameters,
                         overwrite_source_extraction=False):
    """Generate standardized focal plane alignment (fpa) data
       based on JWST camera image.
    """

    save_plot = parameters['save_plot']

    file_list = glob.glob(os.path.join(data_dir, '*{}'.format(pattern)))

    if len(file_list) == 0:
        raise RuntimeError('No data found')

    file_list.sort()
    for f in file_list:

        plt.close('all')

        print()
        print('Data directory: {}'.format(data_dir))
        print('Image being processed: {}'.format(f))

        im = datamodels.open(f)
        if hasattr(im, 'data') is False:
            im.data = fits.getdata(f)
            #im.dq    = np.zeros(im.data.shape)

        header_info = OrderedDict()

        for attribute in 'telescope'.split():
            header_info[attribute] = getattr(im.meta, attribute)

        # observations
        for attribute in 'date time visit_number visit_id visit_group activity_id program_number'.split(
        ):
            header_info['observation_{}'.format(attribute)] = getattr(
                im.meta.observation, attribute)

        header_info['epoch_isot'] = '{}T{}'.format(
            header_info['observation_date'], header_info['observation_time'])

        #  instrument
        for attribute in 'name filter pupil detector'.split():
            header_info['instrument_{}'.format(attribute)] = getattr(
                im.meta.instrument, attribute)

        # subarray
        for attribute in 'name'.split():
            header_info['subarray_{}'.format(attribute)] = getattr(
                im.meta.subarray, attribute)

        # aperture
        for attribute in 'name position_angle pps_name'.split():
            try:
                value = getattr(im.meta.aperture, attribute)
            except AttributeError:
                value = None

            header_info['aperture_{}'.format(attribute)] = value

        header_info['INSTRUME'] = header_info['instrument_name']
        header_info['SIAFAPER'] = header_info['aperture_name']

        instrument_name = getattr(im.meta.instrument, 'name')
        instrument_detector = getattr(im.meta.instrument, 'detector')
        instrument_filter = getattr(im.meta.instrument, 'filter')

        # temporary solution, this should come from populated aperture attributes
        #if header_info['subarray_name'] == 'FULL':
        #    master_apertures = pysiaf.read.read_siaf_detector_layout()
        #    if header_info['instrument_name'].lower() in ['niriss', 'miri']:
        #        header_info['SIAFAPER'] = master_apertures['AperName'][np.where(master_apertures['InstrName']==header_info['instrument_name'])[0][0]]
        #    elif header_info['instrument_name'].lower() in ['fgs']:
        #        header_info['SIAFAPER'] = 'FGS{}_FULL'.format(header_info['instrument_detector'][-1])
        #    elif header_info['instrument_name'].lower() in ['nircam']:
        #        header_info['SIAFAPER'] = header_info['aperture_name']
        #else:
        #    sys.exit('Only FULL arrays are currently supported.')

        # target
        for attribute in 'ra dec catalog_name proposer_name'.split():
            header_info['target_{}'.format(attribute)] = getattr(
                im.meta.target, attribute)

        # pointing
        for attribute in 'ra_v1 dec_v1 pa_v3'.split():
            try:
                value = getattr(im.meta.pointing, attribute)
            except AttributeError:
                value = None
            header_info['pointing_{}'.format(attribute)] = value

        # add HST style keywords
        header_info['PROGRAM_VISIT'] = '{}_{}'.format(
            header_info['observation_program_number'],
            header_info['observation_visit_id'])
        header_info['PROPOSID'] = header_info['observation_program_number']
        header_info['DATE-OBS'] = header_info['observation_date']
        header_info['TELESCOP'] = header_info['telescope']
        header_info['INSTRUME'] = header_info['instrument_name']
        try:
            header_info['APERTURE'] = header_info['SIAFAPER']
        except KeyError:
            header_info['APERTURE'] = None
        header_info['CHIP'] = 0

        # TBD: Need to remove making yet another directory
        #extracted_sources_dir = os.path.join(standardized_data_dir, 'extraction')
        #if os.path.isdir(extracted_sources_dir) is False:
        #    os.makedirs(extracted_sources_dir)
        extracted_sources_file = os.path.join(
            standardized_data_dir,  #extracted_sources_dir,
            '{}_extracted_sources.fits'.format(
                os.path.basename(f).split('.')[0]))

        mask_extreme_slope_values = False
        parameters['maximum_slope_value'] = 1000.

        # Check if extracted_sources_file exists, or overwrite_source_extraction is set to True
        if (not os.path.isfile(extracted_sources_file)) or (
                overwrite_source_extraction):
            data = copy.deepcopy(im.data)
            #dq = copy.deepcopy(im.dq)

            # Convert image data to counts per second
            photmjsr = getattr(im.meta.photometry, 'conversion_megajanskys')
            data_cps = data / photmjsr

            if mask_extreme_slope_values:
                # clean up extreme slope values
                bad_index = np.where(
                    np.abs(data) > parameters['maximum_slope_value'])
                data[bad_index] = 0.
                dq[bad_index] = -1

            bkgrms = MADStdBackgroundRMS()
            mmm_bkg = MMMBackground()
            bgrms = bkgrms(data_cps)
            bgavg = mmm_bkg(data_cps)

            # Default parameters that generally works for NIRCam/NIRISS images
            sigma_factor = 10
            round_lo, round_hi = 0.0, 0.6
            sharp_lo, sharp_hi = 0.3, 1.4
            fwhm_lo, fwhm_hi = 1.0, 20.0
            fwhm = 2.0
            minsep_fwhm = 7  # NOTE: minsep_fwhm>5 to reject artifacts around saturated stars
            flux_percent_lo, flux_percent_hi = 10, 99

            # if 'sharp_lo' in parameters:
            #    sharp_lo = parameters['sharp_lo']

            ###
            ### TBD1: Relocate params below to config parts/files
            ###
            # Use different criteria for selecting good stars
            if parameters['nominalpsf']:
                # If using Nominal PSF models
                if instrument_name == 'NIRISS':
                    #fwhm_lo, fwhm_hi = 1.0, 2.0
                    sharp_lo, sharp_hi = 0.6, 1.4
                elif instrument_name == 'FGS':
                    #fwhm_lo, fwhm_hi = 1.0, 1.4
                    sharp_lo, sharp_hi = 0.6, 1.4
                elif instrument_name == 'NIRCAM':
                    sharp_lo, sharp_hi = 0.6, 1.4
                elif instrument_name == 'MIRI':
                    sharp_lo, sharp_hi = 0.8, 1.0
                    fwhm_lo, fwhm_hi = 1.5, 2.2
                    sigma_factor = 3
                elif instrument_name == 'NIRSPEC':
                    sharp_lo, sharp_hi = 0.6, 0.8
                    round_lo, round_hi = 0.0, 0.3
                    fwhm_lo, fwhm_hi = 1.0, 1.75
            else:
                ###
                ### For OTE commissioning, tweak the params below after finding
                ### the correct ranges by runnin the photometry notebook.
                ###

                # If using Commissioning (non-phased) PSF models
                if instrument_name == 'NIRISS':
                    sharp_lo, sharp_hi = 0.6, 1.4
                    fwhm_lo, fwhm_hi = 1.4, 2.4

################################################################################
################################################################################
################################################################################

                elif instrument_name == 'FGS':
                    sigma_factor = 10
                    minsep_fwhm = 2.5
                    sharp_lo, sharp_hi = 0.45, 0.7
                    round_lo, round_hi = 0.0, 0.3
                    flux_percent_lo, flux_percent_hi = 2, 99
                    fwhm = 4

################################################################################
################################################################################
################################################################################

# Below works well for F200W and F356W images

                elif instrument_name == 'NIRCAM':
                    sigma_factor = 3
                    minsep_fwhm = 2.5
                    sharp_lo, sharp_hi = 0.5, 0.7
                    round_lo, round_hi = 0.0, 0.2
                    flux_percent_lo, flux_percent_hi = 2, 99
                    if 'F200W' in instrument_filter:
                        fwhm = 10
                    elif 'F356W' in instrument_filter:
                        fwhm = 8
                    elif 'F090W' in instrument_filter:
                        fwhm = 5.5
                    elif 'F277W' in instrument_filter:
                        fwhm = 6.5
                    else:
                        fwhm = 3


################################################################################
################################################################################
################################################################################

                elif instrument_name == 'MIRI':
                    sharl_lo, sharp_hi = 0.5, 1.0
                    fwhm_lo, fwhm_hi = 1.5, 2.2
                    sigma_factor = 3
                elif instrument_name == 'NIRSPEC':
                    sharp_lo, sharp_hi = 0.5, 0.8
                    round_lo, round_hi = 0.0, 0.3
                    fwhm_lo, fwhm_hi = 1.0, 1.75

            # Use IRAFStarFinder for source detection
            iraffind = IRAFStarFinder(threshold=sigma_factor * bgrms + bgavg,
                                      fwhm=fwhm,
                                      minsep_fwhm=minsep_fwhm,
                                      roundlo=round_lo,
                                      roundhi=round_hi,
                                      sharplo=sharp_lo,
                                      sharphi=sharp_hi)

            # Create default mask with all False values
            datamask = np.zeros(
                data_cps.shape,
                dtype=bool)  # This creates an array with all False

            # Mask the left (for NRS1) and right regions (for NRS2) for NIRSpec
            if instrument_detector == 'NRS1':
                datamask[:, :1023] = True  # Mask everything on the left side
            elif instrument_detector == 'NRS2':
                datamask[:, 1024:] = True  # Mask everything on the right side

            iraf_extracted_sources = iraffind(data_cps, mask=datamask)

            # Perform some basic filtering

            # Remove sources based on flux percentile
            # 10-99% works well for filtering out too faint or saturated sources
            flux_min = np.percentile(iraf_extracted_sources['flux'],
                                     flux_percent_lo)
            flux_max = np.percentile(iraf_extracted_sources['flux'],
                                     flux_percent_hi)
            iraf_extracted_sources.remove_rows(
                np.where(iraf_extracted_sources['flux'] < flux_min))
            iraf_extracted_sources.remove_rows(
                np.where(iraf_extracted_sources['flux'] > flux_max))

            # Also remove sources based on fwhm
            ###
            ### Don't use below for now - 2/23/2022 (Don't use it unless we get lots of bad sources)
            ###
            #iraf_extracted_sources.remove_rows(np.where(iraf_extracted_sources['fwhm']<fwhm_lo))
            #iraf_extracted_sources.remove_rows(np.where(iraf_extracted_sources['fwhm']>fwhm_hi))

            # Now improve the positions by re-running centroiding algorithm if necessary.
            # NOTE: For now, re-centroiding will be turned off

            ###
            ### TBD2: Add re-centroiding algorithm adopted from Paul here
            ###
            #xarr = sources_masked['xcentroid']
            #yarr = sources_masked['ycentroid']
            #newx, newy = centroid_sources(data_cps, xarr, yarr, box_size=5, centroid_func=centroid_2dg)
            #coords = np.column_stack((newx, newy))
            #srcaper = CircularAnnulus(coords, r_in=1, r_out=3)
            #srcaper_masks = srcaper.to_mask(method='center')
            #satflag = np.zeros((len(newx),),dtype=int)
            #i = 0
            #for mask in srcaper_masks:
            #    srcaper_dq = mask.multiply(dqarr)
            #    srcaper_dq_1d = srcaper_dq[mask.data>0]
            #    badpix = np.logical_and(srcaper_dq_1d>2, srcaper_dq_1d<7)
            #    reallybad = np.where(srcaper_dq_1d==1)
            #    if ((len(srcaper_dq_1d[badpix]) > 1) or (len(srcaper_dq_1d[reallybad]) > 0)):
            #        satflag[i] = 1
            #        i =+1
            #goodx = newx[np.where(satflag==0)]
            #goody = newy[np.where(satflag==0)]
            #print('Number of sources before removing saturated or bad pixels: ', len(xarr))
            #print('Number of sources without saturated or bad pixels: ', len(goodx))
            #print(' ')
            #coords = np.column_stack((goodx,goody))

            print('Number of extracted sources after filtering: {} sources'.
                  format(len(iraf_extracted_sources)))

            if parameters['use_epsf'] is True:
                size = 25
                hsize = (size - 1) / 2
                x = iraf_extracted_sources['xcentroid']
                y = iraf_extracted_sources['ycentroid']
                mask = ((x > hsize) & (x < (data_cps.shape[1] - 1 - hsize)) &
                        (y > hsize) & (y < (data_cps.shape[0] - 1 - hsize)))
                stars_tbl = Table()
                stars_tbl['x'] = x[mask]
                stars_tbl['y'] = y[mask]
                print('Using {} stars to build epsf'.format(len(stars_tbl)))

                data_cps_bkgsub = data_cps.copy()
                data_cps_bkgsub -= bgavg
                nddata = NDData(data=data_cps_bkgsub)
                stars = extract_stars(nddata, stars_tbl, size=size)

                #
                # Figure - PSF stars
                #
                nrows = 10
                ncols = 10
                fig, ax = plt.subplots(nrows=nrows,
                                       ncols=ncols,
                                       figsize=(20, 20),
                                       squeeze=True)
                ax = ax.ravel()
                for i in range(nrows * ncols):
                    if i <= len(stars) - 1:
                        norm = simple_norm(stars[i], 'log', percent=99.)
                        ax[i].imshow(stars[i],
                                     norm=norm,
                                     origin='lower',
                                     cmap='viridis')
                plt.title('{} sample stars for epsf'.format(
                    header_info['APERTURE']))
                if save_plot:
                    figname = os.path.join(
                        extracted_sources_dir, '{}_sample_psfs.pdf'.format(
                            os.path.basename(f).split('.')[0]))
                    plt.savefig(figname)
                if parameters['show_extracted_sources']:
                    plt.show()

                #
                # Timer for ePSF construction
                #
                tic = time.perf_counter()
                epsf_builder = EPSFBuilder(oversampling=4,
                                           maxiters=3,
                                           progress_bar=False)
                print("Building ePSF ...")
                epsf, fitted_stars = epsf_builder(stars)
                toc = time.perf_counter()
                print("Time elapsed for building ePSF:", toc - tic)

                #
                # Figure - ePSF plot
                #
                norm_epsf = simple_norm(epsf.data, 'log', percent=99.)
                plt.figure()
                plt.imshow(epsf.data,
                           norm=norm_epsf,
                           origin='lower',
                           cmap='viridis')
                plt.colorbar()
                plt.title('{} epsf using {} stars'.format(
                    header_info['APERTURE'], len(stars_tbl)))
                if save_plot:
                    figname = os.path.join(
                        extracted_sources_dir, '{}_epsf.pdf'.format(
                            os.path.basename(f).split('.')[0]))
                    plt.savefig(figname)
                if parameters['show_extracted_sources']:
                    plt.show()

                daogroup = DAOGroup(5.0 * 2.0)
                psf_model = epsf.copy()

                tic = time.perf_counter()
                photometry = IterativelySubtractedPSFPhotometry(
                    finder=iraffind,
                    group_maker=daogroup,
                    bkg_estimator=mmm_bkg,
                    psf_model=psf_model,
                    fitter=LevMarLSQFitter(),
                    niters=1,
                    fitshape=(11, 11),
                    aperture_radius=5)
                print('Performing source extraction and photometry ...')
                epsf_extracted_sources = photometry(data_cps)
                toc = time.perf_counter()
                print("Time elapsed for PSF photometry:", toc - tic)
                print('Final source extraction with epsf: {} sources'.format(
                    len(epsf_extracted_sources)))

                epsf_extracted_sources['xcentroid'] = epsf_extracted_sources[
                    'x_fit']
                epsf_extracted_sources['ycentroid'] = epsf_extracted_sources[
                    'y_fit']
                extracted_sources = epsf_extracted_sources
                extracted_sources.write(extracted_sources_file, overwrite=True)

                norm = simple_norm(data_cps, 'sqrt', percent=99.)
                diff = photometry.get_residual_image()
                plt.figure()
                ax1 = plt.subplot(1, 2, 1)
                plt.xlabel("X [pix]")
                plt.ylabel("Y [pix]")
                ax1.imshow(data_cps, norm=norm, cmap='Greys')
                ax2 = plt.subplot(1, 2, 2)
                plt.xlabel("X [pix]")
                plt.ylabel("Y [pix]")
                ax2.imshow(diff, norm=norm, cmap='Greys')
                plt.title('PSF subtracted image for {}'.format(
                    os.path.basename(f)))
                if save_plot:
                    figname = os.path.join(
                        extracted_sources_dir,
                        '{}_psfsubtracted_image.pdf'.format(
                            os.path.basename(f).split('.')[0]))
                    plt.savefig(figname)
                if parameters['show_psfsubtracted_image']:
                    plt.show()

            else:

                extracted_sources = iraf_extracted_sources
                extracted_sources.write(extracted_sources_file, overwrite=True)

            positions = np.transpose((extracted_sources['xcentroid'],
                                      extracted_sources['ycentroid']))
            apertures = CircularAperture(positions, r=10)
            norm = simple_norm(data_cps, 'sqrt', percent=99.)

            plt.figure(figsize=(12, 12))
            plt.xlabel("X [pix]")
            plt.ylabel("Y [pix]")
            plt.imshow(data_cps, norm=norm, cmap='Greys', origin='lower')
            apertures.plot(color='blue', lw=1.5, alpha=0.5)
            title_string = '{}: {} selected sources'.format(
                os.path.basename(f), len(extracted_sources))
            plt.title(title_string)
            plt.tight_layout()
            if save_plot:
                figname = os.path.join(
                    standardized_data_dir, '{}_extracted_sources.pdf'.format(
                        os.path.basename(f).split('.')[0]))
                plt.savefig(figname)
            if parameters['show_extracted_sources']:
                plt.show()
            plt.close()

        else:
            extracted_sources = Table.read(extracted_sources_file)

        print('Extracted {} sources from {}'.format(len(extracted_sources), f))
        impose_positive_flux = True
        if impose_positive_flux and parameters['use_epsf']:
            extracted_sources.remove_rows(
                np.where(extracted_sources['flux_fit'] < 0)[0])
            print('Only {} sources have positve flux'.format(
                len(extracted_sources)))

        astrometry_uncertainty_mas = 5

        if len(extracted_sources) > 0:
            # Cal images are in DMS coordinates which correspond to the SIAF Science (SCI) frame
            extracted_sources['x_SCI'], extracted_sources[
                'y_SCI'] = extracted_sources['xcentroid'], extracted_sources[
                    'ycentroid']

            # For now, astrometric uncertainty defaults to 5 mas for each source.
            extracted_sources['sigma_x_mas'] = np.ones(
                len(extracted_sources)) * astrometry_uncertainty_mas
            extracted_sources['sigma_y_mas'] = np.ones(
                len(extracted_sources)) * astrometry_uncertainty_mas

        # transfer info to astropy table header
        for key, value in header_info.items():
            extracted_sources.meta[key] = value

        extracted_sources.meta['DATAFILE'] = os.path.basename(f)
        extracted_sources.meta['DATAPATH'] = os.path.dirname(f)
        extracted_sources.meta['EPOCH'] = header_info['epoch_isot']

        out_file = os.path.join(
            standardized_data_dir, '{}_FPA_data.fits'.format(
                extracted_sources.meta['DATAFILE'].split('.')[0]))

        print('Writing {}'.format(out_file))
        with warnings.catch_warnings():
            warnings.simplefilter('ignore', AstropyWarning, append=True)
            extracted_sources.write(out_file, overwrite=True)

    return im
Exemplo n.º 11
0
# %%
#util.RERUN_ALL_CACHED = True
cache_dir = Path('./cached_results/')
out_dir = Path('./04_comparison')
base_dir = Path('./gc_images').absolute()
image_cut = np.s_[170:, 100:]
fitshape = 19

# %%
img_combined = getdata(base_dir / 'ssa_deep.fits').astype(
    np.float64)[image_cut]

# %%
epsf_finder = IRAFStarFinder(threshold=20,
                             fwhm=4.5,
                             minsep_fwhm=10,
                             peakmax=10_000,
                             exclude_border=True,
                             brightest=300)
epsf_sources = epsf_finder(img_combined)

# %%
plt.figure()
plt.imshow(img_combined, norm=LogNorm())
plt.plot(epsf_sources['xcentroid'], epsf_sources['ycentroid'], 'rx')

# %%
epsf_sources['x'] = epsf_sources['xcentroid']
epsf_sources['y'] = epsf_sources['ycentroid']

epsf_stars = extract_stars(NDData(img_combined),
Exemplo n.º 12
0
def PSF_IRAF(IMG, results, options):
    """PSF routine which identifies stars and averages the FWHM.

    Uses the photutil IRAF wrapper to identify stars in the image and
    computes the average FWHM.

    Parameters
    -----------------
    ap_guess_psf : float, default None
      Initialization value for the PSF calculation in pixels. If not
      given, AutoProf will default with a guess of 1/*ap_pixscale*

    ap_set_psf : float, default None
      force AutoProf to use this PSF value (in pixels) instead of
      calculating its own.

    Notes
    ----------
    :References:
    - 'background' (float)
    - 'background noise' (float)

    Returns
    -------
    IMG : ndarray
      Unaltered galaxy image

    results : dict
      .. code-block:: python

        {'psf fwhm':  # FWHM of the average PSF for the image
        }

    """
    if "ap_set_psf" in options:
        logging.info("%s: PSF set by user: %.4e" %
                     (options["ap_name"], options["ap_set_psf"]))
        return IMG, {"psf fwhm": options["ap_set_psf"]}
    elif "ap_guess_psf" in options:
        logging.info("%s: PSF initialized by user: %.4e" %
                     (options["ap_name"], options["ap_guess_psf"]))
        fwhm_guess = options["ap_guess_psf"]
    else:
        fwhm_guess = max(1.0, 1.0 / options["ap_pixscale"])

    edge_mask = np.zeros(IMG.shape, dtype=bool)
    edge_mask[int(IMG.shape[0] / 5.0):int(4.0 * IMG.shape[0] / 5.0),
              int(IMG.shape[1] / 5.0):int(4.0 * IMG.shape[1] / 5.0), ] = True

    dat = IMG - results["background"]
    # photutils wrapper for IRAF star finder
    count = 0
    sources = 0
    psf_iter = deepcopy(psf_guess)
    try:
        while count < 5 and sources < 20:
            iraffind = IRAFStarFinder(fwhm=psf_iter,
                                      threshold=6.0 *
                                      results["background noise"],
                                      brightest=50)
            irafsources = iraffind.find_stars(dat, edge_mask)
            psf_iter = np.median(irafsources["fwhm"])
            if np.median(irafsources["sharpness"]) >= 0.95:
                break
            count += 1
            sources = len(irafsources["fwhm"])
    except:
        return IMG, {"psf fwhm": fwhm_guess}
    if len(irafsources) < 5:
        return IMG, {"psf fwhm": fwhm_guess}

    psf = np.median(irafsources["fwhm"])

    if "ap_doplot" in options and options["ap_doplot"]:
        Plot_PSF_Stars(
            IMG,
            irafsources["xcentroid"],
            irafsources["ycentroid"],
            irafsources["fwhm"],
            psf,
            results,
            options,
        )

    return IMG, {"psf fwhm": psf, "auxfile psf": "psf fwhm: %.3f pix" % psf}
Exemplo n.º 13
0
def Star_Mask_IRAF(IMG, results, options):
    """
    Idenitfy the location of stars in the image and create a mask around
    each star of pixels to be avoided in further processing.
    """

    fwhm = results['psf fwhm']
    use_center = results['center']

    # Find scale of bounding box for galaxy. Stars will only be found within this box
    smaj = results['fit R'][-1] if 'fit R' in results else max(IMG.shape)
    xbox = int(1.5 * smaj)
    ybox = int(1.5 * smaj)
    xbounds = [
        max(0, int(use_center['x'] - xbox)),
        min(int(use_center['x'] + xbox), IMG.shape[1])
    ]
    ybounds = [
        max(0, int(use_center['y'] - ybox)),
        min(int(use_center['y'] + ybox), IMG.shape[0])
    ]

    # Run photutils wrapper for IRAF star finder
    iraffind = IRAFStarFinder(fwhm=2 * fwhm,
                              threshold=10. * results['background noise'],
                              brightest=50)
    irafsources = iraffind(
        (IMG - results['background'])[ybounds[0]:ybounds[1],
                                      xbounds[0]:xbounds[1]])
    mask = np.zeros(IMG.shape, dtype=bool)
    # Mask star pixels and area around proportionate to their total flux
    XX, YY = np.meshgrid(range(IMG.shape[0]),
                         range(IMG.shape[1]),
                         indexing='ij')
    if irafsources:
        for x, y, f in zip(irafsources['xcentroid'], irafsources['ycentroid'],
                           irafsources['flux']):
            if np.sqrt(
                (x - (xbounds[1] - xbounds[0]) / 2)**2 +
                (y -
                 (ybounds[1] - ybounds[0]) / 2)**2) < 10 * results['psf fwhm']:
                continue
            # compute distance of every pixel to the identified star
            R = np.sqrt((XX - (x + xbounds[0]))**2 + (YY -
                                                      (y + ybounds[0]))**2)
            # Compute the flux of the star
            #f = np.sum(IMG[R < 10*fwhm])
            # Compute radius to reach background noise level, assuming gaussian
            Rstar = (fwhm / 2.355) * np.sqrt(2 * np.log(
                f / (np.sqrt(2 * np.pi * fwhm / 2.355) *
                     results['background noise'])))  # fixme double check
            mask[R < Rstar] = True

    # Include user defined mask if any
    if 'mask_file' in options and not options['ap_mask_file'] is None:
        mask = np.logical_or(mask, Read_Image(mask_file, options))

    # Plot star mask for diagnostic purposes
    if 'doplot' in options and options['ap_doplot']:
        plt.imshow(np.clip(
            IMG[max(0, int(use_center['y'] - smaj * 1.2)
                    ):min(IMG.shape[0], int(use_center['y'] + smaj * 1.2)),
                max(0, int(use_center['x'] - smaj * 1.2)
                    ):min(IMG.shape[1], int(use_center['x'] + smaj * 1.2))],
            a_min=0,
            a_max=None),
                   origin='lower',
                   cmap='Greys_r',
                   norm=ImageNormalize(stretch=LogStretch()))
        dat = np.logical_or(mask, overflow_mask).astype(float)[
            max(0, int(use_center['y'] - smaj *
                       1.2)):min(IMG.shape[0], int(use_center['y'] +
                                                   smaj * 1.2)),
            max(0, int(use_center['x'] - smaj *
                       1.2)):min(IMG.shape[1], int(use_center['x'] +
                                                   smaj * 1.2))]
        dat[dat == 0] = np.nan
        plt.imshow(dat, origin='lower', cmap='Reds_r', alpha=0.7)
        plt.savefig('%sMask_%s.jpg' %
                    (options['ap_plotpath'] if 'plotpath' in options else '',
                     options['ap_name']))
        plt.close()

    return IMG, {'mask': np.logical_or(mask, overflow_mask)}
Exemplo n.º 14
0
import numpy as np
from skimage import io

import matplotlib.pyplot as plt

from photutils import DAOStarFinder, IRAFStarFinder
from astropy.stats import mad_std
from photutils import aperture_photometry, CircularAperture

img = io.imread("/home/mot/data/saliance/exp3/frame.png", as_grey=True)

img = 1 - img

bkg_sigma = mad_std(img)
daofind = IRAFStarFinder(
    fwhm=24.,
    threshold=1. * bkg_sigma,
)
sources = daofind.find_stars(img)
print(sources)

positions = (sources['xcentroid'], sources['ycentroid'])
apertures = CircularAperture(positions, r=8.)
phot_table = aperture_photometry(img, apertures)
print(phot_table)

plt.imshow(img, cmap="gray")
apertures.plot(color='blue', lw=1.5, alpha=0.5)

plt.show()