Exemple #1
0
def photometry_on_directory(directory_with_images,
                            object_of_interest,
                            star_locs,
                            aperture_rad,
                            inner_annulus,
                            outer_annulus,
                            max_adu,
                            star_ids,
                            camera,
                            bjd_coords=None,
                            observatory_location=None,
                            fwhm_by_fit=True):
    """
    Perform aperture photometry on a directory of images.

    Parameters
    ----------

    directory_with_images : str
        Folder containing the images on which to do photometry. Photometry
        will only be done on images that contain the ``object_of_interest``.

    object_of_interest : str
        Name of the object of interest. The only files on which photometry
        will be done are those whose header contains the keyword ``OBJECT``
        whose value is ``object_of_interest``.

    star_locs : tuple of numpy array
        The first entry in the tuple should be the right ascension of the
        sources, in degrees. The second should be the declination of
        the sources, in degrees.

    aperture_rad : int
        Radius of the aperture to use when performing photometry.

    inner_annulus : int
        Inner radius of annulus to use in for performing local sky
        subtraction.

    outer_annulus : int
        Outer radius of annulus to use in for performing local sky
        subtraction.

    max_adu : int
        Maximum allowed pixel value before a source is considered
        saturated.

    star_ids : array-like
        Unique identifier for each source in ``star_locs``.

    camera : `stellarphot.Camera` object
        Camera object which has gain, read noise and dark current set.

    gain : float
        Gain, in electrons/ADU, of the camera that took the image. The gain
        is used in calculating the instrumental magnitude.

    read_noise : float
        Read noise of the camera in electrons. Used in the CCD equation
        to calculate error.

    dark_current : float
        Dark current, in electron/sec. Used in the CCD equation
        to calculate error.
    """
    ifc = ImageFileCollection(directory_with_images)
    phots = []
    missing_stars = []
    for a_ccd, fname in ifc.ccds(object=object_of_interest, return_fname=True):
        print('on image ', fname)
        try:
            # Convert RA/Dec to pixel coordinates for this image
            pix_coords = a_ccd.wcs.all_world2pix(star_locs[0], star_locs[1], 0)
        except AttributeError:
            print('    ....SKIPPING THIS IMAGE, NO WCS')
            continue

        xs, ys = pix_coords

        # Remove anything that is too close to the edges/out of frame
        padding = 3 * aperture_rad
        out_of_bounds = ((xs < padding) | (xs > (a_ccd.shape[1] - padding)) |
                         (ys < padding) | (ys > (a_ccd.shape[0] - padding)))
        in_bounds = ~out_of_bounds

        # Find centroids of each region around star that is in_bounds
        xs_in = xs[in_bounds]
        ys_in = ys[in_bounds]
        print('    ...finding centroids')
        try:
            xcen, ycen = centroid_sources(a_ccd.data,
                                          xs_in,
                                          ys_in,
                                          box_size=2 * aperture_rad + 1)
        except NoOverlapError:
            print('    ....SKIPPING THIS IMAGE, CENTROID FAILED')
            continue

        # Calculate offset between centroid in this image and the positions
        # based on input RA/Dec. Later we will set the magnitude of those with
        # large differences to an invalid value (maybe).
        center_diff = np.sqrt((xs_in - xcen)**2 + (ys_in - ycen)**2)

        # FWHM is typically 5-6 pixels. The center really shouldn't move
        # by more than that.
        too_much_shift = center_diff > 6

        xcen[too_much_shift] = xs_in[too_much_shift]
        ycen[too_much_shift] = ys_in[too_much_shift]

        # Set up apertures and annuli based on the centroids in this image.
        ap_locs = np.array([xcen, ycen]).T
        aps = CircularAperture(ap_locs, r=aperture_rad)

        anuls = CircularAnnulus(ap_locs, inner_annulus, outer_annulus)

        # Set any clearly bad values to NaN
        a_ccd.data[a_ccd.data > max_adu] = np.nan
        print('    ...doing photometry')
        # Do the photometry...
        pho = aperture_photometry(a_ccd.data, (aps, anuls),
                                  mask=a_ccd.mask,
                                  method='center')

        # We may have some stars we did not do photometry for because
        # those stars were out of bounds.
        # Add the ones we missed to the list of missing
        missed = star_ids[out_of_bounds]
        missing_stars.append(missed)

        # Add all the extra goodies to the table
        print('    ...adding extra columns')
        add_to_photometry_table(pho,
                                a_ccd,
                                anuls,
                                aps,
                                fname=fname,
                                star_ids=star_ids[in_bounds],
                                camera=camera,
                                bjd_coords=bjd_coords,
                                observatory_location=observatory_location,
                                fwhm_by_fit=fwhm_by_fit)

        # And add the final table to the list of tables
        phots.append(pho)

    # ### Combine all of the individual photometry tables into one

    all_phot = vstack(phots)

    # ### Eliminate any stars that are missing from one or more images
    #
    # This makes life a little easier later...

    uniques = set()
    for miss in missing_stars:
        uniques.update(set(miss))

    actually_bad = sorted([u for u in uniques if u in all_phot['star_id']])
    len(uniques), len(actually_bad)

    all_phot.add_index('star_id')
    if actually_bad:
        bad_rows = all_phot.loc_indices[actually_bad]
        try:
            bad_rows = list(bad_rows)
        except TypeError:
            bad_rows = [bad_rows]
        all_phot.remove_indices('star_id')
        all_phot.remove_rows(sorted(bad_rows))

    all_phot.remove_indices('star_id')

    gain = camera.gain

    noise = calculate_noise(gain=camera.gain,
                            read_noise=camera.read_noise,
                            dark_current_per_sec=camera.dark_current,
                            flux=all_phot['aperture_net_flux'],
                            sky_per_pix=all_phot['sky_per_pix_avg'].value,
                            aperture_area=all_phot['aperture_area'],
                            annulus_area=all_phot['annulus_area'],
                            exposure=all_phot['exposure'].value,
                            include_digitization=False)

    snr = gain * all_phot['aperture_net_flux'] / noise

    all_phot['mag_error'] = 1.085736205 / snr
    all_phot['noise'] = noise
    # AstroImageJ includes a factor of gain in the noise. IMHO it is part of the
    # flux but, for convenience, here it is
    all_phot['noise-aij'] = noise / gain
    all_phot['snr'] = snr

    return all_phot
Exemple #2
0
def create_reg(ra, dec, radius, dir, show_regions):
    os.system('ls -d 0* >> datadirs.txt')
    dirs = [line.rstrip('\n').rstrip('/') for line in open('datadirs.txt')]
    os.system('rm datadirs.txt')
    image = None
    for i in range(len(dirs)):

        try_file = '%s/%s/uvot/image/sw%sum2_sk.img.gz' % (
            str(dir), str(dirs[i]), str(dirs[i]))
        if os.path.isfile(try_file):
            image = fits.open(try_file)
            break

        try_file = '%s/%s/uvot/image/sw%suw2_sk.img.gz' % (
            str(dir), str(dirs[i]), str(dirs[i]))
        if os.path.isfile(try_file):
            image = fits.open(try_file)
            break

        try_file = '%s/%s/uvot/image/sw%suw1_sk.img.gz' % (
            str(dir), str(dirs[i]), str(dirs[i]))
        if os.path.isfile(try_file):
            image = fits.open(try_file)
            break

        try_file = '%s/%s/uvot/image/sw%suuu_sk.img.gz' % (
            str(dir), str(dirs[i]), str(dirs[i]))
        if os.path.isfile(try_file):
            image = fits.open(try_file)
            break

        try_file = '%s/%s/uvot/image/sw%suvv_sk.img.gz' % (
            str(dir), str(dirs[i]), str(dirs[i]))
        if os.path.isfile(try_file):
            image = fits.open(try_file)
            break

        try_file = '%s/%s/uvot/image/sw%subb_sk.img.gz' % (
            str(dir), str(dirs[i]), str(dirs[i]))
        if os.path.isfile(try_file):
            image = fits.open(try_file)
            break

        else:
            pass

    w = WCS(image[1].header)
    img = image[1].data
    y, x = np.indices(np.shape(img))

    # Creating source region

    x_source, y_source = w.world_to_pixel(
        SkyCoord(ra=float(ra), dec=float(dec), unit="deg", frame=FK5))
    new_x_source, new_y_source = centroid_sources(img,
                                                  x_source,
                                                  y_source,
                                                  box_size=21,
                                                  centroid_func=centroid_com)

    with open(dir + '/' + 'source.reg', "w") as text_file:
        text_file.write('fk5;circle(%.6f, %.6f, %.1f") # color=green' %
                        (float(ra), float(dec), np.round(radius[0], 1)))

    # Creating background region
    rho = random.randrange(0, 300, 1)
    phi = random.randrange(0, 360, 1)
    x_0 = int(rho * np.cos(phi / 180 * np.pi)) + img.shape[1] / 2
    y_0 = int(rho * np.sin(phi / 180 * np.pi)) + img.shape[0] / 2

    r_map = np.sqrt((x - x_0)**2 + (y - y_0)**2)
    bkg_reg = r_map < radius[1]
    max_bkg = np.max(img[bkg_reg])
    std_bkg = np.std(img[bkg_reg][img[bkg_reg] != 0])
    median_bkg = np.median(img[bkg_reg][img[bkg_reg] != 0])

    while (max_bkg > 5 *
           (median_bkg + std_bkg)) or (((x_0 - x_source)**2 +
                                        (y_0 - y_source)**2) < radius[1]**2):
        rho = random.randrange(0, 300, 1)
        phi = random.randrange(0, 360, 1)
        x_0 = int(rho * np.cos(phi / 180 * np.pi)) + img.shape[1] / 2
        y_0 = int(rho * np.sin(phi / 180 * np.pi)) + img.shape[0] / 2
        r_map = np.sqrt((x - x_0)**2 + (y - y_0)**2)
        bkg_reg = r_map < radius[1]
        max_bkg = np.max(img[bkg_reg])
        std_bkg = np.std(img[bkg_reg][img[bkg_reg] != 0])
        median_bkg = np.median(img[bkg_reg][img[bkg_reg] != 0])

    bkg_coords = w.pixel_to_world(x_0, y_0)
    image.close()
    with open(dir + '/' + 'bkg.reg', "w") as text_file:
        text_file.write(
            'fk5;circle(%.6f, %.6f, %.1f") # color=green' %
            (bkg_coords.ra.deg, bkg_coords.dec.deg, np.round(radius[1], 1)))
    fig, ax = plt.figure(), plt.subplot(projection=w)
    plot = ax.imshow(img,
                     vmin=0,
                     vmax=8 * (median_bkg + std_bkg),
                     origin='lower')
    plt.colorbar(plot, ax=ax)
    c_b = plt.Circle((x_0, y_0), radius[1], color='red', fill=False)
    c_s = plt.Circle((new_x_source, new_y_source),
                     radius[0],
                     color='red',
                     fill=False)
    ax.add_patch(c_s)
    ax.add_patch(c_b)
    plt.savefig(dir + '/regions.png', bbox_inches='tight')
    if show_regions:
        plt.show()
    plt.close('all')
Exemple #3
0
def ap_an_phot(image, sources, source_ap, sky_ap, delta_ann=3.0, coords='xy',
            centroid=False, show_plot=False, **kargs):
    """Performs circular aperture fotometry on a image, given a table with the
    coordinates (x,y) or (ra,dec) of the sources. Background is estimated from a
    annular aperture and substracted

    Input:
        image:      (str) name of the .fits file with the image
        sources:    table with the Positions of the sources in the image.
        source_ap:  Radius of the circular aperture in pixels
        sky_ap:     inner radius of the annulus to calculate the sky.
        delta_ann:  Width of the annulus to calculate the sky
        centroid:   (Boolean) if True the source position centroid are
                    recalculated.
        sky_coord   (str) type of coordinates to use, either xy or radec.
                    If xy sources table must have 'x' and 'y' cols.
                    If ra dec sources table must to have 'ra' and 'dec' cols.
        show_plot:  (Boolean) If True a plot of the aperture is displayed.
    Output:
        phot_table: Table with the resulting photometry
    """

    data = fits.getdata(image)
    x, y = sources.colnames

    if coords == 'radec':
        sources = SkyCoord(sources[x], sources[y], **kargs)
        # convert to pixel coordinates
        header = fits.getheader(image)
        wcs = WCS(header)
        sources = Table(sources.to_pixel(wcs), names=[x, y])
    elif coords == 'xy':
        warnings.warn('Image pixels start at 1 while python index stats at 0',
                      AstropyUserWarning)
        # Check if the following correction is necessary
        # sources[x] -= 1
        # sources[y] -= 1

    if centroid:
        sources = centroid_sources(data, sources[x], sources[y], box_size=30)
        sources = Table(sources, names=[x, y])

    # create apertures
    sources = [(a, b) for a, b in zip(sources[x], sources[y])]
    source_aperture = CircularAperture(sources, r=source_ap)

    sky_aperture = CircularAnnulus(sources, r_in=sky_ap, r_out=sky_ap +
                                   delta_ann)

    if show_plot:
        index = [str(i+1) for i in range(len(sources))]
        norm = simple_norm(data, 'sqrt', percent=99)
        plt.figure()
        plt.imshow(data, norm=norm)
        source_aperture.plot(color='white', lw=2)
        sky_aperture.plot(color='red', lw=2)
        for a, b in sources:
            plt.text(a, b, index, color="purple", fontsize=12)
        plt.show()

    # get background using sigma clipped median
    annulus_masks = sky_aperture.to_mask(method='center')
    bkg_median = []
    for mask in annulus_masks:
        annulus_data = mask.multiply(data)
        annulus_data_1d = annulus_data[mask.data > 0]
        _, median_sigclip, _ = sigma_clipped_stats(annulus_data_1d)
        bkg_median.append(median_sigclip)
    bkg_median = np.array(bkg_median)

    phot_table = aperture_photometry(data, source_aperture)
    phot_table['annulus_median'] = bkg_median
    phot_table['aper_bkg'] = bkg_median * source_aperture.area()
    phot_table['aper_sum_bkgsub'] = phot_table['aperture_sum'] - \
        phot_table['aper_bkg']

    return phot_table
Exemple #4
0
def ap_phot(image, sources, radius, aperture='circular', coords='xy', theta=0,
            centroid=False, show_plot=False, **kargs):
    """Performs circular aperture fotometry on a background substracted image, given a table with the
    coordinates (x,y) or (ra,dec) of the sources.

    Input:
        image:      (str) name of the .fits file with the image
        sources:    table with the Positions of the sources in the image.
        radius:     Radius of the circular aperture in pixels.
                    If aperture = 'elliptical' the semi axes of the ellipese
                    (a,b) should be given.
        aperture:   (str) Shape of the aperture to use. 'circular' or
                    'elliptical'
        theta:      Rotation angle for elliptical aperture in radians, optional
        centroid:   (Boolean) if True the source position centroid are
                    recalculated.
        sky_coord   (str) type of coordinates to use, either xy or radec.
                    If xy sources table must have 'x' and 'y' cols.
                    If ra dec sources table must to have 'ra' and 'dec' cols.
        show_plot:  (Boolean) If True a plot of the aperture is displayed.
    Output:
        phot_table: Table with the resulting photometry
    """

    data = fits.getdata(image)
    x, y = sources.colnames

    if coords == 'radec':
        sources = SkyCoord(sources[x], sources[y], **kargs)
        # convert to pixel coordinates
        header = fits.getheader(image)
        wcs = WCS(header)
        sources = Table(sources.to_pixel(wcs), names=[x, y])
    elif coords == 'xy':
        warnings.warn('Image pixels start at 1 while python index stats at 0',
                      AstropyUserWarning)
        # Check if the following correction is necessary
        # sources[x] -= 1
        # sources[y] -= 1

    if centroid:
        sources = centroid_sources(data, sources[x], sources[y], box_size=30)
        sources = Table(sources, names=[x, y])

    # create apertures
    sources = [(a, b) for a, b in zip(sources[x], sources[y])]
    if aperture == 'circular':
        source_aperture = CircularAperture(sources, r=radius)
    elif aperture == 'elliptical':
        source_aperture = EllipticalAperture(sources, a=radius[0], b=radius[1],
                                           theta=theta)

    if show_plot:
        index = [str(i+1) for i in range(len(sources))]
        norm = simple_norm(data, 'sqrt', percent=99)
        plt.figure()
        plt.imshow(data, norm=norm)
        source_aperture.plot(color='white', lw=2)
        for a, b in sources:
            plt.text(a, b, index, color="purple", fontsize=12)
        plt.show()

    phot_table = aperture_photometry(data, source_aperture)

    return phot_table
Exemple #5
0
def removeStarsPSF(img, starPixX, starPixY, starR, mags, gX, gY, gR, p1, p2, radius, showProgress, inverted = False):
    remove = []
    for i in range(0,len(starPixX)):
        if i%100 == 0:
            print(i)
        for j in range(i+1,len(starPixX)):
            if np.abs(starPixX[i]-starPixX[j])<2.5*radius and np.abs(starPixY[i]-starPixY[j])<2.5*radius:
                remove.append(i)
                remove.append(j)
    
    mask = np.ones(len(starPixX), dtype = bool)
    mask[np.array(remove)] = 0

    starPixX = starPixX[mask]
    starPixY = starPixY[mask]
    starR = starR[mask]
    mags = mags[mask]

    print(radius)
    mask = np.ones(starPixX.shape[0],dtype=bool)
    for i in range(gX.shape[0]):
        mask = np.logical_and(mask, np.sqrt((starPixX-gX[i])**2+(starPixY-gY[i])**2)>gR[i]+2*radius)

    starPixX = starPixX[mask]
    starPixY = starPixY[mask]
    starR = starR[mask]
    mags = mags[mask]

    mask = (2*radius<starPixX) & (starPixX<img.shape[1]-2*radius) & (2*radius<starPixY) & (starPixY<img.shape[0]-2*radius)
    starPixX = starPixX[mask]
    starPixY = starPixY[mask]
    starR = starR[mask]
    mags = mags[mask]

    if p1[0]==p2[0]:
        psfMask = np.abs(starPixX-p1[0])>2.5*radius
        trailMask = np.abs(starPixX-p1[0])<10
        psfX = starPixX[psfMask]
        psfY = starPixY[psfMask]
        psfR = starR[psfMask]
        psfMags = mags[psfMask]
        trailX = starPixX[trailMask]
        trailY = starPixY[trailMask]
        trailMags = mags[trailMask]
    else:
        m,b = TF.getLineParams(p1,p2)
        par,perp = GT.findDistances(starPixX,starPixY,m,b)
        psfMask = np.abs(perp)>2.5*radius
        trailMask = np.abs(perp)<10
        psfX = starPixX[psfMask]
        psfY = starPixY[psfMask]
        psfR = starR[psfMask]
        psfMags = mags[psfMask]
        trailX = starPixX[trailMask]
        trailY = starPixY[trailMask]
        trailMags = mags[trailMask]

    mask = psfR>10

    psfX = psfX[mask]
    psfY = psfY[mask]
    psfMags = psfMags[mask]
    print(psfX.shape[0])

    showImageWithDetectedHotPixels(img, "Image with Star Picks", psfX, psfY, "b", inverted)

    psfX,psfY = centroid_sources(img, psfX, psfY, box_size=21, centroid_func=centroid_com)

    showImageWithDetectedHotPixels(img, "Image with Star Picks Centroid", psfX, psfY, "b", inverted)

    stars = Table()
    stars["x"] = psfX
    stars["y"] = psfY

    #stars2 = Table()
    #stars2["x_0"] = psfX
    #stars2["y_0"] = psfY

    stars = extract_stars(NDData(data=img), stars, size = 2*int(2*radius)+1)

    nrows = 5
    ncols = 5
    fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(20, 20), squeeze=True)
    ax = ax.ravel()
    for i in range(nrows*ncols):
        norm = simple_norm(stars[i], 'log', percent=99.)
        ax[i].imshow(stars[i], norm=norm, origin='lower', cmap='viridis')

    plt.show()

    #sigma_psf = 2.0
    #daogroup = DAOGroup(2.0)
    #mmm_bkg = MMMBackground()
    #fitter = LevMarLSQFitter()
    #psf_model = PRF(sigma=sigma_psf)
    #photometry = BasicPSFPhotometry(group_maker=daogroup,bkg_estimator=mmm_bkg,psf_model=psf_model,fitter=LevMarLSQFitter(),fitshape=(11,11))
    #result_tab = photometry(image=img, init_guesses=stars2)
    #residual_image = photometry.get_residual_image()

    epsfBuilder = EPSFBuilder(oversampling=2, maxiters=20, smoothing_kernel = "quadratic")
    epsf, starFits = epsfBuilder(stars)

    #showImage(residual_image,"Image No Stars",True)

    norm = simple_norm(epsf.data, 'log', percent=99.)
    plt.imshow(epsf.data, norm=norm, origin='lower', cmap='viridis')
    plt.colorbar()
    plt.show()

    nrows = 5
    ncols = 5
    fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(20, 20), squeeze=True)
    ax = ax.ravel()
    for i in range(nrows*ncols):
        norm = simple_norm(starFits[i], 'log', percent=99.)
        ax[i].imshow(starFits[i], norm=norm, origin='lower', cmap='viridis')

    plt.show()

    nrows = 5
    ncols = 5
    fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(20, 20), squeeze=True)
    ax = ax.ravel()
    for i in range(nrows*ncols):
        norm = simple_norm(stars[i].data-starFits[i].data, 'log', percent=99.)
        ax[i].imshow(stars[i].data-starFits[i].data, norm=norm, origin='lower', cmap='viridis')

    plt.show()

    showImage(finalImg, "Image With No Stars", inverted)